← Volver a docs
API / Errores

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:

error schema
{ "code": "string_identificador_del_error", "message": "Descripción legible del problema." }

Campos:

  • code: identificador estable en formato snake_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ódigoSignificadoEjemplos
200OKRequest exitoso
400Bad RequestParámetros inválidos o mal formateados
401UnauthorizedAPI Key faltante o inválida
403ForbiddenPlan insuficiente, key de ambiente incorrecto
404Not FoundRecurso inexistente (ej: market desconocido)
422Unprocessable EntityParámetros válidos en formato pero lógicamente incorrectos
429Too Many RequestsRate limit excedido
500Internal Server ErrorError interno de Cotizave
502Bad GatewayProblema con una fuente upstream
503Service UnavailableMantenimiento o sobrecarga temporal

Errores comunes

400 Bad Request

Request mal formateado o con parámetros inválidos.

response
{ "code": "invalid_format", "message": "Amount must be a number.", "field": "amount" }

Posibles code específicos:

  • invalid_format: el valor de un campo tiene formato incorrecto. Incluye el campo en field.
  • missing_field: falta un campo requerido. Incluye el campo en field.
  • 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.

response
{ "code": "invalid_api_key", "message": "API key is missing, invalid, or revoked." }

Posibles code específicos:

  • invalid_api_key: el header X-API-Key falta, tiene formato incorrecto (no empieza con ctz_live_, CRC32 inválido) o la key no existe en la base de datos
  • key_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.

response
{ "code": "feature_not_in_plan", "message": "This feature ('response_formats') requires a plan upgrade.", "details": { "feature": "response_formats", "current_plan": "free" } }

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.

response
{ "code": "forbidden", "message": "Access denied." }

Posibles code específicos:

  • forbidden: acceso denegado al recurso
  • account_inactive: la cuenta está suspendida o baneada
  • not_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.

response
{ "code": "resource_not_found", "message": "The requested resource was not found." }

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.

response
{ "code": "format_not_available", "field": "format", "message": "This endpoint returns 2 collections (alternatives, skipped) and cannot be flattened to a single CSV table. Use format=xml or format=json." }

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).

response
{ "code": "reference_unavailable", "message": "Reference rate (BCV) is not available right now." }

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.

response
{ "code": "rate_limit_exceeded", "message": "Rate limit reached (25 req/burst, 10 req/seg sostenido). Retry in 1s.", "details": { "kind": "burst", "retry_after": 1, "retry_after_ms": 33 } }

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.

response
{ "code": "internal_error", "message": "Ocurrió un error inesperado. Intenta de nuevo." }

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.

response
{ "code": "internal_error", "message": "An unexpected error occurred." }

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.

response
{ "code": "service_unavailable", "message": "Servicio temporalmente no disponible. Intenta de nuevo en unos momentos." }

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.