1 Conceptos generales

1.1 ¿Qué es una API?

Una API (Application Programming Interface, interfaz de programación de aplicaciones) es una interfaz que define reglas y puntos de acceso mediante los cuales dos aplicaciones de software intercambian información y datos de forma programática, sin depender de pasos manuales (Ofoeda et al. 2019). 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. Este modelo cliente–servidor, sin estado y basado en representaciones de recursos, es el que subyace a la arquitectura de la web moderna (Fielding 2000).

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) (Fielding 2000; Richardson y Ruby 2007), SOAP (más antiguo, basado en XML y muy estructurado), GraphQL (permite pedir exactamente los campos deseados en una sola consulta) (Hartig y Pérez 2018) 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) (Bauer et al. 2022).
  • 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 (API key) para la mayoría de sus series y devuelve resultados en formato 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 (Bauer et al. 2022):

  • Reproducibilidad: el flujo de datos queda escrito en código; cualquier colega puede volver a ejecutar el análisis y obtener el mismo resultado. La reproducibilidad computacional se considera un estándar mínimo para evaluar hallazgos cuando la replicación independiente completa no es viable (Peng 2011).
  • 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 (World Bank, s. f.-a, s. f.-c):

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

La versión 2 reemplazó a la v1 ( que fue descontinuada en el año 2020) y exige incluir v2 en la ruta; entre sus mejoras figura la exposición de códigos ISO-2 e ISO-3, región, nivel de ingreso y tipo de préstamo en los metadatos de cada país (World Bank, s. f.-c). Su gran valor está en la desagregación: cada observación se identifica por varias dimensiones combinables (World Bank, s. f.-b). 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. Entre las más de cuarenta bases accesibles destaca World Development Indicators (WDI), la colección principal de indicadores de desarrollo del Banco Mundial, compilada a partir de fuentes internacionales oficialmente reconocidas (World Bank, s. f.-d). 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(iso2c %in% c("SV", "GT", "HN", "NI", "CR", "PA", "BZ"))
# 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)
# Algunos indicadores (indicators) accesibles por la misma API
catalogo$indicators |> select(indicator_id, indicator) |> head(10)

3 Ejemplos prácticos de acceso con R

Existen tres caminos, de mayor a menor nivel de abstracción, y a continuación se desarrollan ejemplos completos de cada uno:

  1. WDI: el envoltorio (wrapper) más popular, ideal para empezar (Arel-Bundock 2025).
  2. wbstats: un wrapper más flexible (búsqueda por tema, salida en tibble, soporte multilingüe) (Piburn 2020).
  3. Acceso directo con httr + jsonlite: control total de la petición HTTP (Wickham 2023a; Ooms 2014).

Para R, el propio Banco Mundial ha señalado los paquetes WDI y wbstats como vías convenientes de acceso a sus datos; y para quienes no usan esas librerías, sugiere consumir directamente la API y procesar el JSON o XML devuelto, que es precisamente lo que hace la tercera vía (Khokhar 2013).

Antes de entrar en detalle, esta tabla resume en qué se diferencian y cuándo conviene cada una:

Vía Facilidad de uso Control sobre la petición Cuándo conviene
WDI Muy alta Bajo Empezar rápido; consultas simples de uno o varios indicadores.
wbstats Alta Medio Buscar por palabra clave o tema, columnas legibles y trabajo con paneles.
httr + jsonlite Baja Total Combinar series que ningún wrapper trae juntas y controlar paginación, campos y formato.

En la práctica, la mayoría del trabajo aplicado se resuelve con WDI o wbstats; el acceso directo se reserva para cuando se necesita algo que los wrappers no ofrecen.

3.1 Vía 1: El paquete WDI

WDI es la manera más sencilla para acceder a los datos del Banco Mundial desde R. La idea es: no escribir direcciones web ni procesar respuestas; simplemente indicar qué país, qué indicador y qué años requiero, y el paquete se encarga de pedirlo y devolverlo en una tabla lista para usar. El trabajo se reparte en tres funciones:WDIcache(), WDIsearch() y WDI(), que corresponden a tres pasos naturales: poner al día el catálogo, encontrar el código del indicador y descargar los datos (Arel-Bundock 2025).

3.1.1 Paso 1: Poner al día el catálogo de indicadores

Antes de buscar o descargar conviene tener la lista de indicadores actualizada. WDIcache() descarga desde los servidores del Banco Mundial el catálogo completo y vigente de indicadores y países. El paquete ya trae una copia local incorporada, pero esa copia puede quedar desfasada frente a los indicadores agregados más recientemente; WDIcache() baja la versión actual y devuelve un objeto (una lista con dos tablas, series y country) que luego se pasa a WDIsearch() y WDI() mediante el argumento cache =. No recibe argumentos y la descarga tarda unos segundos porque trae todo el catálogo.

library(WDI)

# Descarga el catálogo vigente de indicadores desde el servidor del BM
mi_cache <- WDIcache()

# Estructura del objeto devuelto: dos elementos, 'series' y 'country'
str(mi_cache, max.level = 1) # Lee en una lista sencilla el contenido de 'mi_cache'
#> List of 2
#>  $ series :'data.frame': 29533 obs. of  5 variables:
#>  $ country:'data.frame': 295 obs. of  9 variables:

De aquí en adelante, pasar cache = mi_cache a las funciones de búsqueda y descarga garantiza que se trabaja sobre el listado más reciente disponible:

# Buscar sobre la caché recién descargada
WDIsearch("gdp", cache = mi_cache)[1:3, ]
# Descargar usando la caché; extra = TRUE añade región, nivel de ingreso, etc.
datos_pib <- WDI(
  country   = "US",
  indicator = "NY.GDP.PCAP.KD",
  extra     = TRUE,
  cache     = mi_cache
)

3.1.2 Paso 2: Encontrar el código del indicador

Cada serie del Banco Mundial tiene un código (por ejemplo, NY.GDP.PCAP.KD para el PIB per cápita). Con más de mil indicadores, adivinar ese código es inviable. WDIsearch() es la vía por default, usa grep (ignorando mayúsculas y minúsculas) sobre los nombres de los indicadores y devuelve una matriz con código y descripción del dataset (Arel-Bundock 2025).

3.1.2.1 WDIsearch("string"): búsqueda tipo grep

                         # Búsqueda por palabra suelta indicadores cuyo nombre
WDIsearch("gini")[1:3, ] # contengan la cadena "gini"

Para reducir la dimensión del output y sabiendo que es un índice, se puede deducir:

                        # Es literalmente el nombre del indicador, por defecto
WDIsearch("gini index") # WDIsearch() busca el patrón en la columna `name`

También se pueden realizar búsquedas utilizando .*, que se comporta distinto al espacio en blanco dejado en el ejemplo anterior:

WDIsearch("gini.*index") [1:10, ] # Usa dos metacaracteres: '.' y '*'
  • . significa “cualquier carácter”,
  • * significa “cero o más veces”.

Juntos, .* quiere decir: “gini \(\rightarrow\) luego cualquier cosa (o nada) en medio, \(\rightarrow\) después index”. En ese orden.

3.1.2.2 WDIsearch("string", field = " ")

Con field = " " cambiamos sobre que columna se realiza la búsqueda. Es particularmente útil para hacer búsquedas utilizando la columna indicator, pues los códigos de los indicadores del Banco Mundial siguen una estructura jerárquica de segmentos separados por puntos, del tipo:

TEMA . SUBTEMA . CONCEPTO. UNIDAD

Por ejemplo, NY.GDP.MKTP.CD significa:

