1 Conceptos generales

1.1 ¿Qué es una API?

Una API (Application Programming Interface, interfaz de programación de aplicaciones) es un conjunto de reglas y puntos de acceso que permite que dos programas se comuniquen entre sí sin intervención humana. En lugar de descargar manualmente hojas de cálculo desde un portal web, un cliente (por ejemplo, R) envía una solicitud a un servidor y recibe una respuesta estructurada, normalmente en formato JSON o XML, que puede procesarse de inmediato.

La analogía útil es la de un mesero en un restaurante: el comensal (nuestro programa) no entra a la cocina (la base de datos del Banco Mundial); le hace un pedido al mesero (la API) siguiendo un menú (la documentación), y este devuelve exactamente lo solicitado. El comensal no necesita saber cómo está organizada la cocina, solo cómo pedir.

1.2 Tipos de APIs

Las APIs pueden clasificarse según distintos criterios. Para efectos prácticos, conviene distinguir:

  • Por su arquitectura o protocolo: REST (el más difundido, basado en URLs y verbos HTTP), SOAP (más antiguo, basado en XML y muy estructurado), GraphQL (permite pedir exactamente los campos deseados) y gRPC (orientado a alto rendimiento entre servicios).
  • Por su nivel de acceso: públicas o abiertas (disponibles para cualquier usuario, con o sin registro), de socios (requieren credenciales acordadas) e internas o privadas (uso exclusivo dentro de una organización).
  • Por lo que exponen: APIs de datos (consultan bases estadísticas, como la del Banco Mundial), APIs de servicios (envían correos, procesan pagos) y APIs de sistema operativo o de librerías (funciones dentro de un mismo entorno de programación).

La API del Banco Mundial es una API REST pública de datos: se consulta mediante URLs, no requiere clave de autenticación para la mayoría de sus series y devuelve resultados en JSON o XML.

1.3 Importancia de su uso

Para la investigación económica aplicada, el acceso vía API aporta ventajas que la descarga manual no ofrece:

  • Reproducibilidad: el flujo de datos queda escrito en código; cualquiera puede volver a ejecutar el análisis y obtener el mismo resultado.
  • Actualización automática: al volver a correr el script se obtienen los valores más recientes, sin repetir descargas a mano.
  • Escala y eficiencia: es igual de sencillo pedir un indicador para un país que para 200 economías y 60 años, en una sola instrucción.
  • Integración en el flujo de trabajo: los datos llegan ya en un formato tabular listo para limpiar, modelar y graficar dentro del mismo entorno (R), eliminando pasos intermedios propensos a error.

2 Muestra de datos: la API del Banco Mundial

La API principal del Banco Mundial es la API de Indicadores (Indicators API, versión 2), cuya URL base es:

https://api.worldbank.org/v2/

Su gran valor está en la desagregación: cada observación se identifica por varias dimensiones combinables. Las principales son:

Dimensión Descripción Ejemplo
País / economía ~217 economías, más agregados regionales y por ingreso SV (El Salvador), GT (Guatemala)
Indicador Código único de cada serie estadística NY.GDP.MKTP.CD (PIB, US$ corrientes)
Tiempo Año (algunas series: trimestre o mes) 2000:2024
Tema 20 temas: economía, salud, educación, pobreza… Economy & Growth
Fuente / base Más de 40 bases (WDI, deuda externa, etc.) World Development Indicators
Región / ingreso Agrupaciones geográficas y por nivel de ingreso Latin America & Caribbean, Upper middle income

El paquete wbstats incluye un catálogo precargado (wb_cachelist) que permite inspeccionar sin conexión toda esta estructura. Los siguientes bloques muestran la información disponible desagregada por cada dimensión.

library(wbstats)
library(dplyr)

catalogo <- wb_cachelist

