Errores
La API tiene dos familias de endpoints y, honestamente, dos sobres de error — uno por familia. Identifica cuál estás consumiendo por el recurso: los endpoints fiscales (
/invoices
,
/purchases
en escritura) y la autenticación usan un objeto
error
; los recursos JSON:API usan la lista
errors
del estándar.
El sobre de los endpoints fiscales#
{"error": {"code", "message"}}
— el
code
es estable y programable; el
message
es para humanos, en español. Cuando la falla es de validación se suma
errors
: un mapa de campo → lista de mensajes, con rutas como
lines[0].unit_price
.
| HTTP | code |
Cuándo |
|---|---|---|
| 401 | unauthorized | Llave ausente, inválida o revocada — siempre el mismo 401. |
| 403 | forbidden |
Llave válida sin la capacidad
accounting_api
(plan Empresa).
|
| 404 | not_found | El registro no existe, no es del libro de la llave o no es de producción. |
| 404 | not_ready |
El comprobante aún no tiene XML (
GET /invoices/:id/xml
).
|
| 409 | in_progress |
Una operación con el mismo
external_ref
está en curso; reintenta en unos segundos.
|
| 422 | validation_failed |
El cuerpo no pasó la validación;
errors
trae los mensajes por campo.
|
| 422 | emisor_not_configured | Falta configurar el emisor (RUC, establecimiento, firma) en Contabilidad → Emisor. |
| 422 | book_not_configured |
La llave aún no tiene libro contable configurado (
POST /purchases
).
|
| 422 | withholding_failed |
La retención no pudo emitirse (
POST /purchases/:id/withhold
).
|
| 422 | invalid |
El motor rechazó la operación;
message
resume las causas.
|
| 429 | rate_limited |
Límite de solicitudes excedido; espera lo que indique
Retry-After
.
|
El sobre JSON:API#
Los recursos JSON:API responden la lista
errors
del estándar: cada elemento trae
status
,
code
,
title
,
detail
y un
source.pointer
hacia el atributo culpable. Un cuerpo que no cumple el esquema (un atributo no aceptado, un tipo equivocado) responde
400
; una validación del recurso,
422
.
La diferencia es deliberada y está aquí documentada en lugar de disimulada: los endpoints fiscales conservan su contrato exacto y los recursos generados hablan el estándar. Maneja ambos sobres por el
status
HTTP primero y el código después.
{
"error": {
"code": "validation_failed",
"message": "Revisa los datos enviados."
},
"errors": {
"customer.identification": [
"Ingresa la identificación (RUC/cédula) del cliente."
],
"lines[0].unit_price": [
"El precio unitario debe ser un número."
]
}
}
{
"errors": [
{
"status": "422",
"code": "invalid_attribute",
"title": "Invalid Attribute",
"detail": "url: la URL del webhook debe ser https",
"source": { "pointer": "/data/attributes/url" }
}
]
}