Deconstruido significa:

  • Tema: NY \(\rightarrow\) National accounts (cuentas nacionales): \(Y\) (producto/ingreso),
  • Subtema: GDP \(\rightarrow\) Gross Domestic Product (Producto Interno Bruto - PIB),
  • Concepto: MKTP \(\rightarrow\) Market prices (Precios de mercado),
  • Unidad: CD \(\rightarrow\) Current dollars (dólares corrientes).
3.1.2.2.1 Prefijos por tema (los dos primeros caracteres)
Prefijo Área temática
NY Cuentas nacionales ingreso/producto (PIB, PNB, valor agregado)
NE Cuentas nacionales gasto (consumo, inversión, exportaciones netas)
NV Cuentas nacionales valor agregado por sector
FP Precios financieros (IPC / inflación, deflactores, etc.)
FR Tasas de interés
FM Agregados monetarios (M2, crédito)
FS / FB / FD Sector financiero / bancario / depósitos
FI / CM Sistema e indicadores financieros / mercados de capital
BX Balanza de pagos, ingresos/entradas (IED, remesas)
BM Balanza de pagos, pagos/salidas
BN Balanza de pagos, saldos netos
PA Conversión / tipo de cambio y PPA
TX / TM Comercio, exportaciones / importaciones
TT / TG Términos de intercambio / comercio de bienes
GC Finanzas del gobierno central (deuda, ingresos, gasto)
DT Deuda externa
DC Flujos de ayuda y financiamiento al desarrollo
SP Población y dinámica demográfica
SL Mercado laboral (desempleo, participación)
SI Distribución del ingreso y pobreza (Gini)
SE Educación
SH Salud
SN / SM / SG Nutrición / migración / género
AG Agricultura y uso de la tierra
EG / EN / ER Energía / medio ambiente y emisiones / recursos naturales
IT / IS / IE TIC y comunicaciones / transporte / infraestructura económica
IC Clima de negocios (Doing Business, ease of business)
VC Vulnerabilidad y conflicto (homicidios, fragilidad)
MS Seguridad, gasto militar
per_ Protección social y trabajo (base ASPIRE)
3.1.2.2.2 Sufijos de unidades: Los mas importantes
Sufijo Significado
.CD US$ corrientes
.KD US$ constantes (año base 2015)
.CN / .KN Moneda local corriente / constante
.PP.CD / .PP.KD PPA, dólares internacionales corrientes / cosntantes
.ZS Porcentaje / participación
.KD.ZG Crecimiento real (%)
.PC / .PCAP Per cápita
.IN / .P5 / .P3 Valor absoluto / por cada 100,000 / por cada 1,000
# Buscar por prefijo de código: NY (national accounts: product (income)
WDIsearch("NY.*KD", field = "indicator")

La búsqueda con field = "indicator" es particularmente útil cuando ya se intuye el prefijo de una familia de series, porque la matriz resultante lista todas las variantes de esa familia.

Para conocer más códigos, consultar Anexo A

3.1.2.3 WDIsearch("string", short = FALSE)

Controlamos cuánta información muestra la matriz resultante, short = TRUE por defecto da solo código y nombre, short = FALSE agrega descripción y fuente. Útil para entender que mide un indicador antes de descargarlo:

WDIsearch("gini index", short = FALSE) -> gini_index_search


library(kableExtra)
gini_index_search |>
  kable(caption = "Indicadores descubirtos para 'gini index' en la API del BM") |>
  kable_classic(html_font = "Helvetica", font_size = 14) |>
  add_footnote(label = "Tomado de la API del BM", notation = "symbol") |>
  kable_styling()
Indicadores descubirtos para ‘gini index’ en la API del BM
indicator name description sourceDatabase sourceOrganization
26195 SI.POV.GINI Gini index Gini index measures the extent to which the distribution of income (or, in some cases, consumption expenditure) among individuals or households within an economy deviates from a perfectly equal distribution. A Lorenz curve plots the cumulative percentages of total income received against the cumulative number of recipients, starting with the poorest individual or household. The Gini index measures the area between the Lorenz curve and a hypothetical line of absolute equality, expressed as a percentage of the maximum area under the line. Thus a Gini index of 0 represents perfect equality, while an index of 100 implies perfect inequality. World Development Indicators World Bank, Poverty and Inequality Platform. Data are based on primary household survey data obtained from government statistical agencies and World Bank country departments. Data for high-income economies are mostly from the Luxembourg Income Study database. For more information and methodology, please see http://pip.worldbank.org., World Bank (WB), uri: http://pip.worldbank.org, note: Data are based on primary household survey data obtained from government statistical agencies and World Bank country departments. Data for high-income economies are mostly from the Luxembourg Income Study database.
* Tomado de la API del BM

El argumento field decide sobre qué columna se busca; short solo decide qué columnas se muestran. Son independientes: se puede buscar en description con short = TRUE. En la práctica se combinan field = description (o sourceDatabase, sourceOrganization) con short = FALSE para poder ver la columna sobre la que se hizo el match.

WDIsearch("mortality rates", field = "description", short = FALSE) -> mortality_rates_search

mortality_rates_search |>
  head(5) |>
  kable(caption = "Indicadores de mortalidad descubiertos en la API del Banco Mundial") |>
  kable_classic(html_font = "Helvetica", font_size = 14) |>
  add_footnote(label = "Tomado de la API del BM", notation = "symbol") |>
  kable_styling()
Indicadores de mortalidad descubiertos en la API del Banco Mundial
indicator name description sourceDatabase sourceOrganization
15572 MO.INDEX.HDEV.XQ Human Development Health and Welfare: Within this sub-category the Ibrahim Index measures: (i) Incidence of TB – incidence of new cases of Tuberculosis. (ii) Child Mortality – likelihood that a newborn baby will die before the age of five, assuming that he/she is subject to current, age-specific mortality rates. (iii) Immunisation against Measles – proportion of one year olds (children aged 12–23 months) who have received one dose of measles vaccine. (iv) Immunisation against DTP – proportion of one year olds (children aged 12–23 months) who have received three doses of DTP vaccine. (v) Welfare Regime – equality of access to social safety nets that compensate for poverty and other risks. (vi) Social Protection and Labour – clustered indicator (average) of variables from the African Development Bank and the World Bank measuring government policies and regulations to ensure a minimum level of welfare to all people. (vii) Social Exclusion – extent to which significant parts of society are isolated due to poverty and inequality. (viii) Antiretroviral Treatment Provision – people with advanced HIV infection who are receiving antiretroviral treatment (ART) according to nationally approved or international standards. (ix) Antiretroviral Treatment Provision for Pregnant Women – HIV positive pregnant women who received antiretroviral treatment (ART) to reduce the risk of mother-to-child transmission. (x) Access to Piped Water – proportion of the population with access to water piped into their dwelling or just outside it. (xi) Access to Improved Water – proportion of the population with access to a water source protected from outside contamination. (xii) Access to Improved Sanitation – proportion of the population served with a sanitation facility that hygienically separates human excreta from human contact. (xiii) Open Defecation Sanitation – proportion of the population forced to dispose of human faeces in open bodies of water or outdoor open spaces. Africa Development Indicators Mo Ibrahim Foundation, electronic files and web site.
16175 NY.ADJ.DPEM.CD Adjusted savings: particulate emission damage (current US$) Particulate emissions damage is the damage due to exposure of a country’s population to ambient concentrations of particulates measuring less than 2.5 microns in diameter (PM2.5), ambient ozone pollution, and indoor concentrations of PM2.5 in households cooking with solid fuels. Damages are calculated as foregone labor income due to premature death. Estimates of health impacts from the Global Burden of Disease Study 2013 are for 1990, 1995, 2000, 2005, 2010, and 2013. Data for other years have been extrapolated from trends in mortality rates. This indicator is expressed in current prices, meaning no adjustment has been made to account for price changes over time. This indicator is expressed in United States dollars. World Development Indicators Global Burden of Disease 2013 study, Institute for Health Metrics and Evaluation (IHME)
16176 NY.ADJ.DPEM.GN.ZS Adjusted savings: particulate emission damage (% of GNI) Particulate emissions damage is the damage due to exposure of a country’s population to ambient concentrations of particulates measuring less than 2.5 microns in diameter (PM2.5), ambient ozone pollution, and indoor concentrations of PM2.5 in households cooking with solid fuels. Damages are calculated as foregone labor income due to premature death. Estimates of health impacts from the Global Burden of Disease Study 2013 are for 1990, 1995, 2000, 2005, 2010, and 2013. Data for other years have been extrapolated from trends in mortality rates. This indicator is expressed as a percentage of Gross National Income (GNI) which is the total income earned by all residents within an economic territory during an accounting period. It is equal to gross domestic product plus earned income receivable from abroad minus earned income payable abroad. World Development Indicators Global Burden of Disease 2013 study, Institute for Health Metrics and Evaluation (IHME)
25492 SH.DYN.0509 Probability of dying among children ages 5-9 years (per 1,000) Probability of dying between age 5-9 years of age expressed per 1,000 children aged 5, if subject to age-specific mortality rates of the specified year. World Development Indicators UN Inter-agency Group for Child Mortality Estimation, UN Children’s Fund (UNICEF), uri: www.childmortality.org; World Health Organization (WHO), uri: www.childmortality.org, note: UN Inter-agency Group for Child Mortality Estimation; World Bank (WB), uri: www.childmortality.org, note: UN Inter-agency Group for Child Mortality Estimation; United Nations (UN), uri: www.childmortality.org, note: UN Inter-agency Group for Child Mortality Estimation, publisher: UN Population Division
25493 SH.DYN.0509.FE Probability of dying among children ages 5-9 years, female (per 1,000) Probability of dying among female children between age 5-9 years of age expressed per 1,000 female children aged 5, if subject to female age-specific mortality rates of the specified year. Health Nutrition and Population Statistics Estimates developed by the UN Inter-agency Group for Child Mortality Estimation (UNICEF, WHO, World Bank, UN DESA Population Division) at www.childmortality.org.
* Tomado de la API del BM

