# Idempotencia y reintentos

> clientEmissionId es la clave - qué devuelve exactamente un retry

## La clave de idempotencia

Cada CFE lleva un `clientEmissionId` (obligatorio) elegido por el integrador, y
es **único** por:

```
company + branchOffice + cfeType + clientEmissionId
```

La unicidad vale también para requests simultáneos: dos envíos concurrentes con
la misma clave no generan dos CFE.

## Qué devuelve un reintento con el mismo `clientEmissionId`

El gateway **no emite un segundo CFE**: devuelve el original. El objeto de
error trae `code: "DUPLICATED_KEY"` y un campo `firstCfeResponse` con los datos
del comprobante original:

```json
{
  "code": "DUPLICATED_KEY",
  "status": "FAIL",
  "firstCfeResponse": {
    "id": "6a7121a37698d7c0ab3f1b51",
    "clientEmissionId": "009993ca34f74e0de3106aba89f818b3",
    "serie": "A",
    "nro": 3503,
    "type": "111",
    "caeNumber": 90120000538,
    "caeSerie": "A",
    "caeRange": { "from": 1, "to": 10000 },
    "caeExpirationDate": "2050-01-01T00:00:00.000Z",
    "total": "3050.00",
    "emitionDate": "2026-08-03T20:17:46.000-03:00",
    "sentXmlHash": "mghK5nJZkGskjJUkRv8EnG+U8xa1vs1tROJsIqDXBMk=",
    "securityCode": "mghK5n",
    "bulkCfesManager": null,
    "TmstFirma": "2026-08-03T20:17:46-03:00",
    "qrUrl": "https://.../consultaQR/cfe?..."
  }
}
```

Es decir: un retry con el mismo id es **seguro** y te devuelve los
identificadores del CFE original (serie, número, CAE, hash, QR) - podés
persistirlos igual que en el éxito.

`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

1. **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 en `firstCfeResponse`.
2. **Nunca reintentar con un id nuevo.** Un `clientEmissionId` distinto es una
   emisión nueva: genera un **segundo CFE fiscalmente válido** (duplicado real
   ante DGI).
3. El id es único por empresa + sucursal + tipo de CFE; el mismo id con otro
   `cfeType` es otro comprobante.

## La excepción: CFE recibido sin CAE disponible

Hay un caso donde el mismo `clientEmissionId` **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 registra como `DELETED_MISSING_CAE` y **con otro id**,
`<tuId>-DELETED-MISSING-CAE-<n>`. Eso deja libre tu id.

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.
