Conceptos
Idempotencia
Una factura duplicada en SUNAT es un dolor de cabeza tributario. Idempotency-Key garantiza que un retry de red no genere dos documentos.
Por qué importa
Tu servicio emite un POST a /v1/documents. La red se cae justo cuando recibíamos la respuesta. Tu cliente HTTP reintenta. Sin idempotencia, acabas con dos facturas con números correlativos distintos por la misma operación — problema tributario y problema con tu cliente final.
Cómo funciona
Cada POST que cambia estado debe llevar header Idempotency-Key con un UUID v4 elegido por ti (cualquier string de 1 a 64 caracteres funciona, pero recomendamos UUID).
- La primera vez que recibimos esa key, ejecutamos la operación y guardamos la respuesta.
- Si llega una segunda petición con la misma key y el mismo body, devolvemos la respuesta guardada con header
Idempotent-Replayed: true. NO se crea un segundo documento. - Si llega con la misma key pero body distinto, devolvemos 409 Conflict (
idempotency_conflict). - Las claves se retienen 24 horas. Después se purgan y la key se puede reutilizar.
Genera la key ANTES del retry
Ejemplo
# Primera petición — crea el documento
curl -X POST https://api.fiscal-web.pe/v1/documents \
-H "Authorization: Bearer $FW_KEY" \
-H "Idempotency-Key: 8e1d4b1a-5e6f-4a3b-8c2e-1f0d9e8c7b6a" \
-d @factura.json
# Segunda petición con la MISMA Idempotency-Key — devuelve el mismo doc
curl -X POST https://api.fiscal-web.pe/v1/documents \
-H "Authorization: Bearer $FW_KEY" \
-H "Idempotency-Key: 8e1d4b1a-5e6f-4a3b-8c2e-1f0d9e8c7b6a" \
-d @factura.json
# < 200 OK + Idempotent-Replayed: trueLa segunda petición devuelve el mismo documento sin volverlo a emitir.
Endpoints afectados
Todos los POST que crean recursos cobrables o emiten ante SUNAT requieren Idempotency-Key:
POST /v1/documents— emisión.POST /v1/documents/:id/cancel— anulación.POST /v1/credentials— subida de certificado.
Errores comunes
- 422 con
idempotency_key_missing— olvidaste el header en un endpoint que lo requiere. - 409 con
idempotency_conflict— reutilizaste la key con un payload distinto dentro de la ventana de 24h.