Blog
Desarrolladores·17 de octubre de 2026 · 8 min

Idempotencia en facturación electrónica: cómo no emitir dos veces la misma factura

Mandá una Idempotency-Key que identifique la venta: si reintentás con la misma clave en 24 horas, recibís la factura original y no se emite otra.

Idempotencia en facturación electrónica: cómo no emitir dos veces la misma factura

Respuesta corta: para no emitir dos veces la misma factura, cada emisión lleva la cabecera Idempotency-Key con un valor que identifique la venta (por ejemplo pedido-4471). Si tu sistema reintenta con la misma clave dentro de 24 horas, la API devuelve la factura que ya existe en vez de emitir otra. Si la reintentás mientras todavía se procesa, recibís 409 idempotency_in_progress.

Una factura duplicada no es un error menor: son dos comprobantes fiscales con su propio consecutivo, dos ingresos declarados y, normalmente, una nota de crédito para deshacer el segundo. Y casi nunca es culpa del usuario: es un reintento automático después de un corte de red.

El escenario que la idempotencia resuelve

  1. Tu sistema manda la factura.
  2. La API la recibe, la firma y responde.
  3. La respuesta no llega: se cayó la conexión, venció el timeout, se reinició el proceso.
  4. Tu sistema no sabe si se emitió, y reintenta.

Sin idempotencia, el paso 4 emite una segunda factura para la misma venta. Con idempotencia, el paso 4 recibe la respuesta del paso 2.

Cómo funciona en la API de Facturaencr

Los POST de emisión exigen la cabecera:

Idempotency-Key: pedido-2026-07-000123
SituaciónResultado
Misma clave, mismo cuerpoDevuelve el resultado original. No se emite de nuevo
Misma clave, cuerpo distinto409 idempotency_conflict
Misma clave, todavía procesándose409 idempotency_in_progress
Clave nuevaEmisión nueva

La ventana es de 24 horas.

La clave se toma antes de emitir

Apenas llega la petición, la clave queda reservada hasta que la emisión termina, bien o mal. Si en ese lapso entra otra petición con la misma clave, recibe:

{
  "error": "idempotency_in_progress",
  "message": "La Idempotency-Key \"pedido-4471\" está siendo procesada en este momento.",
  "retryAfterSeconds": 5
}

No es un fallo. Significa que ya hay una emisión en curso con esa clave. Esperá los segundos indicados y volvé a pedir con la misma clave: si el comprobante se emitió, recibís su respuesta original.

Qué pasa con la clave si la emisión falla

ResultadoLa clave…
2xxQueda tomada con la respuesta guardada. Reintentar devuelve esa respuesta
4xx / 5xxSe libera. Podés reintentar con la misma clave y el payload corregido
El proceso se cae a mitadQueda reservada unos 2 minutos y después se libera sola

Que un error libere la clave es a propósito: si un 400 por un CABYS mal puesto la dejara tomada, tendrías que inventar otra clave para cada corrección, y perderías la protección justo cuando más la necesitás. Los 429 y los 5xx son seguros de reintentar con la misma clave: si la petición no llegó a emitir, no consumió consecutivo.

Cómo elegir la clave: la parte que se hace mal

Hay dos formas de equivocarse, y van en sentidos opuestos.

Error 1: una clave nueva en cada intento. Generar un UUID aleatorio dentro del reintento anula la protección: cada intento parece una venta nueva. Es exactamente el caso que la idempotencia debía cubrir.

Error 2: una clave calculada del contenido. Usar un hash del cuerpo de la factura parece elegante, pero dos ventas legítimas pueden ser idénticas: el mismo cliente comprando lo mismo dos veces el mismo día. La segunda devuelve la primera —misma clave numérica, mismo consecutivo— y desde afuera parece que «el botón no emite». Lo vimos pasar en una integración real: la clave dura 24 horas, así que cualquier venta repetida en el día choca.

La regla correcta: la clave identifica la venta o el intento del usuario, no el contenido ni el reintento.

OrigenClave recomendada
Pedido de un e-commercepedido- + el id del pedido
Orden de un ERPorden- + número de orden
Venta en cajaUn id generado al iniciar la venta y guardado con ella
Botón «Emitir» en una pantallaUn id por clic, que se mantiene en los reintentos y se renueva solo cuando la emisión termina bien
Nota de crédito de un pedidonc-pedido- + id (no la misma clave de la factura)

Idempotencia del otro lado: tu webhook

La API también te entrega eventos por webhook, y una entrega puede llegar más de una vez por diseño (reintentos con backoff si tu endpoint falló). Tu handler tiene que ser idempotente: descartá repetidos con la cabecera X-Efactura-Delivery-Id o con la clave del comprobante, y no confiés en el orden de los eventos. Más en webhooks vs polling.

Lo que la idempotencia no cubre

  • Un comprobante rechazado. Si Hacienda lo rechaza, no se reintenta con la misma clave: se emite un comprobante nuevo que lo sustituye, con su propia clave de idempotencia. Ver qué hacer si Hacienda rechaza una factura.
  • Dos sistemas distintos emitiendo la misma venta. Si tu tienda y tu ERP facturan cada uno por su lado, la idempotencia no los conoce entre sí. Decidí un solo origen de facturación por venta.
  • Más de 24 horas. Pasada la ventana, la misma clave es una emisión nueva. Si tu cola puede reintentar días después, revisá primero tu propio registro de documentId.

Y si nuestro proceso se cae firmando

Si la plataforma se interrumpe mientras firma tu comprobante, lo termina sola con la misma clave numérica y el mismo consecutivo que ya había reservado. Recibís un webhook document.queued con "recuperado": true y el documento sigue su curso. No queda un salto en tu numeración y no tenés que hacer nada.

Preguntas frecuentes

¿La Idempotency-Key es obligatoria?

Sí, en los POST de emisión. Sin ella no hay forma de distinguir un reintento de una venta nueva.

¿Puedo usar el mismo número de pedido para la factura y la nota de crédito?

Usá claves distintas (pedido-4471 y nc-pedido-4471): son dos emisiones diferentes y con el mismo valor la segunda devolvería 409 idempotency_conflict por traer otro cuerpo.

¿Un 400 me hace perder la clave?

No. Un error libera la clave: corregí el payload y reintentá con la misma.

¿El 409 significa que se emitió dos veces?

No. idempotency_in_progress dice que la primera sigue en curso; idempotency_conflict dice que reusaste la clave con otro cuerpo. En ninguno de los dos casos se emitió un duplicado.

La API de Facturaencr exige Idempotency-Key en toda emisión justamente para que un corte de red no te cueste una factura duplicada. Los detalles están en la documentación, y si estás arrancando, en tu primera factura por API.

Empezá a emitir con la API

Sandbox gratis. Tus primeros 100 documentos sin costo. Pagás solo por lo que emitís.