3.1.2.4 WDIsearch("string", cache = mi_cache)

Acá se decide contra que catálogo WDIsearch() hace la búsqueda. Al omitirse, usa la lista local (que puede estar defasada), si se le pasa el resultado del Paso 1, busca sobre el catálogo recién descargado del servidor:

WDIsearch("remittance", short = FALSE, cache = mi_cache) -> remittance_search

remittance_search |>
  as.data.frame() |>
  dplyr::select(dplyr::any_of(c("indicator", "name", "sourceDatabase"))) |>
  head(10) |>
  kable(row.names = FALSE,
        caption = "Indicadores de reemesas descubiertos en la API del Banco Mundial alojados en caché") |>
  kable_classic(html_font = "Helvetica", font_size = 14) |>
  add_footnote(label = "Tomado de la API del BM", notation = "symbol") |>
  kable_styling()
Indicadores de reemesas descubiertos en la API del Banco Mundial alojados en caché
indicator name sourceDatabase
BM.TRF.MGR.CD Migrant remittance outflows (current US\() </td> <td style="text-align:left;"> Africa Development Indicators </td> </tr> <tr> <td style="text-align:left;"> BM.TRF.PWKR.CD </td> <td style="text-align:left;"> Workers' remittances, payments (BoP, current US\)) Africa Development Indicators
BM.TRF.PWKR.CD.DT Personal remittances, paid (current US\() </td> <td style="text-align:left;"> World Development Indicators </td> </tr> <tr> <td style="text-align:left;"> BN.TRF.PWKR.CD </td> <td style="text-align:left;"> Workers' remittances, net (BoP, current US\)) Africa Development Indicators
BN.TRF.PWKR.CD.DT Personal remittances, net (current US\() </td> <td style="text-align:left;"> WDI Database Archives </td> </tr> <tr> <td style="text-align:left;"> BX.GSR.INCL.CD </td> <td style="text-align:left;"> Exports of goods, services, income and workers' remittances (BoP, current US\)) Africa Development Indicators
BX.TRF.MGR.CD Migrant remittance inflows (current US\() </td> <td style="text-align:left;"> Africa Development Indicators </td> </tr> <tr> <td style="text-align:left;"> BX.TRF.MGR.DT.GD.ZS </td> <td style="text-align:left;"> Migrant remittance inflows (% of GDP) </td> <td style="text-align:left;"> Africa Development Indicators </td> </tr> <tr> <td style="text-align:left;"> BX.TRF.PWKR.CD.DT </td> <td style="text-align:left;"> Personal remittances, received (current US\)) World Development Indicators
BX.TRF.PWKR.DT.GD.ZS Personal remittances, received (% of GDP) World Development Indicators
* Tomado de la API del BM

3.1.3 Paso 3: Descargar y graficar los datos

WDI() es la función central. Sus argumentos clave son:

  • country. Uno o varios códigos ISO-2/ISO-3, o "all")
  • indicator. Uno o varios códigos),
  • start y end – rango de años,
  • extra. Si es TRUE agrega columnas de región, ingreso, etc.) y
  • cache. La caché a utilizar.

Devuelve un data.frame en formato largo: una fila por país y año listo para graficar (Arel-Bundock 2025).

3.1.3.1 Ejemplo 1: Índice de Gini en Centroamérica

El índice de Gini (SI.POV.GINI) mide cuánto se aparta la distribución del ingreso o, en algunos casos, del consumo de una economía respecto de una distribución perfectamente igualitaria: 0 equivale a igualdad perfecta y 100 a desigualdad máxima (World Bank, s. f.-d). Descargamos la serie para los seis países centroamericanos entre 2000 y 2023:

library(dplyr)
library(ggplot2)

datos <- WDI(
  country   = c("GTM", "SLV", "HND", "NIC", "CRI", "PAN"),
  indicator = "SI.POV.GINI",
  start     = 2000,
  end       = 2023,
  extra     = FALSE,
  cache     = mi_cache
)

ggplot(datos, aes(x = year, y = SI.POV.GINI, color = country)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Coeficiente de Gini en Centroamérica (2000-2023)",
    x = "Año", y = "Coeficiente de Gini", color = "País"
  ) +
  theme_minimal() +
  theme(legend.position = "right")

En el ggplot, aes() asigna el año al eje X, el valor del Gini al eje Y y el país al color; geom_line() traza la evolución y geom_point() marca cada observación. Como el Gini proviene de encuestas de hogares, la serie tiene huecos y geom_line() conecta solo los años con dato, de modo que las líneas no deben leerse como una medición continua.

3.1.3.2 Ejemplo 2: Gasto público en salud

Para encontrar datos del gasto público en salud, volvemos a utilizar la función WDIsearch() combinada con palabras clave en inglés, como “health expenditure” o simplemente “health”, como lo queremos en proporción al PIB del país, agregamos a la consulta “gdp”:

WDIsearch("health.*expenditure.*gdp", short = FALSE)[1:5, ] -> health_search

health_search |>
  head(5) |>
  kable(caption = "Indicadores de gasto en salud descubiertos en la API del Banco Mundial") |>
  kable_classic(html_font = "Helvetica", font_size = 14) |>
  add_footnote(label = "Tomado de la API del BM", notation = "symbol") |>
  kable_styling()
