Appearance
Errores
La API devuelve errores con un JSON estandarizado:
json
{
"error": "validation_failed",
"message": "email no puede estar en blanco",
"errors": { "email": ["no puede estar en blanco"] }
}errores un código estable que debes usar para tomar decisiones en código.messagees texto en español apto para mostrar al usuario final.errors(opcional, solo en422 validation_failed) trae los errores por campo.
Códigos por status HTTP
400 Bad Request
error | Cuándo |
|---|---|
invalid_id | El parámetro :id no es un ObjectId válido. |
401 Unauthorized
error | Cuándo |
|---|---|
invalid_key | El header Authorization falta, está mal formado, la key no existe, no matchea el digest, o fue revocada. Devolvemos el mismo error en todos esos casos para no filtrar información. |
403 Forbidden
error | Cuándo |
|---|---|
origin_not_allowed | El Origin/Referer no matchea con la lista de dominios permitidos del account. |
insufficient_scope | La key autenticada no tiene el scope que requiere ese endpoint. El campo required te dice cuál falta. |
module_not_enabled | El módulo opt-in que cubre ese endpoint no está activado para la empresa (p. ej. Facturación en /sales/:id/invoice). Se activa desde la aplicación, no por API. |
404 Not Found
error | Cuándo |
|---|---|
not_found | El recurso con ese :id no existe, o existe pero pertenece a otra empresa (deliberadamente devolvemos el mismo error para no filtrar IDs entre tenants). |
422 Unprocessable Entity
error | Cuándo |
|---|---|
validation_failed | El payload no pasa las validaciones del modelo. Mira errors para el detalle por campo. |
parameter_missing | El JSON no incluye la llave data o un campo obligatorio en data.<field>. |
idempotency_key_reused | El header Idempotency-Key ya se usó con un body diferente. Reusar la misma key requiere el MISMO body. |
not_supported_yet | El endpoint existe pero esta acción no está soportada en Fase 1 (ej. POST /automations). |
invalid_metadata | El metadata se salió de su forma: más de 50 claves, una clave de más de 40 bytes, un valor de más de 500 bytes, o un objeto/lista anidados. Ver metadata. |
period_locked | occurred_at cae en un mes que la contabilidad ya cerró. La llave no puede saltarse un cierre — la respuesta trae year y month. |
already_invoiced | La venta ya tiene CFDI timbrado. Para corregirlo, sustituye en vez de volver a emitir. |
sale_without_tax | La venta tiene conceptos sin IVA, que un CFDI no admite salvo exentos o tasa 0%. |
no_emitter | La empresa no tiene completos sus datos fiscales o sus sellos digitales (CSD). |
customer_no_rfc | El cliente de la venta no tiene RFC. Sin cliente, la venta se timbra a público en general. |
409 Conflict
error | Cuándo |
|---|---|
duplicate_reference | Un update intentó poner un metadata.external_ref que otro registro de la empresa ya tiene. En un create, esto no es un error: se devuelve 200 con el recurso que ya existía (ver idempotencia). |
413 Payload Too Large
error | Cuándo |
|---|---|
idempotency_body_too_large | Bodies > 100 KB no se pueden idempotency-key. Quita el header o mándalo en partes. |
426 Upgrade Required
error | Cuándo |
|---|---|
https_required | En producción solo aceptamos HTTPS. Cambia a https://. |
429 Too Many Requests
error | Cuándo |
|---|---|
rate_limited | Excediste el cap de 600 req/min para tu API key. Espera lo que indica el header Retry-After. |
Ver: Rate limiting.
Mejores prácticas
- Lee
error, nomessage:messagepuede cambiar de redacción;errores contrato estable. - No diferencies
401: nunca te diremos si una key existe pero está mal o si jamás existió. Trata cualquier401 invalid_keyigual: re-emite la key. - Reintenta con backoff exponencial solo en
429o5xx. Para4xxel reintento sin cambios no va a ayudar. - Usa
Idempotency-Keyen POST para evitar duplicados en reintentos. Ver Idempotencia.