Manejo de errores
Cotizave usa códigos de respuesta HTTP estándar y un formato consistente de errores JSON para que puedas manejar fallos de forma predecible.
Formato de errores
Todos los errores devuelven un JSON con esta estructura:
{
"code": "string_identificador_del_error",
"message": "Descripción legible para humanos."
}Campos:
code: identificador estable del error en formatosnake_case. Úsalo en tu código para lógica condicional.message: descripción en inglés del problema, pensada para desarrolladores. No la muestres directamente al usuario final.
Códigos de estado HTTP
| Código | Significado | Ejemplos |
|---|---|---|
200 | OK | Request exitoso |
400 | Bad Request | Parámetros inválidos o mal formateados |
401 | Unauthorized | API Key faltante o inválida |
403 | Forbidden | Plan insuficiente, key de ambiente incorrecto |
404 | Not Found | Recurso inexistente (ej: market desconocido) |
422 | Unprocessable Entity | Parámetros válidos en formato pero lógicamente incorrectos |
429 | Too Many Requests | Rate limit excedido |
500 | Internal Server Error | Error interno de Cotizave |
502 | Bad Gateway | Problema con una fuente upstream |
503 | Service Unavailable | Mantenimiento o sobrecarga temporal |
Errores comunes
400 Bad Request
Request mal formateado o con parámetros inválidos.
{
"code": "invalid_parameter",
"message": "Parameter 'from' must be one of: USD, EUR."
}Cómo responder: revisa los parámetros que estás enviando. Probablemente un typo, un valor no soportado o un formato incorrecto.
401 Unauthorized
Problema con la autenticación.
{
"code": "unauthorized",
"message": "Missing or invalid API key."
}Posibles code específicos:
missing_api_key: no incluiste el headerX-API-Keyinvalid_api_key_format: el formato de la key es incorrecto (no empieza connd-)api_key_not_found: la key no existe o fue revocadaapi_key_wrong_brand: la key pertenece a otro producto (ej: Normadata)api_key_revoked: la key fue revocada por el usuario o por nosotros
Cómo responder: verifica tu API Key. Si fue revocada, crea una nueva.
403 Forbidden
La autenticación es válida pero no tienes permisos para este endpoint.
{
"code": "plan_insufficient",
"message": "This endpoint requires a paid plan. Current plan: free."
}Posibles code específicos:
plan_insufficient: tu Plan no incluye este endpointfeature_disabled: la feature fue deshabilitada para tu Cuentaregion_blocked: acceso desde tu IP bloqueado por razones de compliance
Cómo responder: haz upgrade del Plan si necesitas el endpoint, o usa una funcionalidad equivalente disponible en tu Plan actual.
404 Not Found
El recurso solicitado no existe.
{
"code": "market_not_found",
"message": "Market 'xyz' not found."
}Cómo responder: verifica el nombre del market. Consulta la lista completa de markets disponibles en la documentación del endpoint.
422 Unprocessable Entity
Los parámetros son válidos en formato pero no tienen sentido lógico.
{
"code": "invalid_amount",
"message": "Amount must be greater than 0."
}Cómo responder: revisa la lógica de tu request.
429 Too Many Requests
Rate limit excedido.
{
"code": "rate_limit_exceeded",
"message": "Monthly quota exceeded."
}Headers relevantes:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetRetry-After
Posibles code específicos:
rate_limit_exceeded: cuota mensual agotadaburst_rate_limit_exceeded: demasiados requests en poco tiempo
Cómo responder:
- Respeta el header
Retry-After(valor en segundos) - Implementa backoff exponencial
- Considera hacer upgrade del Plan si es recurrente
500 Internal Server Error
Error inesperado del lado de Cotizave. No es tu culpa.
{
"code": "internal_error",
"message": "An unexpected error occurred. Please try again."
}Cómo responder:
- Implementa retry con backoff exponencial
- Si persiste por más de unos minutos, revisa /status
- Si el status page dice “operational” pero sigues viendo errores, contáctanos en hello@cotizave.com
502 Bad Gateway
Problema con una fuente upstream. Por ejemplo, si Binance o el sitio del BCV están caídos.
{
"code": "upstream_error",
"message": "Upstream source 'binance' is currently unavailable."
}Cómo responder: si pides una market específica que está caída, prueba con otra o usa /v1/fx/rates (devuelve las que sí están disponibles).
503 Service Unavailable
Servicio temporalmente no disponible. Mantenimiento planificado o sobrecarga.
{
"code": "service_unavailable",
"message": "Service is temporarily unavailable. Please try again shortly."
}Cómo responder: retry con el delay sugerido.
Patrón recomendado: retry con backoff exponencial
Para manejar errores transitorios (5xx, 429 con Retry-After):
async function fetchWithRetry(url, options, maxRetries = 5) {
let lastError
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options)
// Éxito
if (response.ok) {
return await response.json()
}
// Errores que no tiene sentido retryar
if (response.status === 401 || response.status === 403 || response.status === 404) {
throw new Error(`Non-retryable: ${response.status}`)
}
// Rate limit: respetar Retry-After
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60')
await sleep(retryAfter * 1000)
continue
}
// Errores retriables (5xx)
if (response.status >= 500) {
const delay = Math.min(1000 * Math.pow(2, attempt), 30000) // max 30s
await sleep(delay)
continue
}
// Otros errores
throw new Error(`HTTP ${response.status}`)
} catch (err) {
lastError = err
if (attempt === maxRetries - 1) throw err
const delay = Math.min(1000 * Math.pow(2, attempt), 30000)
await sleep(delay)
}
}
throw lastError
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}Buenas prácticas:
- No retries errores 4xx (excepto
429). Si la request es inválida, va a seguir siendo inválida. - Siempre pon un límite máximo de reintentos (5 es razonable).
- Usa jitter (un valor aleatorio pequeño agregado al delay) para evitar que múltiples clientes retryen al mismo tiempo.
- Logea los retries para poder diagnosticar problemas recurrentes.
Verificación de salud
Si quieres verificar que la API está operativa antes de hacer requests críticos, puedes usar el endpoint de healthcheck:
curl https://api.cotizave.com/healthRespuesta normal:
{
"status": "ok",
"timestamp": "2026-04-08T17:30:00Z",
"version": "1.0.0"
}Este endpoint no requiere autenticación y no cuenta contra tu cuota.
Reporte de bugs
Si encuentras un comportamiento que parece un bug (response con schema roto, código de error inconsistente, datos corruptos), repórtalo a hello@cotizave.com con:
- Request exacto que enviaste (sin la API Key)
- Response recibido completo
- Timestamp aproximado del incidente
- Tu email de Cuenta
Respondemos dentro de 24 horas hábiles.