Indicadores de gasto en salud descubiertos en la API del Banco Mundial
indicator name description sourceDatabase sourceOrganization
26083 SH.XPD.CHEX.GD.ZS Current health expenditure (% of GDP) Level of current health expenditure expressed as a percentage of GDP. Estimates of current health expenditures include healthcare goods and services consumed during each year. This indicator does not include capital health expenditures such as buildings, machinery, IT and stocks of vaccines for emergency or outbreaks. World Development Indicators Global Health Expenditure Database, updated December 12th, 2025, World Health Organization (WHO), uri: https://apps.who.int/nha/database
26092 SH.XPD.GHED.GD.ZS Domestic general government health expenditure (% of GDP) Public expenditure on health from domestic sources as a share of the economy as measured by GDP. World Development Indicators Global Health Expenditure Database, updated December 12th, 2025, World Health Organization (WHO), uri: http://apps.who.int/nha/database
26097 SH.XPD.KHEX.GD.ZS Capital health expenditure (% of GDP) Level of capital investments on health expressed as a percentage of GDP. Capital health investments include health infrastructure (buildings, machinery, IT) and stocks of vaccines for emergency or outbreaks. Health Nutrition and Population Statistics World Health Organization Global Health Expenditure database (http://apps.who.int/nha/database). The data was retrieved on April 7, 2023.
26109 SH.XPD.PRIV.ZS Health expenditure, private (% of GDP) Private health expenditure includes direct household (out-of-pocket) spending, private insurance, charitable donations, and direct service payments by private corporations. WDI Database Archives World Health Organization Global Health Expenditure database (see http://apps.who.int/nha/database for the most recent updates).
26112 SH.XPD.PUBL.ZS Health expenditure, public (% of GDP) Public health expenditure consists of recurrent and capital spending from government (central and local) budgets, external borrowings and grants (including donations from international agencies and nongovernmental organizations), and social (or compulsory) health insurance funds. WDI Database Archives World Health Organization Global Health Expenditure database (see http://apps.who.int/nha/database for the most recent updates).
* Tomado de la API del BM

La serie que nos interesa es SH.XPD.GHED.GD.ZS: Domestic general government health expenditure (% of GDP)

Cambiando un único argumento (el código del indicador) se accede a otro dominio. SH.XPD.GHED.GD.ZS mide el gasto público en salud de fuentes internas como porcentaje del PIB (World Bank, s. f.-d):

datos_salud <- WDI(
  country   = c("GTM", "SLV", "HND", "NIC", "CRI", "PAN"),
  indicator = "SH.XPD.GHED.GD.ZS",
  start     = 2000, end = 2023,
  extra     = FALSE, cache = mi_cache
)

ggplot(datos_salud, aes(x = year, y = SH.XPD.GHED.GD.ZS, color = country)) +
  geom_line(linewidth = 1) +
  geom_point() +
  labs(
    title = "Gasto público en salud (% del PIB) en Centroamérica, 2000-2023",
    x = "Año", y = "Porcentaje del PIB", color = "País"
  ) +
  theme_minimal()

3.2 Vía 2: El paquete wbstats

wbstats hace lo mismo que WDI: traer datos sin escribir URLs, pero con una caja de herramientas más amplia: funciones con prefijo wb_, resultados en tibble, catálogo consultable por tema y soporte en español (Piburn 2020).

3.2.1 Paso 0: Ver el catálogo completo

wb_indicators() devuelve todo el catálogo de indicadores como tibble, con código, nombre, descripción y tema; el argumento lang permite pedirlo en español. Es la forma de “hojear” qué hay disponible. Se muestran los diez primeros:

library(wbstats)
library(dplyr)
library(kableExtra)

indicadores <- wb_indicators(lang = "es")

indicadores |>
  head(10) |>
  kable(caption = "Indicadores disponibles en la API del Banco Mundial") |>
  kable_classic(html_font = "Helvetica", font_size = 14) |>
  add_footnote(label = "Tomado de la API del BM", notation = "symbol") |>
  kable_styling()
Indicadores disponibles en la API del Banco Mundial
indicator_id indicator unit indicator_desc source_org topics source_id source
1.0.HCount.1.90usd Tasa de Incidencia de la Pobreza ($1.90 al día) NA Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2011) por debajo de la línea de pobreza. Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.HCount.2.5usd Tasa de Incidencia de la Pobreza ($2.50 al día) NA Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2005) por debajo de la línea de pobreza. Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.HCount.Mid10to50 Tasa de Incidencia de la Clase Media ($10-50 al día) NA Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2005) por debajo de la línea de pobreza. Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.HCount.Ofcl Tasa Oficial de la Pobreza Moderada-Nacional NA Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario por debajo de la línea de pobreza desarrollada por cada país. Tabulaciones del LAC Equity Lab de los datos de las Oficinas Nacionales de Estadística 11 , Pobreza 37
1.0.HCount.Poor4uds Tasa de Incidencia de la Pobreza ($4 al día) NA Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2005) por debajo de la línea de pobreza. Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.HCount.Vul4to10 Tasa de incidencia de población Vulnerable ($4-10 al día) NA Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2005) por debajo de la línea de pobreza. Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.PGap.1.90usd Brecha de Pobreza ($1.90 al día) NA La Brecha de Pobreza captura el déficit del ingreso o consumo promedio agregado relativo a la línea de pobreza a través de toda la población. Mide el total de recursos necesarios para traer a todos os pobres al nivel de la línea de pobreza (promediado sobre la población total). Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.PGap.2.5usd Brecha de Pobreza ($2.50 al día) NA La Brecha de Pobreza captura el déficit del ingreso o consumo promedio agregado relativo a la línea de pobreza a través de toda la población. Mide el total de recursos necesarios para traer a todos os pobres al nivel de la línea de pobreza (promediado sobre la población total). Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.PGap.Poor4uds Brecha de Pobreza ($4 al día) NA La Brecha de Pobreza captura el déficit del ingreso o consumo promedio agregado relativo a la línea de pobreza a través de toda la población. Mide el total de recursos necesarios para traer a todos os pobres al nivel de la línea de pobreza (promediado sobre la población total). Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
1.0.PSev.1.90usd Severidad de la Pobreza ($1.90 al día) NA El índice de severidad de la pobreza combina información tanto de pobreza como de desigualdad entre los pobres, al promediar los cuadrados de las brechas de pobreza relativas a la línea de pobreza Tabulaciones del LAC Equity Lab con datos de SEDLAC (CEDLAS y el Banco Mundial) 11 , Pobreza 37
* Tomado de la API del BM

3.2.2 Paso 1: Buscar el indicador: por palabra clave o por tema

IMPORTANTE: wb_search() no tiene argumento lang, para buscar en español primero se construye un caché en español, por ejemplo: cache = cache_es.

wb_cache(lang = "es") -> cache_es

La cobertura del español es parcial, mientras que los nombres de las variables (la columna indicator) es fiable y cuenta con traducción al español para la práctica mayoría de los indicadores, la columna de las descripciones de los indicadores (indicator_desc) no cuenta con la misma cobertura en su traducción al español y muchas descripciones de indicadores permanecen en inglés.

Al igual que WDI ofrece WDIsearch(), wbstats incluye su propia búsqueda tipo grep: wb_search(). Recibe un patrón, lo busca como expresión regular y sin distinguir mayúsculas de minúsculas sobre el código, el nombre y la descripción de los indicadores, y devuelve los que coinciden (Piburn 2020). Es el equivalente directo de WDIsearch() y suele ser la forma más rápida de dar con un código cuando se sabe qué se busca.

3.2.2.1 wb_search("string"): búsqueda tipo grep

Por defecto, busca en tres columnas: indicator_id, indicator e indicator_desc.

# Todos los indicadores relacionados con la palabra clave "remesas"
wb_search("remesas", cache = cache_es) |> head(5)
# Todos los indicadores relacionados con las palabras "gini" e "indice"
# ".*" indica que pueden haber otros caracteres o espacios entre las dos palabras

