Pide a cinco servicios distintos el tipo de cambio EUR/USD ahora mismo y obtendrás cinco números ligeramente diferentes. No radicalmente distintos, pero sí en el cuarto decimal, a veces en el tercero. Si alguna vez tu equipo financiero ha abierto una incidencia porque el checkout mostraba 1,0847 mientras el extracto bancario decía 1,0821, ya sabes que esto no es una cuestión académica.
Entonces, ¿de dónde obtienen sus datos las APIs de tipos de cambio? La respuesta honesta es que ninguna API "conoce" el tipo de cambio, porque no existe un único tipo de cambio que conocer. El mercado de divisas es un mercado extrabursátil sin bolsa central ni campana de cierre: solo miles de instituciones cotizando precios entre sí en todo el mundo. Cada API que puedes llamar es una tubería que muestrea ese mercado, lo limpia y te entrega un número. Esta guía recorre esa tubería capa por capa, explica exactamente por qué dos proveedores discrepan y te enseña a auditar una fuente antes de construir lógica de facturación sobre ella.
La respuesta corta: tres capas entre el mercado y tu JSON
Toda API de tipos de cambio —gratuita o de pago, incluida la nuestra— se construye sobre las mismas tres capas:
- Adquisición. Los precios en bruto se obtienen de fuentes upstream: feeds institucionales de FX, publicaciones de bancos centrales y cotizaciones de brókers o del mercado minorista.
- Normalización. Esos precios se validan, se descartan los valores atípicos, se combinan varias fuentes y se deriva un único tipo de referencia por par.
- Entrega. El tipo derivado se captura según una frecuencia determinada, se cachea y se sirve por HTTP con una marca de tiempo.
Las diferencias en cualquiera de esas tres capas producen un número distinto en tu cuerpo de respuesta. La mayoría de los desarrolladores asume que la discrepancia viene de la capa 1. En la práctica, las capas 2 y 3 causan otro tanto.
Capa 1 — De dónde salen realmente los precios en bruto
Feeds interbancarios e institucionales
Lo más parecido a un tipo de cambio "real" es el mercado interbancario: los precios a los que grandes bancos y proveedores de liquidez operan entre sí. Estos precios llegan como flujos continuos de cotizaciones bid y ask desde plataformas de negociación, prime brokers y proveedores de datos de mercado.
Este tipo de feed es la fuente de mayor fidelidad disponible. También es la más cara, y esa es la razón principal por la que las APIs gratuitas rara vez la usan como fuente primaria. Cuando un proveedor dice ofrecer tipos "en tiempo real" o "por debajo del minuto", casi siempre es porque hay feeds institucionales en la cima de su tubería.
Ten en cuenta que un feed interbancario te da dos precios, no uno: un bid y un ask. El tipo único que ves en una respuesta de API suele ser el punto medio entre ambos. Si esa distinción te resulta nueva, nuestra guía sobre el spread bid-ask en el cambio de divisas lo cubre en detalle.
Tipos de referencia de bancos centrales
La segunda gran fuente son las publicaciones oficiales de bancos centrales. El ejemplo más conocido es el Banco Central Europeo, que publica sus tipos de cambio de referencia del euro cada día hábil TARGET en torno a las 16:00 CET, sobre la base de un procedimiento de concertación entre bancos centrales europeos. Decenas de otros bancos centrales publican tipos diarios equivalentes para sus propias monedas.
Los tipos de bancos centrales tienen dos ventajas enormes: son gratuitos y son autoritativos. Muchas administraciones tributarias y normas contables los aceptan explícitamente para reporting. Por eso buena parte del ecosistema de APIs gratuitas se construye sobre ellos. Frankfurter, un proyecto de código abierto muy utilizado en este espacio, rastrea tipos diarios de 84 bancos centrales cubriendo 201 divisas, con histórico que se remonta a 1948, todo ello datos públicos redistribuidos.
También tienen dos limitaciones serias:
- Son capturas diarias, no precios en vivo. Un tipo de referencia de las 16:00 CET no te dice nada de lo que ocurrió a las 09:00 o a las 22:00.
- Se detienen los fines de semana y festivos. Si tu API no devuelve datos para un sábado, o repite el número del viernes, una fuente derivada del BCE suele ser la explicación.
Cotizaciones minoristas y de brókers
La tercera fuente es el precio de cara al cliente final: lo que un banco, una red de tarjetas, un procesador de pagos o un servicio de transferencias le dará realmente a un cliente. Estos tipos ya incluyen un margen, una comisión incorporada al precio por encima del tipo de mercado.
Esta es la razón por la que un tipo que ves en un comparador de consumo no coincide con el de tu extracto bancario. No es un error en ninguno de los dos sitios; están midiendo cosas distintas. Los sitios de consumo suelen mostrar el tipo medio de mercado, mientras que tu banco te cotiza el tipo medio más su spread. Para la mayoría de casos de uso de software, quieres el número medio de mercado y quieres aplicar tu propio margen de forma explícita, donde puedas verlo y auditarlo.
Capa 2 — Cómo los proveedores convierten los feeds en un único tipo
Una vez que llegan los precios en bruto, el proveedor tiene que decidir qué número publicar. Aquí ocurren cuatro decisiones, y cada una de ellas es un punto donde los proveedores divergen.
Mezcla (blending). La mayoría de las APIs comerciales no dependen de una única fuente upstream. Open Exchange Rates, por ejemplo, describe sus datos como recopilados de múltiples proveedores y combinados algorítmicamente. La mezcla suaviza un tick malo aislado, pero los pesos de la combinación son propietarios, y precisamente por eso dos feeds mezclados nunca coinciden exactamente.
Rechazo de atípicos. Una cotización errónea de una plataforma puede desviarse un orden de magnitud. Los proveedores aplican filtros que descartan precios fuera de una banda de tolerancia alrededor del consenso. Un filtrado agresivo significa tipos estables pero reacción más lenta a movimientos genuinos. Un filtrado laxo significa reacción rápida pero ruido ocasional.
Derivación del medio. Si el feed upstream es bid/ask, el proveedor publica un medio. El punto medio simple (bid + ask) / 2 es lo estándar, pero los enfoques ponderados por volumen producen un resultado ligeramente distinto.
Triangulación de cruces. Ningún proveedor obtiene directamente los más de 30.000 pares de divisas posibles. En su lugar, la mayoría de los pares se calculan a través de una divisa pivote, normalmente USD o EUR:
GBP/JPY = (USD/JPY) / (USD/GBP)Eso significa que el tipo que obtienes para un par exótico hereda el redondeo y el timing de otros dos pares. Los proveedores que pivotan sobre USD y los que pivotan sobre EUR llegarán a números distintos para el mismo cruce. Cubrimos la mecánica en tipos de cambio cruzados explicados.
Capa 3 — Cómo llega el tipo a tu código
La capa final es la que los desarrolladores más controlan y menos piensan.
La frecuencia de actualización es el mayor diferenciador entre proveedores y entre planes de precios. Los planes gratuitos suelen refrescar una o dos veces al día. Los planes de pago refrescan cada hora, cada diez minutos o cada 60 segundos. Dos APIs con datos idénticos discreparán simplemente porque una capturó a las 14:00 y la otra a las 14:47.
El cacheo agrava esto. La mayoría de las APIs están detrás de una CDN, y la mayoría de los clientes bien construidos cachean localmente encima. Añade una caché de borde de 15 minutos a un refresco de 10 minutos y tu aplicación podría estar trabajando con un tipo de hace 25 minutos. Eso está bien para mostrar precios e es inaceptable para liquidar una operación: la pregunta práctica siempre es cuánta antigüedad es demasiada para esta operación concreta. Nuestra guía sobre cacheo y gestión de errores en APIs de divisas explica cómo dimensionar esas ventanas.
Las marcas de tiempo son tu defensa. Toda API seria devuelve el momento en que se capturó el tipo. Léelo. No asumas que el momento en que recibiste la respuesta es el momento en que el tipo era cierto:
const MAX_AGE_SECONDS = 900; // 15 minutes
async function getRate(base, symbol) {
const res = await fetch(
`https://api.finexly.com/v1/latest?base=${base}&symbols=${symbol}`,
{ headers: { Authorization: `Bearer ${process.env.FINEXLY_API_KEY}` } }
);
const data = await res.json();
const ageSeconds = Math.floor(Date.now() / 1000) - data.timestamp;
if (ageSeconds > MAX_AGE_SECONDS) {
throw new Error(`Rate is ${ageSeconds}s old — refusing to price on stale data`);
}
return { rate: data.rates[symbol], ageSeconds };
}Esta es la petición subyacente y una forma representativa de la respuesta:
curl "https://api.finexly.com/v1/latest?base=USD&symbols=EUR,GBP,JPY" \
-H "Authorization: Bearer YOUR_API_KEY"{
"success": true,
"base": "USD",
"timestamp": 1755244800,
"rates": {
"EUR": 0.9241,
"GBP": 0.7863,
"JPY": 147.2150
}
}Todos los detalles de parámetros y endpoints están en la documentación de la API de Finexly.
Por qué dos APIs devuelven números distintos para el mismo par
Uniendo las tres capas, estas son las seis causas de discrepancia, aproximadamente en orden de daño causado:
- Momentos de captura distintos. La causa más común con diferencia. Nada falla en ninguno de los dos feeds; simplemente miraron en momentos distintos.
- Mezclas de fuentes distintas. Un tipo derivado de banco central y uno derivado del interbancario miden dos cosas diferentes por definición.
- Medio de mercado frente a precio con margen. Un proveedor te da el punto medio del mercado, otro te da un precio de cara al cliente con el spread ya dentro.
- Divisas pivote distintas para los cruces. La triangulación vía USD y vía EUR produce resultados diferentes para el mismo par no-USD.
- Precisión y redondeo. Seis decimales truncados a cuatro, o tipos publicados como pares inversos y vueltos a invertir, ambos introducen desviación.
- Capas de caché que olvidaste. Tu CDN, la caché HTTP de tu framework y tu propia capa Redis suman antigüedad.
Una regla útil: para pares principales, una diferencia de unos pocos puntos básicos (0,01% = 1 pb) entre dos fuentes reputadas de medio de mercado es normal y esperable. Una diferencia de 50 pb o más significa que una de las dos está desactualizada, lleva margen o está rota, y deberías averiguar cuál antes de desplegar.
Cómo auditar una API de tipos de cambio antes de confiar en ella
No aceptes las afirmaciones de precisión de un proveedor por fe. Ejecuta esta comprobación durante una semana contra la fuente que tu equipo financiero considere autoritativa:
import os
import requests
from datetime import datetime, timezone
FINEXLY_URL = "https://api.finexly.com/v1/latest"
HEADERS = {"Authorization": f"Bearer {os.environ['FINEXLY_API_KEY']}"}
def get_rate(base: str, symbol: str) -> dict:
r = requests.get(
FINEXLY_URL,
headers=HEADERS,
params={"base": base, "symbols": symbol},
timeout=5,
)
r.raise_for_status()
data = r.json()
return {
"rate": data["rates"][symbol],
"captured_at": datetime.fromtimestamp(data["timestamp"], tz=timezone.utc),
}
def basis_points(a: float, b: float) -> float:
"""Difference between two rates, in basis points."""
return abs(a - b) / ((a + b) / 2) * 10_000
primary = get_rate("EUR", "USD")
reference = 1.0839 # whatever your accounting source published
diff = basis_points(primary["rate"], reference)
print(f"Finexly: {primary['rate']} captured {primary['captured_at']:%H:%M UTC}")
print(f"Reference: {reference}")
print(f"Delta: {diff:.1f} bp -> {'OK' if diff < 25 else 'INVESTIGATE'}")Tres cosas que buscar en los resultados:
- ¿La diferencia es estable o va a la deriva? Un desfase constante sugiere un margen sistemático. Uno aleatorio sugiere timing.
- ¿La diferencia se dispara a ciertas horas? Eso apunta al momento de captura, normalmente alrededor de una ventana de publicación de un banco central.
- ¿Qué pasa los fines de semana? Si tu fuente se congela el viernes por la tarde y se reanuda el lunes, es derivada de banco central: planifica tu conciliación del lunes en consecuencia.
También puedes verificar la triangulación obteniendo un cruce directamente y calculándolo vía USD; ambos deberían coincidir con un margen de uno o dos puntos básicos.
Cómo elegir una fuente de datos según tu caso de uso
No hay una fuente universalmente "mejor", solo la fuente adecuada para lo que estás construyendo.
| Caso de uso | Qué necesitas | Antigüedad aceptable |
|---|---|---|
| Mostrar precios a compradores | Tipo medio de mercado, con tu propio margen encima | Horas |
| Facturación de suscripciones SaaS | Medio de mercado, una captura por ciclo de facturación, guardada con la factura | Horas, pero debe quedar registrada |
| Contabilidad y reporting fiscal | Tipo de referencia del banco central para la fecha concreta | Diaria, por definición |
| Analítica y dashboards | Serie histórica consistente de una única fuente | Diaria |
| Pagos y remesas | Medio de mercado fresco con una banda de tolerancia explícita | Minutos |
| Trading y cobertura | Bid/ask real de un feed institucional | Segundos |
Si todavía estás evaluando opciones, nuestra comparativa de APIs de divisas gratuitas frente a de pago desglosa qué cambia al subir de plan, y la página de planes de precios muestra dónde encajan la frecuencia de actualización y los límites de peticiones. Para una comprobación manual rápida de cualquier par, el conversor de divisas usa el mismo feed subyacente que la API.
Preguntas frecuentes
¿De dónde obtienen sus datos las APIs de divisas gratuitas?
Casi siempre de publicaciones de bancos centrales, con más frecuencia de los tipos de referencia diarios del euro del Banco Central Europeo, a veces combinados con un puñado de otras fuentes públicas. Por eso los planes gratuitos suelen refrescar una vez al día, saltarse los fines de semana y cubrir menos divisas exóticas que los de pago.
¿Por qué el tipo de cambio de mi API es distinto al de Google?
Google muestra un tipo de referencia medio de mercado, que es una captura y no un precio continuo en vivo, y no necesariamente se muestrea en el mismo instante que tu llamada a la API. Una diferencia pequeña es normal. Una grande suele significar que uno de los dos es un tipo minorista con margen y no un tipo medio de mercado.
¿Qué tipo de cambio debo usar para contabilidad y reporting fiscal?
Usa el tipo de referencia oficial publicado por el banco central correspondiente para la fecha de la transacción: eso es lo que esperan la mayoría de las administraciones tributarias. Obtenlo de un endpoint histórico con fecha explícita en lugar de reutilizar un tipo en vivo, y guárdalo con el registro de la transacción.
¿Una API de tipos de cambio en tiempo real es realmente en tiempo real?
Rara vez en el sentido literal. "Tiempo real" suele significar que el proveedor refresca en un intervalo corto —60 segundos es habitual en el plan más alto— no que transmita tick a tick. Comprueba la marca de tiempo en la respuesta y el intervalo de refresco documentado, no el texto de marketing.
¿Puedo simplemente hacer scraping de tipos de cambio en lugar de usar una API?
Puedes, pero heredas todos los modos de fallo de la página que raspas: cambios de maquetación, limitación de peticiones, ausencia de marcas de tiempo, ausencia de histórico y, con frecuencia, una violación de los términos de servicio. Cubrimos el balance completo en API de divisas frente a web scraping.
Construye sobre un feed que puedas auditar
Saber de dónde vienen tus datos de tipos de cambio es la diferencia entre un bug de divisas que puedes explicar en una frase y otro que se come una semana de ingeniería. Hazle tres preguntas a cualquier proveedor antes de integrarlo: cuáles son las fuentes, con qué frecuencia se refresca y si cada respuesta lleva una marca de tiempo de captura.
¿Listo para integrar tipos de cambio que realmente puedes auditar? Consigue tu clave gratuita de la API de Finexly: sin tarjeta de crédito. Empieza con 1.000 peticiones gratuitas al mes en más de 170 divisas, con respuestas con marca de tiempo y datos históricos desde el primer día.
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →