La clave de idempotencia
Cada CFE lleva unclientEmissionId (obligatorio) elegido por el integrador. El
gateway tiene un índice único sobre:
Qué devuelve un reintento con el mismo clientEmissionId
Verificado en código: el gateway
detecta la colisión, no emite un segundo CFE, busca el CFE original por
company + branchOffice + cfeType + clientEmissionId y lo devuelve. El objeto de
error trae code: "DUPLICATED_KEY" y un campo firstCfeResponse con los datos
del comprobante original:
firstCfeResponse trae dos campos que el éxito no trae: bulkCfesManager, que
identifica el envío masivo si el CFE original vino por lote y es null si no, y
TmstFirma, la marca de tiempo de la firma.
Reglas para el integrador
- Reintentar con el mismo
clientEmissionId. Ante timeout o error de red, reenviar con el mismo id: no se crea un segundo comprobante y recibís el original enfirstCfeResponse. - Nunca reintentar con un id nuevo. Un
clientEmissionIddistinto es una emisión nueva: genera un segundo CFE fiscalmente válido (duplicado real ante DGI). - El id es único por empresa + sucursal + tipo de CFE; el mismo id con otro
cfeTypees otro comprobante.
La excepción: CFE recibido sin CAE disponible
Hay un caso donde el mismoclientEmissionId sí se puede volver a usar para
emitir de verdad, y conviene conocerlo porque contradice la regla de arriba.
Si el CFE llega y la empresa no tiene un CAE disponible para ese tipo, el gateway
no lo emite: lo guarda marcado como DELETED_MISSING_CAE y le renombra el id
a <tuId>-DELETED-MISSING-CAE-<n>. Eso libera tu id del índice único.
Consecuencia práctica: cuando se cargue el CAE que faltaba, reenviar el mismo
clientEmissionId emite el comprobante, no devuelve un DUPLICATED_KEY. Es
el comportamiento deseado, y es la razón por la que un DGI_MISSING_CAE no es un
error terminal: se resuelve cargando el CAE y reintentando igual que un timeout.
Lo que no cambia: si el CFE sí se emitió, el id queda tomado para siempre.
Verificado en el código del gateway: el índice único, el manejo del
DUPLICATED_KEY, la construcción de firstCfeResponse y el renombrado por CAE
faltante. No se reprodujo un retry en vivo porque requiere una emisión real.