wb_search("gini.*índice", cache = cache_es) # OJO: reconoce acentos

3.2.2.2 wb_search("string", fields = " ")

Con fields = " " acotamos sobre que columnas se realiza la búsqueda:

wb_search("pobreza", fields = c("indicator", "indicator_desc"), cache = cache_es) -> pobreza_search

pobreza_search |>
  head(5) |>
  kable(caption = "Indicadores de pobreza descubiertos en la API del Banco Mundial") |>
  kable_classic(html_font = "Helvetica", font_size = 14) |>
  add_footnote(label = "Tomado de la API del BM", notation = "symbol") |>
  kable_styling()
Indicadores de pobreza descubiertos en la API del Banco Mundial
indicator_id indicator indicator_desc
1.0.HCount.1.90usd Tasa de Incidencia de la Pobreza ($1.90 al día) Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2011) por debajo de la línea de pobreza.
1.0.HCount.2.5usd Tasa de Incidencia de la Pobreza ($2.50 al día) Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2005) por debajo de la línea de pobreza.
1.0.HCount.Mid10to50 Tasa de Incidencia de la Clase Media ($10-50 al día) Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2005) por debajo de la línea de pobreza.
1.0.HCount.Ofcl Tasa Oficial de la Pobreza Moderada-Nacional Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario por debajo de la línea de pobreza desarrollada por cada país.
1.0.HCount.Poor4uds Tasa de Incidencia de la Pobreza ($4 al día) Tasa de Incidencia de la Pobreza mide la proporción de la población con ingreso per cápita diario (en PPA de 2005) por debajo de la línea de pobreza.
* Tomado de la API del BM

3.2.2.3 wb_search("string", extra = TRUE)

Controlamos cuánta información muestra la matriz resultante, extra = FALSE por defecto da solo código y nombre, extra = TRUE agrega columnas de información útiles para entender que mide un indicador antes de descargarlo:

wb_search("emisiones.*co2", extra = TRUE, cache = cache_es)

3.2.2.4 wb_indicators() + filtrado con dplyr

Cuando no se busca una palabra concreta sino un área temática, la alternativa es filtrar por la columna topics. Cada indicador está etiquetado con uno o varios temas; con grepl() y una expresión regular (la barra vertical | funciona como “o”) se conservan solo los de Public Sector: Government finance:

fiscales <- wb_indicators() |>
  filter(grepl("Public Sector", topics)) |>
  select(indicator_id, indicator)

fiscales |>
  head(10) |>
  kable(caption = "Indicadores económicos y fiscales", align = "c") |>
  kable_material(html_font = "sans-serif")
Indicadores económicos y fiscales
indicator_id indicator
GB.TAX.CMAR.ZS Highest marginal tax rate, corporate rate (%)
GC.AST.TOTL.CN Net acquisition of financial assets (current LCU)
GC.AST.TOTL.GD.ZS Net acquisition of financial assets (% of GDP)
GC.DOD.TOTL.CN Central government debt, total (current LCU)
GC.DOD.TOTL.GD.ZS Central government debt, total (% of GDP)
GC.LBL.TOTL.CN Net incurrence of liabilities, total (current LCU)
GC.LBL.TOTL.GD.ZS Net incurrence of liabilities, total (% of GDP)
GC.NFN.TOTL.CN Net investment in nonfinancial assets (current LCU)
GC.NFN.TOTL.GD.ZS Net investment in nonfinancial assets (% of GDP)
GC.NLD.TOTL.CN Net lending (+) / net borrowing (-) (current LCU)

3.2.3 Paso 2: Verificar antes de descargar (opcional)

Se puede realizar un diagnóstico de disponibilidad; devuelve un resumen precalculado con el porcentaje de observaciones no faltantes por país y el total de observaciones por país:

wb_country_coverage("producto interno bruto", 
                    country = "El Salvador", 
                    cache = cache_es)

3.2.4 Paso 3: Descargar un panel fiscal

wb_data() es la función de descarga. Su rasgo más útil: admite en indicator un vector con nombres, donde la clave se usa como nombre de columna y el valor como código del indicador, de modo que el tibble resultante llega con columnas legibles en lugar de códigos crípticos.

Descargamos cuatro indicadores fiscales cuyas definiciones oficiales son (World Bank, s. f.-d):

  • Gasto del gobierno (GC.XPN.TOTL.GD.ZS, Expense, % del PIB),
  • Presión tributaria (GC.TAX.TOTL.GD.ZS, Tax revenue, % del PIB),
  • Deuda del gobierno central (GC.DOD.TOTL.GD.ZS, Central government debt, % del PIB) y
  • Remesas personales recibidas (BX.TRF.PWKR.DT.GD.ZS, Personal remittances, % del PIB).
mis_indicadores <- c(
  Gasto_Publico        = "GC.XPN.TOTL.GD.ZS",
  Ingresos_Tributarios = "GC.TAX.TOTL.GD.ZS",
  Deuda_gobierno       = "GC.DOD.TOTL.GD.ZS",
  Remesas_Personales   = "BX.TRF.PWKR.DT.GD.ZS"
)

datos_wb <- wb_data(
  indicator  = mis_indicadores,
  country    = c("SLV", "GTM", "HND", "CRI"),
  start_date = 2000,
  end_date   = 2020
)

datos_wb |>
  head(10) |>
  kable(format = "html", caption = "Panel fiscal de Centroamérica", align = "c") |>
  add_footnote(label = "Tomado de la API del BM", notation = "symbol") |>
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, position = "center"
  )
Panel fiscal de Centroamérica
iso2c iso3c country date Remesas_Personales Deuda_gobierno Ingresos_Tributarios Gasto_Publico
CR CRI Costa Rica 2000 0.9056788 38.50185 12.83971 22.03412
CR CRI Costa Rica 2001 1.2421210 39.33511 13.36103 22.75867
CR CRI Costa Rica 2002 1.5118475 NA 13.36811 24.59492
CR CRI Costa Rica 2003 1.8578276 NA 13.58495 23.62190
CR CRI Costa Rica 2004 1.7170131 NA 13.35893 22.52539
CR CRI Costa Rica 2005 2.0974697 NA 13.63540 22.64636
CR CRI Costa Rica 2006 2.2590539 NA 13.84166 21.60123
CR CRI Costa Rica 2007 2.2984079 NA 14.85647 21.16081
CR CRI Costa Rica 2008 1.9634238 NA 15.23251 21.66894
CR CRI Costa Rica 2009 1.6688240 NA 13.18307 24.74499
* Tomado de la API del BM

El tibble devuelto trae una columna iso2c, iso3c, el nombre del país, el año y una columna por cada indicador nombrado; esa estructura ancha es la que aprovechan la tabla y los gráficos de los pasos siguientes.

3.2.5 Paso 4: Graficar la evolución de las remesas

Con los datos descargados, un ggplot de líneas muestra la trayectoria de las remesas personales (% del PIB), ampliando la consulta a los siete países del istmo:

library(ggplot2)

datos_wb2 <- wb_data(
  indicator  = mis_indicadores,
  country    = c("SLV", "GTM", "HND", "NIC", "CRI", "BLZ", "PAN"),
  start_date = 2000, end_date = 2020
)

ggplot(datos_wb2, aes(x = date, y = Remesas_Personales, color = country, group = country)) +
  geom_line(linewidth = 1) +
  scale_x_continuous(breaks = seq(2000, 2020, 5)) +
  labs(
    title = "Remesas personales recibidas (% del PIB) en Centroamérica",
    x = "Año", y = "Remesas personales (% del PIB)", color = "País"
  ) +
  theme_minimal()

3.3 Vía 3: Acceso directo con httr + jsonlite: migración y remesas