# ¿Cuántos elementos hay en cada dimensión del catálogo?
sapply(catalogo, NROW)
#>     countries    indicators       sources        topics       regions 
#>           295         29533            71            21            43 
#> income_levels lending_types     languages 
#>             7             4            23
# Países y economías de Centroamérica disponibles
catalogo$countries %>%
  filter(region == "Latin America & Caribbean ") %>%
  select(iso3c, iso2c, country, income_level, region) %>%
  filter(iso3c %in% c("SLV", "GTM", "HND", "NIC", "CRI", "PAN", "BLZ")) 
# Los temas (topics) bajo los que se organizan los indicadores
catalogo$topics %>% select(topic_id, topic)
# Algunas de las bases de datos (sources) accesibles por la misma API
catalogo$sources %>% select(source_id, source) %>% head(10)

Con esto queda claro que la API no expone “una tabla”, sino un cubo de datos consultable por país, indicador, tiempo, tema y fuente de forma combinada.


3 Ejemplos prácticos de acceso con R

Existen tres caminos, de mayor a menor nivel de abstracción:

  1. WDI — el envoltorio (wrapper) más popular, ideal para empezar.
  2. wbstats — más flexible (búsqueda avanzada, valores más recientes, cache).
  3. Acceso directo con httr + jsonlite — control total de la petición HTTP.

3.1 Vía 1 — Paquete WDI

Primero se busca el código del indicador y luego se descarga para los países y años deseados. La función devuelve un data.frame en formato largo (país–año).

library(WDI)

# Buscar indicadores de PIB per cápita en dólares constantes
WDIsearch("gdp.*capita.*constant")[1:5, ]
# PIB per cápita (US$ constantes) para el Triángulo Norte, 2010-2023
ca <- WDI(
  country   = c("SV", "GT", "HN"),
  indicator = "NY.GDP.PCAP.KD",
  start     = 2010,
  end       = 2023
)

head(ca)

3.2 Vía 2 — Paquete wbstats

Ofrece búsqueda tipo grep, salida en tibble y utilidades como mrnev (traer los n valores más recientes no vacíos). Es útil cuando se trabaja con paneles amplios.

library(wbstats)

# Crecimiento del PIB (% anual) para toda Centroamérica, 2015-2024
pib_ca <- wb_data(
  indicator  = "NY.GDP.MKTP.KD.ZG",
  country    = c("SV", "GT", "HN", "NI", "CR", "PA", "BZ"),
  start_date = 2015,
  end_date   = 2024
)

head(pib_ca)
library(ggplot2)

ggplot(pib_ca, aes(x = date, y = NY.GDP.MKTP.KD.ZG, color = country)) +
  geom_line(linewidth = 0.8) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "grey50") +
  labs(
    title    = "Crecimiento del PIB en Centroamérica",
    subtitle = "Variación anual del PIB real (%), 2015-2024",
    x = NULL, y = "% anual", color = "País",
    caption  = "Fuente: Banco Mundial (API de Indicadores) vía wbstats"
  ) +
  theme_minimal()

3.3 Vía 3 — Acceso directo con httr + jsonlite

Cuando se necesita entender qué ocurre “por debajo”, se puede llamar a la API directamente. La respuesta JSON de la API de Indicadores tiene dos partes: el elemento [[1]] contiene la metadata de paginación (páginas, total de registros, última actualización) y el [[2]] contiene los datos.

library(httr)
library(jsonlite)

# Construcción de la URL: PIB (US$ corrientes) de El Salvador, 2010-2023
url <- paste0(
  "https://api.worldbank.org/v2/country/SV/indicator/NY.GDP.MKTP.CD",
  "?format=json&date=2010:2023&per_page=100"
)

resp <- GET(url)
contenido <- fromJSON(content(resp, as = "text", encoding = "UTF-8"))

# Parte 1: metadata de paginación
str(contenido[[1]])
#> List of 6
#>  $ page       : int 1
#>  $ pages      : int 1
#>  $ per_page   : int 100
#>  $ total      : int 14
#>  $ sourceid   : chr "2"
#>  $ lastupdated: chr "2026-07-13"
# Parte 2: los datos (se aplanan las columnas anidadas indicator/country)
datos <- contenido[[2]]
datos[, c("countryiso3code", "date", "value")] |> head()

