API de tipos de cambio por WebSocket
Suscríbete a pares compatibles y recibe actualizaciones en una conexión persistente. Guarda tu clave API en el servidor.
Inicia una conexión
Conéctate a wss://api.exchangerate.dev/v1/stream, envía auth en 10 segundos y suscríbete después de authenticated.
Ejemplo de conexión
Esta secuencia del servidor autentica una clave y se suscribe a USD/EUR y USD/JPY.
// Node.js 22+ · run on your server · set EXCHANGERATE_API_KEY in the environment
const key = process.env.EXCHANGERATE_API_KEY;
if (!key) throw new Error("EXCHANGERATE_API_KEY is required");
let retries = 0;
let stopped = false;
function connect() {
const ws = new WebSocket("wss://api.exchangerate.dev/v1/stream");
ws.addEventListener("open", () => {
ws.send(JSON.stringify({ action: "auth", api_key: key }));
});
ws.addEventListener("message", ({ data }) => {
const frame = JSON.parse(String(data));
if (frame.type === "authenticated") {
retries = 0;
ws.send(JSON.stringify({ action: "subscribe", base: "USD", symbols: ["EUR", "JPY"] }));
} else if (frame.type === "snapshot" || frame.type === "update") {
if (frame.stale) return; // Keep the observation time; don't treat it as a fresh tick.
console.log(frame.base, frame.symbol, frame.rate, frame.effective_at);
} else if (frame.type === "state") {
console.log(frame.base, frame.symbol, frame.state); // stale or unavailable
} else if (frame.type === "error") {
console.error(frame.code, frame.message);
if (["invalid_api_key", "quota_exceeded", "connection_limit_exceeded", "subscription_limit_exceeded"].includes(frame.code)) {
stopped = true;
ws.close();
}
}
});
ws.addEventListener("close", () => {
if (stopped) return;
const delay = Math.min(30_000, 1_000 * 2 ** Math.min(retries++, 5));
setTimeout(connect, delay + Math.random() * 250);
});
}
connect();Las conexiones WebSocket requieren autenticación.
Lee cada mensaje
Cada mensaje incluye el par, el tipo, la hora de observación y el estado de frescura. Trata unavailable y stale como estados explícitos.
{
"type": "update",
"base": "USD",
"symbol": "JPY",
"rate": "154.792",
"effective_at": "2026-09-15T02:59:44Z",
"source": "live",
"source_type": "market",
"market_session": "open",
"derived": false,
"stale": false
}Cobertura
Solo puedes suscribirte a los pares de la tabla de cobertura actual. Los cruces requieren observaciones recientes de ambas patas.
AUD, CAD, CHF, EUR, GBP, JPY, MXN, NOK, NZD, PLN, SEK, SGD, USD, ZAR · 182 Pares compatibles
Las actualizaciones son observaciones indicativas. Comprueba el estado y la hora de observación.
Ver la cobertura actualLímites del plan
El número de conexiones y de pares por conexión depende del plan. Cada conexión aceptada consume una unidad de cuota mensual.
| Plan | Conexiones | Pares por conexión | Uso comercial |
|---|---|---|---|
| Free | 1 | 5 | No |
| Basic | 3 | 25 | Sí |
| Pro | 10 | 100 | Sí |
Cada conexión aceptada consume una unidad de cuota mensual.
Ver preciosUso comercial
Consulta el plan y las condiciones de uso comercial actuales antes de distribuir un producto que dependa del flujo.
Reconecta de forma segura
Tras una desconexión, espera antes de reconectar, autentica de nuevo, espera authenticated y vuelve a suscribirte. Nunca pongas la clave en una URL ni en JavaScript público.
Las actualizaciones que faltan siguen faltando; el flujo no inventa valores.
¿Puedo conectarme sin autenticación?
No. Las conexiones WebSocket requieren una clave API. La evaluación anónima está disponible mediante los endpoints REST compatibles.
¿Se transmite cada par de divisas?
No. La cobertura de WebSocket depende del par. Consulta la tabla y gestiona explícitamente las suscripciones no compatibles.