Idempotencia
Cómo usar el encabezado Idempotency-Key para que un reintento de una emisión de documentos no genere un segundo documento ante la DIAN
Emitir un documento ante la DIAN es una operación irreversible: una vez aceptado, deshacerlo requiere emitir una anulación. Por eso un reintento del cliente —tras un timeout, un corte de red o un error en tu propio código— no debería producir una segunda emisión.
El encabezado Idempotency-Key te permite declarar que dos peticiones son la misma operación lógica. Cuando lo envías, la API garantiza que la operación se ejecute a lo sumo una vez para esa llave.
DisponibilidadEl encabezado está disponible en todos los endpoints de emisión de documentos. El encabezado es opcional: si no lo envías, el comportamiento de la API no cambia en absoluto.
| Documento | Endpoints |
|---|---|
| Factura de venta | POST /invoices |
| Nota crédito | POST /credit-notes |
| Nota débito | POST /debit-notes |
| Documento soporte | POST /support-documents |
| Nota de ajuste de documento soporte | POST /adjustment-note-support-documents |
| Documento equivalente (POS) | POST /equivalent-documents/pos |
| Nota de ajuste de documento equivalente | POST /adjustment-note-equivalent-documents |
| Evento | POST /events, POST /events/from-xml, POST /events/from-cufe |
| Nómina electrónica | POST /payrolls, POST /payrolls/{id}/replace, POST /payrolls/{id}/cancel |
La llave identifica una operación lógica dentro de un tipo de documento: la misma llave usada en POST /invoices y en POST /credit-notes son dos operaciones independientes. Los tres endpoints de eventos, en cambio, comparten el mismo espacio: son tres formatos de entrada para la misma operación lógica, así que reutilizar una llave entre ellos con un cuerpo distinto devuelve 422.
Cómo usarlo
- Genera un UUID v4 por cada operación lógica. El formato es obligatorio: la llave debe ser un UUID versión 4 en forma canónica con guiones (
550e8400-e29b-41d4-a716-446655440000). Cualquier otro valor recibe400. Se acepta en mayúsculas o minúsculas. - Guárdala junto con la operación antes de enviar la petición, en el mismo lugar donde registras que ibas a emitir ese documento.
- Reutiliza exactamente la misma llave en todos los reintentos de esa operación. Una llave nueva significa una operación nueva y, por lo tanto, un documento nuevo.
Por qué se exige UUID v4 y no cualquier cadenaUna llave derivada de tus datos (
factura-2026-02-cliente-1234) parece única hasta el día en que la vuelves a generar para una operación que sí es nueva. Ahí recibirías la respuesta de la anterior en lugar de una emisión — y el síntoma sería un documento faltante, mucho más difícil de detectar que uno duplicado. Un v4 son 122 bits aleatorios: no se repite por accidente.
La mayoría de lenguajes lo traen de fábrica: crypto.randomUUID() en Node y navegadores, uuid.uuid4() en Python, UUID.randomUUID() en Java, Str::uuid() en Laravel.
curl -X POST https://api.alegra.com/e-provider/col/invoices \
-H "Authorization: Basic <tu-token>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{ "number": 1, "resolution": { ... }, "company": { ... }, "customer": { ... }, "items": [ ... ] }'Qué responde la API
| Situación | Respuesta | Qué hacer |
|---|---|---|
| Primera ejecución | La respuesta normal del endpoint | Nada especial |
| Reintento de una operación ya resuelta | El mismo código de estado y cuerpo de la primera ejecución, con el encabezado Idempotent-Replayed: true | Tratarla como la respuesta original |
| Otra petición con la misma llave sigue en curso | 409 con código IDEMPOTENCY_REQUEST_IN_PROGRESS | Reintentar en unos segundos con la misma llave |
| La llave se reutilizó con un cuerpo diferente | 422 con código IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD | Revisar tu integración: usa una llave nueva si de verdad es otra operación |
| La llave está mal formada | 400 con código IDEMPOTENCY_KEY_INVALID | Corregir el formato de la llave |
| No fue posible establecer el resultado de la petición original | 409 con código IDEMPOTENCY_OUTCOME_INDETERMINATE | Consultar el estado del documento con el endpoint GET o el webhook antes de reintentar |
Cómo se compara el cuerpo de la petición
La API calcula una huella del cuerpo enviado. El orden de las propiedades de un objeto y la representación numérica no la afectan: {"a":1,"b":2} y {"b":2,"a":1} son equivalentes, igual que 100.00 y 100.
En cambio el orden de los elementos de un arreglo sí importa, porque en los documentos el orden de los ítems, devengados o pagos tiene significado. Reordenar un arreglo produce una huella distinta y, por lo tanto, un 422.
El caso que este mecanismo evitaEnviar el mismo documento dos veces con números consecutivos distintos produce dos documentos ante la DIAN, porque para la API son dos operaciones diferentes. Si ambas peticiones llevan la misma
Idempotency-Key, la segunda recibe422y no se emite nada.
La respuesta almacenada es la de la petición original
La respuesta que se replica queda congelada en el momento de la primera ejecución. Si esa primera respuesta reportó WAITING_RESPONSE y el documento fue aceptado más tarde, un reintento seguirá reportando WAITING_RESPONSE: el encabezado Idempotent-Replayed: true es la señal de que estás viendo un resultado histórico.
Para conocer el estado actual de un documento usa siempre el endpoint GET correspondiente o el webhook de emisión, nunca un reintento.
La única excepción son las URLs de archivos: se firman de nuevo en cada respuesta, de modo que un reintento días después devuelve un enlace vigente y no uno vencido.
Si la generación de un enlace falla, el campo correspondiente dentro de files llega como null — nunca como un error: el documento sí fue emitido, y el enlace puede obtenerse consultando el documento con el endpoint GET correspondiente. Esto aplica tanto a las respuestas idempotentes como a las peticiones sin Idempotency-Key.
Vigencia
Las llaves se conservan 7 días. Pasado ese plazo, la misma llave vuelve a considerarse una operación nueva.
Updated about 1 month ago