Las dos vías anteriores usan paquetes que “esconden” la API detrás de una función cómoda. Aquí haremos lo contrario: hablarle a la API directamente, para entender qué ocurre por debajo y para poder combinar series que ningún paquete trae juntas.

El caso de estudio es la relación entre migración y remesas en América Latina: en buena parte de Centroamérica y el Caribe la migración funciona como una “válvula” económica y el dinero que envían los emigrantes (las remesas) sostiene el consumo interno, hasta volverse una fuente de ingreso tan resiliente como estructural (World Bank y KNOMAD 2024).

Usaremos cuatro series, con sus definiciones oficiales (World Bank, s. f.-d):

Código Variable Papel en el análisis
BX.TRF.PWKR.DT.GD.ZS Remesas personales recibidas (% del PIB) Indicador principal (“motor”)
BX.TRF.PWKR.CD.DT Remesas personales recibidas (US$ corrientes) Magnitud en dólares
SM.POP.NETM Migración neta (personas) Presión migratoria (estimación quinquenal)
SM.POP.TOTL.ZS Stock de migrantes internacionales (% de población) Acumulado histórico de migración

El recorrido tiene seis pasos: primero veremos cómo se le pide un solo dato a la API (Paso 0); luego automatizaremos ese pedido (Paso 1), uniremos las cuatro series (Paso 2), nos quedaremos con América Latina (Paso 3) y, por último, resumiremos los datos en una tabla (Paso 4) y dos gráficos (Pasos 5 a 6).

3.3.1 Paso 0: ¿Cómo se le pide un dato a la API?

Antes de automatizar nada, conviene ver la operación más simple posible. Pedirle un dato a la API se parece a escribir una dirección web muy precisa: cada parte de esa dirección (la URL) le dice al servidor del Banco Mundial qué país, qué indicador y qué años queremos. La computadora del Banco Mundial recibe esa dirección y responde con el dato, no con una página web para leer.

library(httr)
library(jsonlite)

# Una sola pregunta a la API: remesas (% del PIB) de El Salvador, 2020-2023
url <- paste0(
  "https://api.worldbank.org/v2/",            # dirección base de la API (versión 2)
  "country/SLV/",                             # país: El Salvador (código ISO-3)
  "indicator/BX.TRF.PWKR.DT.GD.ZS",          # indicador: remesas (% del PIB)
  "?format=json&date=2020:2024&per_page=100"  # formato, rango de años y tamaño de página
)

respuesta <- GET(url)  # GET() envía la solicitud al servidor y guarda lo que responde

# content() extrae el texto de la respuesta y fromJSON() lo convierte en objetos de R
contenido <- fromJSON(content(respuesta, as = "text", encoding = "UTF-8"), flatten = TRUE)

# La respuesta llega SIEMPRE en dos partes:
contenido[[1]]$total  # (1) metadata: cuántos registros encontró
#> [1] 5
contenido[[2]][, c("country.value", "date", "value")]  # (2) los datos que pedimos

Lo esencial que hay que retener de este paso:

  • 1. la URL se arma por piezas: país, indicador, formato, años;
  • 2. GET() hace la pregunta y fromJSON() traduce la respuesta a algo que R entiende; y
  • 3. esa respuesta siempre trae dos partes: primero la metadata (cuántos datos hay y en cuántas “páginas” están repartidos) y después los datos en sí (World Bank, s. f.-b). Todo lo que sigue no es más que repetir esta misma idea de forma automática.

3.3.2 Paso 1: Automatizar el pedido con una función

Escribir esa URL para cada país, indicador y año sería muy lento y quedaría propenso a errores. La siguiente función arma la URL automáticamente, hace la solicitud y devuelve una tabla ordenada. Añade además una protección: cuando hay muchos datos, la API los reparte en varias “páginas”, así que la función revisa cuántas páginas hay (pages) y, si es necesario, descarga y une las que falten con jsonlite::rbind_pages().

library(dplyr)

wb_indicador <- function(codigo, paises = "all", inicio = 1960, fin = 2026, per_page = 20000) {
  url_base <- paste0(
    "https://api.worldbank.org/v2/country/", paises, "/indicator/", codigo,
    "?format=json&date=", inicio, ":", fin, "&per_page=", per_page
  )

  resp <- GET(url_base)
  stop_for_status(resp)   # si la API falla, se detiene con un mensaje claro

  crudo         <- fromJSON(content(resp, as = "text", encoding = "UTF-8"), flatten = TRUE)
  metadata      <- crudo[[1]]         # la parte (1): metadata
  total_paginas <- metadata$pages     # ¿en cuántas páginas viene la respuesta?

  paginas <- list(crudo[[2]])         # la parte (2): datos de la primera página
  if (!is.null(total_paginas) && total_paginas > 1) {
    for (p in 2:total_paginas) {      # descarga las páginas restantes, si las hay
      resp_p  <- GET(paste0(url_base, "&page=", p))
      stop_for_status(resp_p)
      crudo_p <- fromJSON(content(resp_p, as = "text", encoding = "UTF-8"), flatten = TRUE)
      paginas[[p]] <- crudo_p[[2]]
    }
  }

  rbind_pages(paginas) |>             # pega todas las páginas en una sola tabla
    as_tibble() |>
    transmute(
      # coalesce por robustez: algunas bases del BM dejan vacío countryiso3code
      # y colocan el ISO-3 en country.id; coalesce toma el primer valor no vacío
      iso3c     = coalesce(na_if(countryiso3code, ""), country.id),
      anio      = as.integer(date),
      !!codigo := value               # la columna de valores toma el nombre del código
    )
}

Tres detalles clave: stop_for_status() interrumpe el proceso con un aviso legible si el servidor responde con error, en lugar de dejar que el problema aparezca más adelante disfrazado. La línea de la llave iso3c resuelve una inconsistencia real del Banco Mundial: según la base, el código de país (ISO-3) llega a veces en la columna countryiso3code y a veces en country.id; coalesce() simplemente toma “el que no esté vacío”, de modo que las uniones posteriores nunca fallen. Y !!codigo := value hace que la columna de valores se llame igual que el indicador, lo que evita choques de nombres al unir varias series.

3.3.3 Paso 2: Descargar las cuatro series y unirlas

Aplicamos la función a los cuatro indicadores con purrr::map() (que repite la descarga para cada código) (Wickham y Henry 2023) y pegamos los resultados con reduce(full_join, ...). El full_join es una unión “generosa”: conserva toda combinación de país y año que aparezca en cualquiera de las series, aunque una tenga más años que otra.

library(purrr)

codigos <- c("BX.TRF.PWKR.DT.GD.ZS", "BX.TRF.PWKR.CD.DT", "SM.POP.NETM", "SM.POP.TOTL.ZS")

panel_migracion <- codigos |>
  map(wb_indicador) |>                           # una tabla por indicador
  reduce(full_join, by = c("iso3c", "anio")) |>  # las une por país y año
  rename(
    remesas_pib     = "BX.TRF.PWKR.DT.GD.ZS",
    remesas_usd     = "BX.TRF.PWKR.CD.DT",
    migracion_neta  = "SM.POP.NETM",
    stock_migrantes = "SM.POP.TOTL.ZS"
  )

3.3.4 Paso 3: Quedarnos solo con América Latina

El panel anterior trae el mundo entero, e incluso “países” que en realidad son agregados (como “Mundo” o “Ingreso alto”). Para quedarnos con países latinoamericanos individuales, pedimos a la API su catálogo de países y lo filtramos por región (Wickham 2023b).

library(stringr)

