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

El generador de UUID debe correr una sola vez por intento lógico, no dentro del retry. Si generas un UUID nuevo en cada retry, pierdes la idempotencia.

Ejemplo

Reintento idempotente
# 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: true

La 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.