Errores e idempotencia
Todos los errores de la API tienen la misma forma y un code estable. Tu sistema debe decidir por el code, nunca por el texto del message.
Formato
{
"code": "error.document.invalid",
"message": "El documento tiene campos inválidos",
"errors": [
{"field": "lines[0].quantity", "message": "Cantidad inválida: debe ser mayor que cero."},
{"field": "exchange_rate", "message": "Obligatoria cuando la moneda no es COP, y solo en ese caso: envía la tasa (pesos por unidad, la TRM o la pactada) y su fecha."}
],
"details": ["lines[0].quantity", "exchange_rate"],
"request_id": "01JC8Z6Q1N4V7R2T5X9B3D0F6H"
}code: identificador estable del error.message: texto para personas, en español por defecto o en inglés conAccept-Language: en.errors: en validaciones (400), cada campo con problemas:fieldes la ruta en el JSON que enviaste (p. ej.lines[0].quantity) ymessageexplica qué falla y cómo corregirlo.details: solo las rutas de esos campos (se conserva por compatibilidad; usaerrors).request_id: inclúyelo cuando nos escribas por soporte.
Códigos HTTP
| HTTP | Cuándo | Ejemplos de code |
|---|---|---|
400 | Datos inválidos. errors explica cada campo. | error.document.invaliderror.numbering.range_requirederror.bad_request |
401 | Falta la API key o no sirve. | error.missing_api_keyerror.invalid_api_keyerror.api_key.expired |
402 | En producción, la cuenta no tiene un plan activo (venció o se consumió sin renovación). No se crea el documento. | error.plan.inactive |
404 | No existe o pertenece a otra cuenta. | error.document.not_founderror.issuer.not_found |
409 | Choca con el estado actual. | error.numbering.unavailableerror.document.reference_not_acceptederror.document.not_acceptederror.document.not_correctable |
422 | Faltan datos para generar el documento. | error.document.incomplete |
Un documento que la DIAN rechaza no es un error HTTP: se crea bien y termina en estado rejected con los motivos.
Idempotencia con external_id
Al crear un documento envías tu propio external_id (máximo 128 caracteres): el número de pedido, de venta o de nómina. Es la clave de idempotencia de tu cuenta:
- La primera petición crea el documento y responde
202. - Repetirla con el mismo
external_iddevuelve el documento existente con200, sin crear otro ni consumir otro número, aunque las peticiones lleguen al mismo tiempo.
Consecutivos sin huecos
El número se asigna cuando el documento se envía a la DIAN, no al crearlo: mientras espera, number y full_number vienen en null. Si la DIAN lo rechaza, o si el envío falla sin llegar a la DIAN, el número lo toma el siguiente documento y no queda un hueco en tu numeración.
Corregir un documento rechazado
Un documento rejected trae los motivos en dian.errors. Corrige los datos y reenvíalo con PUT /documents/{id}, con el mismo cuerpo con el que lo creaste: vuelve a la fila con el mismo external_id y recibe el número que le toque. Un documento aceptado no se modifica (409 error.document.not_correctable): se corrige con una nota crédito o débito.
En dian.rules vienen los mismos motivos separados: rule (p. ej. FAJ44b), type (rejection rechaza el documento; notification es un aviso que no impide la aceptación), message de la DIAN y, cuando ya sabemos cómo se corrige, hint.