meta_resp <- GET("https://api.worldbank.org/v2/country?format=json&per_page=400")
stop_for_status(meta_resp)
meta <- fromJSON(content(meta_resp, 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

Ahora un inner_join entre el panel mundial y ese catálogo hace dos cosas a la vez: añade el nombre del país y su región, y filtra, porque solo sobreviven las filas cuyo país aparece en el catálogo latinoamericano (los agregados y las demás regiones se quedan fuera automáticamente).

migracion_latam <- panel_migracion |>
  inner_join(paises_lac, by = "iso3c") |>
  relocate(pais, region, ingreso, .after = iso3c) |>
  arrange(pais, anio)

3.3.5 Paso 4: Una tabla con el último dato disponible

Las cuatro series no se publican al mismo ritmo: las remesas son anuales, pero la migración neta es una estimación que el Banco Mundial reporta cada cinco años. Por eso buscamos el último dato de cada indicador por separado. La receta: estirar la tabla a formato “largo” con pivot_longer(), tomar el año más reciente de cada par país-indicador con slice_max(), y volver a “ancho” con pivot_wider() (Wickham et al. 2024). La presentación final usa kableExtra (Zhu 2024).

library(tidyr)
library(kableExtra)

migracion_largo <- migracion_latam |>
  pivot_longer(
    cols = c(remesas_pib, remesas_usd, migracion_neta, stock_migrantes),
    names_to = "codigo_indicador", values_to = "valor"
  ) |>
  filter(!is.na(valor)) |>
  mutate(indicador = recode(codigo_indicador,
    remesas_pib     = "Remesas recibidas (% del PIB)",
    remesas_usd     = "Remesas recibidas (US$ corrientes)",
    migracion_neta  = "Migración neta (personas)",
    stock_migrantes = "Stock de migrantes internacionales (% población)"
  ))

tabla_migracion <- migracion_largo |>
  group_by(pais, indicador) |>
  slice_max(anio, n = 1, with_ties = FALSE) |>   # el año más reciente con dato
  ungroup() |>
  mutate(valor_con_anio = paste0(round(valor, 2), " (", anio, ")")) |>
  select(pais, indicador, valor_con_anio) |>
  pivot_wider(names_from = indicador, values_from = valor_con_anio)

tabla_migracion |>
  kable(caption = "América Latina y el Caribe: migración y remesas, último dato disponible") |>
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, html_font = "Helvetica", font_size = 11
  ) |>
  footnote(symbol = "Entre paréntesis, el año oficial más reciente disponible.")
América Latina y el Caribe: migración y remesas, último dato disponible
pais Migración neta (personas) Remesas recibidas (% del PIB) Remesas recibidas (US$ corrientes) Stock de migrantes internacionales (% población)
Antigua and Barbuda 12 (2025) 0.94 (2025) 22036892.59 (2025) 32.5 (2024)
Argentina 2859 (2025) 0.13 (2025) 916447215.5 (2025) 4.3 (2024)
Aruba 111 (2025) 1.04 (2023) 38964260.61 (2023) 68 (2024)
Bahamas, The 935 (2025) 0.42 (2024) 65929000 (2024) 16.8 (2024)
Barbados -87 (2025) 1.46 (2017) 85175892.5 (2017) 12.5 (2024)
Belize 360 (2025) 3.72 (2025) 123831546.94 (2025) 16.5 (2024)
Bolivia -3179 (2025) 1.96 (2025) 1267996895.51 (2025) 1.5 (2024)
Brazil -217283 (2025) 0.21 (2025) 4758109116.62 (2025) 0.7 (2024)
British Virgin Islands 153 (2025) NA NA 62.1 (2024)
Cayman Islands 888 (2025) 0.15 (2024) 11496340.14 (2024) 42.9 (2024)
Chile 51712 (2025) 0.03 (2025) 100289867.6 (2025) 7.8 (2024)
Colombia 129139 (2025) 2.87 (2025) 13129361534.85 (2025) 5.8 (2024)
Costa Rica 1000 (2025) 0.83 (2025) 853351002.16 (2025) 12.2 (2024)
Cuba -22244 (2025) NA NA 0 (2024)
Curacao 470 (2025) 5.38 (2023) 176607685.45 (2023) 43.1 (2024)
Dominica -242 (2025) 5.48 (2025) 39633245.56 (2025) 12.7 (2024)
Dominican Republic -35306 (2025) 9.74 (2025) 12411400000 (2025) 6.5 (2024)
Ecuador -17219 (2025) 5.93 (2025) 7734058771.59 (2025) 4.1 (2024)
El Salvador -23934 (2025) 27.51 (2025) 10098866981.46 (2025) 0.7 (2024)
Grenada -185 (2025) 3.35 (2025) 47508314.81 (2025) 6.3 (2024)
Guatemala -7959 (2025) 19.12 (2024) 21644521520 (2024) 0.5 (2024)
Guyana -5092 (2025) 3.22 (2023) 545579977.92 (2023) 6.5 (2024)
Haiti -32052 (2025) 16.95 (2024) 4111002565.95 (2024) 0.2 (2024)
Honduras -4778 (2025) 30.12 (2025) 11927362660.75 (2025) 0.4 (2024)
Jamaica -11053 (2025) 16.19 (2024) 3564377716.21 (2024) 0.8 (2024)
Mexico -108037 (2025) 3.51 (2025) 64391618338 (2025) 1.3 (2024)
Nicaragua -8371 (2025) 26.63 (2024) 5245600000 (2024) 0.6 (2024)
Panama 6151 (2025) 0.7 (2025) 634454278.24 (2025) 10.6 (2024)
Paraguay -12423 (2025) 3.1 (2025) 1525903924.32 (2025) 2.6 (2024)
Peru 11931 (2025) 1.58 (2025) 5299341957.05 (2025) 5.4 (2024)
Puerto Rico (US) 5495 (2025) NA NA 6.9 (2024)
Sint Maarten (Dutch part) 530 (2025) 2.85 (2023) 48022544.58 (2023) 69.5 (2024)
St. Kitts and Nevis 18 (2025) 3.36 (2025) 39716697.41 (2025) 17 (2024)
St. Lucia -23 (2025) 2.35 (2025) 62478904.44 (2025) 4.5 (2024)
St. Martin (French part) -1170 (2025) NA NA 0 (2024)
St. Vincent and the Grenadines -714 (2025) 7.04 (2025) 88324437.04 (2025) 4.8 (2024)
Suriname -967 (2025) 3.89 (2025) 176127338.79 (2025) 8.2 (2024)
Trinidad and Tobago 691 (2025) 0.77 (2025) 199557121.67 (2025) 7.5 (2024)
Turks and Caicos Islands 177 (2025) 0.57 (2018) 7481920 (2018) 61.1 (2024)
Uruguay -1338 (2025) 0.18 (2025) 149981548.74 (2025) 4.7 (2024)
Venezuela, RB -100467 (2025) 0.25 (2016) 2.79e+08 (2016) 4.4 (2024)
Virgin Islands (U.S.) -357 (2025) NA NA 66.9 (2024)
* Entre paréntesis, el año oficial más reciente disponible.

3.3.6 Paso 5: ¿Quién depende más de las remesas hoy?

Un gráfico de barras ordena a los países por su nivel actual de remesas sobre el PIB. Fijamos una paleta de colores para seis economías clave.

library(ggplot2)

paises_clave <- c("El Salvador", "Honduras", "Guatemala", "Nicaragua", "Costa Rica", "Mexico")
paleta_paises <- c(
  "El Salvador" = "#e41a1c", "Honduras" = "#377eb8", "Guatemala" = "#4daf4a",
  "Nicaragua" = "#984ea3", "Costa Rica" = "#ff7f00", "Mexico" = "#a65628"
)

snapshot_remesas <- migracion_largo |>
  filter(codigo_indicador == "remesas_pib") |>
  group_by(pais) |>
  slice_max(anio, n = 1, with_ties = FALSE) |>
  ungroup() |>
  mutate(grupo = if_else(pais %in% paises_clave, pais, "Otros países de la región"))

ggplot(snapshot_remesas, aes(x = reorder(pais, valor), y = valor, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = round(valor, 1)), hjust = -0.15, size = 3, color = "gray30") +
  coord_flip() +
  scale_fill_manual(values = c(paleta_paises, "Otros países de la región" = "grey80"), name = NULL) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.12))) +
  labs(
    title = "Remesas como motor económico en América Latina y el Caribe",
    subtitle = "Remesas personales recibidas (% del PIB), último año disponible por país",
    x = NULL, y = "% del PIB",
    caption = "Fuente: Banco Mundial (WDI), BX.TRF.PWKR.DT.GD.ZS"
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")

3.3.7 Paso 6: La evolución en el tiempo (serie temporal interactiva)

Para ver cómo cambió la dependencia de las remesas usamos TSstudio::ts_plot(), que produce un gráfico de líneas (Krispin 2020).

library(TSstudio)

# 1) Remesas (% del PIB) de los países clave, en formato ancho: años en filas,
#    países en columnas, con la rejilla de años completa (NA donde no hay dato).
serie_wide <- migracion_largo |>
  filter(codigo_indicador == "remesas_pib", pais %in% paises_clave) |>
  select(pais, anio, valor) |>
  complete(pais, anio = full_seq(anio, 1)) |>   # rejilla anual completa (sin huecos)
  pivot_wider(names_from = pais, values_from = valor) |>
  arrange(anio)

# 2) Convertir a serie temporal ANUAL: frequency = 1 y start = primer año.
anio_inicial <- min(serie_wide$anio)
serie_ts <- ts(serie_wide[, -1], start = anio_inicial, frequency = 1)

# 3) Graficar de forma interactiva.
ts_plot(serie_ts,
        title  = "Evolución de las remesas recibidas (% del PIB)",
        Xtitle = "Año",
        Ytitle = "% del PIB")

El bloque hace tres cosas: reorganiza los datos a una tabla de años × países, rellena los años faltantes para que la serie no tenga saltos, y recién entonces la convierte en un objeto ts anual (frequency = 1) que ts_plot() puede dibujar. La frecuencia debe reflejar la periodicidad real de los datos.

4 Buenas prácticas y conclusión

  • 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 Conclusión

En conclusión, la API REST v2 del Banco Mundial representa una herramienta fundamental para la investigación económica contemporánea al facilitar la extracción programática de miles de indicadores globales. Mediante el uso de R, este enfoque no solo optimiza el trabajo analítico del economista y contribuye a la sociedad mediante estudios reproducibles, sino que también democratiza el acceso a la información. Aunque existen tres vías principales de acceso: los paquetes WDI, wbstats y el consumo directo en JSON, wbstats se posiciona como la alternativa más flexible, completa y eficiente para estructurar flujos de trabajo analíticos.


Todo el análisis es reproducible en el entorno estadístico R (R Core Team 2025) con los paquetes WDI (Arel-Bundock 2025), wbstats (Piburn 2020), httr (Wickham 2023a), jsonlite (Ooms 2014), dplyr (Wickham et al. 2023), tidyr (Wickham et al. 2024), purrr (Wickham y Henry 2023), stringr (Wickham 2023b), ggplot2 (Wickham 2016), kableExtra (Zhu 2024) y TSstudio (Krispin 2020).

Referencias

Arel-Bundock, Vincent. 2025. WDI: World Development Indicators and Other World Bank Data. https://vincentarelbundock.github.io/WDI/.
Bauer, Paul C., Camille Landesvatter, y Lion Behrens. 2022. APIs for Social Scientists: A Collaborative Review (V1.0). Online book. https://bookdown.org/paul/apis_for_social_scientists/.
Fielding, Roy Thomas. 2000. «Architectural Styles and the Design of Network-based Software Architectures». Tesis doctoral, University of California, Irvine. https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm.
Hartig, Olaf, y Jorge Pérez. 2018. «Semantics and Complexity of GraphQL». Proceedings of the 2018 World Wide Web Conference (WWW ’18) (Lyon, France), 1155-64. https://doi.org/10.1145/3178876.3186014.
Khokhar, Tariq. 2013. Accessing the World Bank Data APIs in Python, R, Ruby & Stata. World Bank Data Blog. https://blogs.worldbank.org/en/opendata/accessing-world-bank-data-apis-python-r-ruby-stata.
Krispin, Rami. 2020. TSstudio: Functions for Time Series Analysis and Forecasting. https://github.com/RamiKrispin/TSstudio.
Ofoeda, Joshua, Richard Boateng, y John Effah. 2019. «Application Programming Interface (API) Research: A Review of the Past to Inform the Future». International Journal of Enterprise Information Systems 15 (3): 76-95. https://doi.org/10.4018/IJEIS.2019070105.
Ooms, Jeroen. 2014. «The jsonlite Package: A Practical and Consistent Mapping Between JSON Data and R Objects». arXiv:1403.2805 [stat.CO]. https://arxiv.org/abs/1403.2805.
Peng, Roger D. 2011. «Reproducible Research in Computational Science». Science 334 (6060): 1226-27. https://doi.org/10.1126/science.1213847.
Piburn, Jesse. 2020. wbstats: Programmatic Access to Data and Statistics from the World Bank API. https://doi.org/10.11578/dc.20171025.1827.
R Core Team. 2025. R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing. https://www.R-project.org/.
Richardson, Leonard, y Sam Ruby. 2007. RESTful Web Services. O’Reilly Media.
Wickham, Hadley. 2016. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.
Wickham, Hadley. 2023a. httr: Tools for Working with URLs and HTTP. https://httr.r-lib.org/.
Wickham, Hadley. 2023b. stringr: Simple, Consistent Wrappers for Common String Operations. https://stringr.tidyverse.org.
Wickham, Hadley, Romain François, Lionel Henry, Kirill Müller, y Davis Vaughan. 2023. dplyr: A Grammar of Data Manipulation. https://dplyr.tidyverse.org.
Wickham, Hadley, y Lionel Henry. 2023. purrr: Functional Programming Tools. https://purrr.tidyverse.org.
Wickham, Hadley, Davis Vaughan, y Maximilian Girlich. 2024. tidyr: Tidy Messy Data. https://tidyr.tidyverse.org.
World Bank. s. f.-a. About the Indicators API Documentation. World Bank Data Help Desk. Accedido 12 de septiembre de 2026. https://datahelpdesk.worldbank.org/knowledgebase/articles/889392-about-the-indicators-api-documentation.
World Bank. s. f.-b. API Basic Call Structures. World Bank Data Help Desk. Accedido 12 de septiembre de 2026. https://datahelpdesk.worldbank.org/knowledgebase/articles/898581-api-basic-call-structures.
World Bank. s. f.-c. New Features and Enhancements in the V2 API. World Bank Data Help Desk. Accedido 12 de septiembre de 2026. https://datahelpdesk.worldbank.org/knowledgebase/articles/1886674-new-features-and-enhancements-in-the-v2-api.
World Bank. s. f.-d. World Development Indicators. World Bank Data. Accedido 12 de septiembre de 2026. https://datatopics.worldbank.org/world-development-indicators/.
World Bank, y KNOMAD. 2024. Migration and Development Brief 40. World Bank; Global Knowledge Partnership on Migration; Development (KNOMAD). https://www.knomad.org/publication/migration-and-development-brief-40.
Zhu, Hao. 2024. kableExtra: Construct Complex Table with ’kable’ and Pipe Syntax. https://haozhu233.github.io/kableExtra/.