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:
Campos:
code: identificador estable en formatosnake_case. Úsalo en tu código para lógica condicional.message: descripción 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.
Posibles code específicos:
invalid_format: el valor de un campo tiene formato incorrecto. Incluye el campo enfield.missing_field: falta un campo requerido. Incluye el campo enfield.validation_failed: validación de negocio fallida.
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.
Posibles code específicos:
invalid_api_key: el headerX-API-Keyfalta, tiene formato incorrecto (no empieza conctz_live_, CRC32 inválido) o la key no existe en la base de datoskey_revoked: la key fue revocada explícitamente desde el dashboard
Cómo responder: verifica tu API Key. Si fue revocada, crea una nueva.
402 Payment Required
Tu autenticación es correcta, pero tu plan no incluye lo que pediste. No es un error técnico: es un límite comercial, y se resuelve subiendo de plan, no reintentando.
details.feature te dice exactamente qué falta y details.current_plan en qué plan estás, para que puedas mostrar el mensaje correcto sin adivinar.
No consume cuota. Un 402 no cuenta como request facturado, así que probar una funcionalidad que no tienes no te cuesta llamadas.
Cómo responder: no reintentes — el resultado será el mismo. Ofrece el upgrade al usuario o quita el parámetro que activó la funcionalidad.
403 Forbidden
La autenticación es válida pero no tienes acceso al recurso.
Posibles code específicos:
forbidden: acceso denegado al recursoaccount_inactive: la cuenta está suspendida o baneadanot_available: el producto o endpoint no está disponible para tu plan o país
Cómo responder: verifica el estado de tu cuenta en el dashboard.
404 Not Found
El recurso solicitado no existe.
Cómo responder: verifica el path, el market o el ID del recurso.
406 Not Acceptable
El formato que pediste existe, pero no puede representar esa respuesta en concreto. Hoy solo ocurre al pedir format=csv en un endpoint que devuelve dos colecciones: un CSV es una tabla y no hay una sola tabla que las contenga. El mensaje nombra cuáles son.
Por qué 406 y no 400: tu petición es válida y el endpoint también. Lo que no existe es una representación aceptable de lo que pediste, que es justamente lo que significa Not Acceptable. Un 400 te haría buscar un error de escritura que no está.
Cómo responder: usa format=xml o format=json en ese endpoint. Ver Formatos de respuesta.
422 Unprocessable Entity
Los parámetros son válidos en formato pero no tienen sentido lógico (ej: spread contra un market no disponible).
Posibles code específicos (422):
reference_unavailable: la tasa BCV no está disponible (solo en/v1/fx/spread)compared_unavailable: la tasa del market comparado no está disponible (solo en/v1/fx/spread)
Cómo responder: reintenta en unos minutos.
429 Too Many Requests
Rate limit excedido. El campo details.kind distingue los dos casos, que se resuelven de forma opuesta.
kind: "burst" significa que pediste demasiado rápido — tu cuota mensual sigue intacta y se resuelve espaciando los pedidos. kind: "monthly" significa que agotaste el plan; ahí details trae resets_at en lugar de retry_after_ms.
Headers relevantes: X-RateLimit-Scope, Retry-After, X-RateLimit-Retry-After-Ms, X-RateLimit-Limit-Second, X-RateLimit-Burst, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Todos documentados en Rate limits.
Cómo responder: respeta Retry-After (o X-RateLimit-Retry-After-Ms si quieres precisión), agrega un jitter aleatorio para no reintentar sincronizado con otros clientes, y usa details.kind para decidir si el arreglo es en tu código o un upgrade de plan.
500 Internal Server Error
Error inesperado del lado de Cotizave. No es tu culpa.
Cómo responder: retry con backoff. Si persiste, revisa la página de status o escríbenos a support@cotizave.com.
502 Bad Gateway
Problema con una fuente upstream (por ejemplo, si Binance o el BCV están caídos). El backend retorna internal_error con HTTP 500 en estos casos, o service_unavailable con 503 si el servicio de datos no está disponible.
Cómo responder: retry con backoff. Si el error es persistente, revisa la página de status.
503 Service Unavailable
Servicio temporalmente no disponible. Mantenimiento planificado o sobrecarga.
Cómo responder: retry con el delay sugerido. Si persiste, revisa la página de status.
Reporte de bugs
Si encuentras un comportamiento que parece un bug, repórtalo a support@cotizave.com con:
- Request exacto que enviaste (sin la API Key)
- Response recibido completo
- Timestamp aproximado del incidente
- Tu email de Cuenta
Respondemos en 2-3 días hábiles en los planes de pago; en la familia Escala, tu ticket entra primero. El soporte cubre errores del Servicio — no la depuración de tu aplicación. Alcance completo en la Política de Disponibilidad §11.