Nota sobre paginación. La API devuelve por defecto 50 registros por página. Para descargas grandes conviene fijar per_page (hasta 32 500) o recorrer las páginas con el parámetro page, usando el campo pages de la metadata para saber cuántas iteraciones hacen falta.

3.3.1 Un caso completo: pobreza multidimensional en Latinoamérica

El ejemplo anterior descarga un indicador para un país. Pero la pobreza multidimensional es, por definición, un fenómeno de varias dimensiones: privaciones monetarias, educativas y de acceso a servicios básicos. Como la API sirve un indicador por llamada, construir un dataset multivariable exige descargar cada serie por separado y unirlas (join) por país y año. Y para acotar el resultado a “toda Latinoamérica” se necesita un segundo tipo de join contra el catálogo de países, que actúa como filtro regional.

Combinamos el conjunto de indicadores del Multidimensional Poverty Measure (MPM) del Banco Mundial:

Código Variable Papel en el análisis
SI.POV.MDIM Tasa de pobreza multidimensional (% de población) Indicador agregado (MPM)
SI.POV.MDIM.IT Intensidad de la privación (% promedio entre los pobres) Profundidad de la pobreza
SI.POV.DDAY Pobreza monetaria (línea internacional; hoy US$ 3.00/día, PPA 2021) Dimensión monetaria
SI.POV.GINI Índice de Gini Desigualdad (contexto)

Paso 1 — Función reutilizable. Encapsulamos la petición HTTP en una función que descarga un indicador para todas las economías y devuelve un tibble ordenado. La columna de valores toma el nombre del propio código, lo que luego facilita el join.

library(httr)
library(jsonlite)
library(dplyr)
library(purrr)
library(stringr)

wb_indicador <- function(codigo, inicio = 2000, fin = 2024) {
  url <- paste0(
    "https://api.worldbank.org/v2/country/all/indicator/", codigo,
    "?format=json&date=", inicio, ":", fin, "&per_page=20000"
  )
  resp  <- GET(url)
  stop_for_status(resp)
  crudo <- fromJSON(content(resp, as = "text", encoding = "UTF-8"),
                    flatten = TRUE)

  crudo[[2]] |>
    as_tibble() |>
    transmute(
      # La API es inconsistente entre bases: unas dejan vacío countryiso3code y
      # ponen el ISO-3 en country.id (caso de las series de pobreza), otras al
      # revés. coalesce() toma el primero no vacío -> siempre queda el ISO-3.
      iso3c     = coalesce(na_if(countryiso3code, ""), country.id),
      anio      = as.integer(date),
      !!codigo := value            # la columna se nombra con el código
    )
}

Detalle clave para los join. No todas las bases de la API rellenan los mismos campos: las series de pobreza dejan vacío countryiso3code y colocan el código ISO-3 en country.id, mientras que otras (como el PIB) hacen lo contrario. Por eso la llave se construye con coalesce(): si se usara solo countryiso3code, el join no encontraría coincidencias y el dataset final quedaría vacío. Conviene siempre inspeccionar las llaves antes de unir.

Paso 2 — El pipe con múltiples variables y full_join. Recorremos los códigos con map(), obtenemos una lista de tibbles (uno por indicador) y los fusionamos con reduce(full_join, ...). El full_join conserva toda combinación país–año presente en cualquiera de las series, de modo que ningún dato se pierde en la unión.

codigos <- c("SI.POV.MDIM", "SI.POV.MDIM.IT", "SI.POV.DDAY", "SI.POV.GINI")

panel <- codigos |>
  map(wb_indicador) |>                             # lista: un tibble por serie
  reduce(full_join, by = c("iso3c", "anio")) |>    # une las 4 variables
  rename(                                           # nombres legibles
    pobreza_multidim  = "SI.POV.MDIM",
    intensidad        = "SI.POV.MDIM.IT",
    pobreza_monetaria = "SI.POV.DDAY",
    gini              = "SI.POV.GINI"
  )

