Errores y límites de solicitudes
Todos los endpoints informan de los fallos con la misma estructura, con un código legible por máquina y un ID de solicitud.
Respuesta de error
Una llamada fallida devuelve success: false. code es estable y está pensado para programas, error es un mensaje breve en inglés pensado para personas, y request_id identifica la llamada en nuestros registros. param indica el parámetro causante cuando el problema está en los datos de entrada.
Ejemplos reales
Estas son respuestas en vivo, obtenidas de la API al generar esta página.
{
"success": false,
"error": "coin required",
"code": "INVALID_PARAM",
"request_id": "cb-mwefuknz-6c036f864c"
}{
"success": false,
"code": "NOT_FOUND",
"error": "unknown endpoint: GET /api/this-endpoint-does-not-exist",
"request_id": "cb-mwefuknz-7768c7f02d"
}Códigos de error
| Código | HTTP | Significado | Qué hacer |
|---|---|---|---|
| INVALID_PARAM | 400 | Falta un parámetro obligatorio o un valor no se acepta. `param` indica el nombre del parámetro cuando se conoce. | No reintente sin cambios; corrija la solicitud. |
| UNAUTHORIZED | 401 | Se envió la cabecera `CB-API-KEY`, pero la clave es desconocida o está revocada. Los datos públicos no necesitan clave: elimine la cabecera o use una clave válida. | No reintente sin cambios. |
| FORBIDDEN | 403 | La ruta no forma parte de la API pública (interna o solo para cuentas). | No reintente. |
| NOT_FOUND | 404 | Ruta desconocida, o la moneda / el exchange / el fondo solicitado no existe. | No reintente; compruebe la ruta y los identificadores en el catálogo. |
| RATE_LIMITED | 429 | Más solicitudes que el límite por minuto. `Retry-After` indica los segundos de espera. | Espere el tiempo de `Retry-After` y después reintente con espera progresiva. |
| INTERNAL | 500 | Error inesperado del servidor. El mensaje es genérico por diseño; cite `request_id` al informar del error. | Reintente una vez tras unos segundos; si persiste, infórmelo con el ID de solicitud. |
| UPSTREAM_FAILED | 503 | La fuente de datos de este endpoint no respondió a tiempo. No se devuelven cifras desactualizadas ni sustitutas en su lugar. | Reintente con espera progresiva; consulte la página de estado. |
| UNAVAILABLE | 501 / 503 | El conjunto de datos no está listo temporalmente (calentamiento de la caché) o el endpoint aún no tiene una fuente pública lícita. | Reintente más tarde; el catálogo marca los endpoints que no están disponibles por diseño. |
| REQUEST_FAILED | 200 | Algunos endpoints antiguos responden HTTP 200 con `success: false`. Compruebe siempre `success`, no solo el estado HTTP. | Depende del mensaje; trátelo como una solicitud fallida. |
ID de solicitud
Cada respuesta incluye una cabecera X-Request-Id. Las respuestas fallidas la repiten en el cuerpo como request_id. Las respuestas servidas desde la caché de borde de corta duración repiten el ID de la solicitud que las generó, de modo que dos ID idénticos en llamadas consecutivas indican que se recibió una copia en caché.
Límites de solicitudes
Los límites se aplican por minuto: por dirección IP en las llamadas anónimas y por clave cuando se envía una cabecera CB-API-KEY válida. El límite es de 1200 solicitudes por minuto. Las solicitudes de iconos bajo /api/coin-icon no se contabilizan.
Cabeceras del límite de solicitudes
| Nombre | Descripción |
|---|---|
| X-Request-Id | Identificador de esta solicitud. Cítelo en los informes de errores. |
| X-RateLimit-Limit | Solicitudes permitidas en la ventana actual de un minuto. |
| X-RateLimit-Remaining | Solicitudes restantes en la ventana actual. |
| X-RateLimit-Reset | Hora Unix, en segundos, en la que se reinicia la ventana. |
| Retry-After | Se envía con HTTP 429: segundos que hay que esperar antes de reintentar. |
| X-Cache | HIT, STALE o MISS de la caché de respuestas del servidor. |
Cuando se supera el límite
La API responde HTTP 429 con el código RATE_LIMITED. Espere el número de segundos indicado en Retry-After y reintente. Consultar con más frecuencia que el TTL de caché de un endpoint devuelve la misma respuesta en caché, así que ajuste el intervalo de consulta al TTL indicado en cada página de referencia.
Reintentos con espera progresiva
async function getJson(url, tries = 4) {
for (let i = 0; i < tries; i++) {
const res = await fetch(url);
if (res.status === 429 || res.status >= 500) {
const wait = Number(res.headers.get("Retry-After")) || 2 ** i;
await new Promise((r) => setTimeout(r, wait * 1000));
continue;
}
const body = await res.json();
if (body.success === false) {
throw new Error(body.code + ": " + body.error + " (" + body.request_id + ")");
}
return body;
}
throw new Error("gave up after " + tries + " attempts");
}La ausencia de datos no es un error
Cuando los parámetros son válidos pero no existe una fuente pública lícita para el dato, la llamada se completa con HTTP 200: los campos de valor son null, meta.quality es UNAVAILABLE y coverage.unavailable indica el motivo. Represéntelo con un guion. No lo convierta en 0.
Datos desactualizados
Si un recolector se retrasa, los endpoints siguen sirviendo los últimos valores almacenados con meta.is_stale: true hasta que superan la ventana de uso; a partir de ahí se retiran de los agregados y se listan en coverage.stale_excluded.