glimpse(panel)
#> Rows: 6,709
#> Columns: 6
#> $ iso3c             <chr> "ARB", "ARB", "ARB", "ARB", "ARB", "ARB", "ARB", "AR…
#> $ anio              <int> 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012…
#> $ pobreza_multidim  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
#> $ intensidad        <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
#> $ pobreza_monetaria <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
#> $ gini              <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …

Paso 3 — Catálogo de países como tabla de filtro. Descargamos los metadatos de países y nos quedamos solo con la región Latin America & Caribbean. Este tibble aporta el nombre, la región y el nivel de ingreso, y servirá para recortar el panel mediante un inner_join.

meta <- fromJSON(
  content(GET("https://api.worldbank.org/v2/country?format=json&per_page=400"),
          as = "text", encoding = "UTF-8"),
  flatten = TRUE
)

paises_lac <- meta[[2]] |>
  as_tibble() |>
  transmute(
    iso3c   = id,
    pais    = name,
    region  = region.value,
    ingreso = incomeLevel.value
  ) |>
  filter(str_detect(region, "Latin America"))   # descarta agregados y otras regiones

Paso 4 — Join final que filtra a Latinoamérica. Aquí el inner_join cumple doble función: agrega los atributos de cada país y, al conservar solo las filas con coincidencia en paises_lac, filtra el panel mundial a la región de interés (los agregados y las economías de otras regiones quedan fuera).

pobreza_latam <- panel |>
  inner_join(paises_lac, by = "iso3c") |>        # une + filtra a la región
  relocate(pais, region, ingreso, .after = iso3c) |>
  arrange(pais, anio)

head(pobreza_latam)

Paso 5 — Foto más reciente por país. Los datos del MPM provienen de encuestas de hogares y son escasos (un país no tiene un valor por año, sino uno cada varios años). Por eso construimos una “foto” con el último año disponible de pobreza multidimensional en cada país.

snapshot_latam <- pobreza_latam |>
  filter(!is.na(pobreza_multidim)) |>
  group_by(iso3c) |>
  slice_max(anio, n = 1, with_ties = FALSE) |>   # último año con dato por país
  ungroup() |>
  select(pais, anio, pobreza_multidim, intensidad, pobreza_monetaria, gini) |>
  arrange(desc(pobreza_multidim))

snapshot_latam
library(ggplot2)

ggplot(snapshot_latam,
       aes(x = reorder(pais, pobreza_multidim), y = pobreza_multidim)) +
  geom_col(fill = "#2c7fb8") +
  coord_flip() +
  labs(
    title    = "Pobreza multidimensional en América Latina y el Caribe",
    subtitle = "Incidencia (% de población), último año disponible por país",
    x = NULL, y = "% de la población",
    caption  = "Fuente: Banco Mundial — Multidimensional Poverty Measure (API v2)"
  ) +
  theme_minimal()

En síntesis, el pipe articula dos lógicas de join: full_join para ensamblar las variables (nada se descarta) e inner_join para acotar el universo a Latinoamérica. Ese mismo patrón —una función de descarga, un reduce(full_join) sobre varios indicadores y un inner_join con una tabla de referencia— escala a cualquier conjunto de series y a cualquier recorte geográfico.


4 Buenas prácticas y cierre

  • Guardar en caché los resultados de la API (por ejemplo, con cache=TRUE en los chunks o guardando un .rds) para no golpear el servidor en cada compilación y trabajar sin conexión.
  • Documentar los códigos de indicador usados: NY.GDP.MKTP.CD es más reproducible que “PIB corriente”.
  • Verificar la cobertura temporal: no todos los indicadores cubren todos los años ni todos los países; conviene revisar los NA.
  • Citar la fuente y la fecha de descarga, ya que las series se revisan.

Los tres caminos consultan la misma API; la elección depende del control que se necesite. Para la mayoría del trabajo aplicado, WDI o wbstats bastan; el acceso directo con httr queda como recurso cuando se requiere ajustar la petición al detalle.

4.1 Referencias