> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fire.rest/llms.txt
> Use this file to discover all available pages before exploring further.

# Ejemplos reales

> Peticiones y respuestas capturadas de una integración en funcionamiento — éxito y error, tal como viajaron.

Nada de esto está inventado: son llamadas reales entre FIRE y un proveedor fiscal en
funcionamiento, con los identificadores cambiados. Sirven para contrastar una
implementación contra algo que ya funciona, en vez de contra una descripción.

## Numerar una venta

El request es **el mismo para los dos países** —mismos campos, mismo orden—; lo que cambia es
qué usa cada proveedor y qué devuelve en `document`. Acá van los cuerpos recortados a lo que
hace falta para leer el ejemplo; el request completo, campo por campo, está en el
[contrato](/es/fiscal-providers/contract#3-request).

<Tabs>
  <Tab title="Ecuador (EC) — SRI">
    ### Lo que enviamos

    ```json theme={null}
    POST {baseUrl}/api/v1/fiscal/ec/prekeys
    x-api-key: ••••

    {
      "country": "EC",
      "operation": "INVOICE",
      "businessDayDate": "2026-08-13",
      "createdAt": "2026-08-13T20:41:05.512Z",
      "orderCode": "E2E-NUM-B-1786636044723",
      "store": {
        "code": "K004",
        "storeFiscalConfig": {
          "govIdType": "RUC",
          "govIdNumber": "1791415132001",
          "company": {
            "govIdType": "RUC",
            "govIdNumber": "1791415132001",
            "legalName": "INT FOOD SERVICES CORP S.A.",
            "tradeName": "KFC"
          },
          "metadata": {}
        }
      },
      "device": { "uid": "52CAEA5A18D9B75F", "name": "KIOSK", "platform": "android" },
      "client": {
        "name": "CONSUMIDOR",
        "lastName": "FINAL",
        "govIdType": "FINAL_CONSUMER",
        "govIdNumber": "00000000000"
      },
      "totals": [
        {
          "currencyCode": "USD",
          "total": "100000",
          "subtotalWithoutTaxes": "87000",
          "taxValue": "13000",
          "taxes": [{ "name": "IVA", "base": "87000", "rate": "0.15", "amount": "13000" }]
        }
      ],
      "metadata": {}
    }
    ```

    `storeFiscalConfig.metadata` va vacío: en Ecuador el establecimiento y el punto de emisión
    los resolvés vos contra tu catálogo, a partir de `store.code` y `device.uid`.

    ### Lo que devolvió el proveedor

    ```json theme={null}
    HTTP 200

    {
      "status": "INVOICED",
      "country": "EC",
      "orderCode": "E2E-NUM-B-1786636044723",
      "reused": false,
      "retryable": false,
      "authorizationMode": "ONLINE",
      "issuedAt": "2026-08-13T15:47:26.057337855Z",
      "document": {
        "numeroComprobante": "005-004-000000052",
        "claveAcceso": "1308202601000000000000110050040000000521234567811",
        "establecimiento": "005",
        "puntoEmision": "004",
        "secuencial": "000000052",
        "ambiente": "2"
      },
      "graphic": {
        "qr": "1308202601000000000000110050040000000521234567811"
      },
      "failure": null,
      "provider": { "name": "hio.fiscalization", "version": "dev" },
      "metadata": { "externalDeviceId": "1", "externalStoreCode": "K004" }
    }
    ```

    * **`document` habla ecuatoriano.** `claveAcceso`, `secuencial`, `ambiente` — los nombres
      del SRI, no una traducción. Y no hay campos de otros países: el `cufe` colombiano
      sencillamente no existe acá.
    * **El número visible viene armado en `numeroComprobante`** (`005-004-000000052`). Lo
      componés vos, que conocés la regla —art. 18 del Reglamento— y FIRE lo imprime tal cual,
      sin reformatearlo. Las tres piezas siguen viajando aparte, como las define el SRI, pero
      son para conciliar: nadie las vuelve a unir.
    * **`graphic.qr` coincide con `document.claveAcceso`.** En Ecuador es así, y la redundancia
      es deliberada: la alternativa es que el punto de venta sepa qué se codifica en cada país.
    * **`ambiente: "2"` es pruebas** — en el SRI. En la DIAN el `2` es al revés; ver la pestaña
      de Colombia.
  </Tab>

  <Tab title="Colombia (CO) — DIAN">
    ### Lo que enviamos

    ```json theme={null}
    POST {baseUrl}/api/v1/fiscal/co/prekeys
    x-api-key: ••••

    {
      "country": "CO",
      "operation": "INVOICE",
      "businessDayDate": "2026-08-16",
      "createdAt": "2026-08-16T14:03:22.145Z",
      "orderCode": "CO-K039-1786901234",
      "store": {
        "code": "K039",
        "storeFiscalConfig": {
          "govIdType": "NIT",
          "govIdNumber": "9001234567",
          "company": {
            "govIdType": "NIT",
            "govIdNumber": "9001234567",
            "legalName": "COMERCIALIZADORA ANDINA S.A.S.",
            "tradeName": "KFC"
          },
          "metadata": {
            "claveTecnica": "fc8eac422eba16e22ffd8c6f94b3f40a6e38162c",
            "rangoFacturacion": {
              "prefijo": "SETP",
              "desde": "990000000",
              "hasta": "995000000",
              "resolucion": "18760000001",
              "vigenteHasta": "2027-08-16"
            }
          }
        }
      },
      "device": { "uid": "52CAEA5A18D9B75F", "name": "CAJA 3", "platform": "android" },
      "client": {
        "name": "Consumidor",
        "lastName": "final",
        "govIdType": "FINAL_CONSUMER",
        "govIdNumber": "00000000000"
      },
      "totals": [
        {
          "currencyCode": "COP",
          "total": "500000000",
          "subtotalWithoutTaxes": "420168100",
          "taxValue": "79831900",
          "taxes": [{ "name": "IVA", "base": "420168100", "rate": "0.19", "amount": "79831900" }]
        }
      ],
      "metadata": {}
    }
    ```

    Acá `storeFiscalConfig.metadata` **sí trae datos** —la clave técnica y el rango que la DIAN
    entrega con la resolución—, y los importes de `totals` no son informativos: entran al hash
    del CUFE.

    ### Lo que devolvió el proveedor

    ```json theme={null}
    HTTP 200

    {
      "status": "INVOICED",
      "country": "CO",
      "orderCode": "CO-K039-1786901234",
      "reused": false,
      "retryable": false,
      "authorizationMode": "ONLINE",
      "issuedAt": "2026-08-16T14:21:03.118Z",
      "document": {
        "numeroComprobante": "SETP990000001",
        "prefijo": "SETP",
        "numeroDian": "990000001",
        "cufe": "9c4f1e…  ← 96 caracteres hexadecimales",
        "qrCode": "https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=9c4f1e…",
        "ambiente": "2"
      },
      "graphic": null,
      "failure": null,
      "provider": { "name": "hio.fiscalization", "version": "dev" },
      "metadata": { "externalStoreCode": "K039" }
    }
    ```

    * **`document` habla colombiano**, y no se parece al de Ecuador: no hay `claveAcceso` ni
      `secuencial`, hay `cufe`, `prefijo` y `numeroDian`.
    * **`graphic` viene en `null`.** En Colombia el QR es la URL del catálogo de la DIAN y viaja
      dentro de `document.qrCode`, así que no se duplica afuera.
    * **`numeroComprobante` y `numeroDian` no son lo mismo**: el primero es el número visible ya
      armado (`prefijo + consecutivo`), el segundo es el consecutivo solo. Los dos se devuelven
      resueltos; FIRE no concatena nada.
    * **`ambiente: "2"` es pruebas en la DIAN** — el código es el del ente, sin normalizar, y
      por eso significa lo contrario que en Ecuador.
  </Tab>
</Tabs>

Fijate en lo que **no** viaja en ninguno de los dos: ni `accountId`, ni `vendorId` —el tenant
sale de la API key—, ni códigos del ente, ni referencia al catálogo del proveedor.

Y dos cosas comunes a los dos países:

* **`authorizationMode` e `issuedAt` están en la raíz**, fuera de `document`: son comunes a
  todos los países, así que no pertenecen al bloque del país.
* **`status: "INVOICED"`**, no `"PENDING"`. Recién numerado el documento siempre está
  pendiente de autorización — es la condición normal, no un estado que informar.

## Cuando falla

### La misma petición, con la tienda fuera del catálogo del proveedor

```json theme={null}
HTTP 422

{
  "orderCode": "E2E-FUEL-FALLA-01",
  "retryable": false,
  "failure": {
    "code": "UNMAPPED_STORE_IDENTITY",
    "message": "identidad fiscal no configurada: EC / la tienda K004 no está cargada en el catálogo de identidades fiscales",
    "details": [
      { "field": "store.code", "issue": "no está en el catálogo de identidades fiscales" }
    ]
  },
  "document": null,
  "graphic": null,
  "provider": { "name": "hio.fiscalization", "version": "" }
}
```

Por qué este error está bien construido:

|                            |                                                                                                                 |
| -------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **HTTP `422`, no `200`**   | Un rechazo con `200` y el motivo escondido en un campo es un contrato donde alguien no valida y cree que numeró |
| **`retryable: false`**     | Es configuración: reintentar en la caja mientras el cliente espera no lo va a arreglar                          |
| **`failure.code` estable** | `UNMAPPED_STORE_IDENTITY` sirve para alertas y documentación de soporte. Un texto libre no                      |
| **`message` accionable**   | Dice qué tienda y qué catálogo. Se puede arreglar sin abrir un ticket                                           |
| **`details[]`**            | Apunta al campo exacto del request                                                                              |

<Warning>
  **`retryable` es lo que decide qué pasa después.** Con `false` cortamos y la venta queda
  sin comprobante fiscal, con el motivo registrado. Con `true` la solicitud queda abierta y
  se puede retomar.

  Sin ese campo hay que adivinar por el código HTTP — y adivinar mal significa reintentar
  mientras el cliente espera, o abandonar una venta que se podía numerar.
</Warning>

## Qué hacemos con cada respuesta

El estado que expone FIRE a sus canales se **deriva** de lo que devuelve el proveedor. El
proveedor no conoce estos estados ni tiene que emitirlos:

| Lo que devuelve el proveedor                 | Estado que expone FIRE                           |
| -------------------------------------------- | ------------------------------------------------ |
| `2xx` con `document`                         | `GENERATED` — hay comprobante                    |
| No-`2xx` con `retryable: false`              | `FAILED_FINAL` — no hay, y reintentar no sirve   |
| No-`2xx` con `retryable: true`               | `FAILED_RETRYABLE` — no hay, se puede reintentar |
| **No respondió** (timeout, conexión cortada) | `PENDING` — **no sabemos si numeró**             |

<Note>
  `PENDING` no puede venir del proveedor por definición: decirlo implicaría haber
  contestado. Es el estado de "no hubo respuesta", y es el más delicado — el proveedor pudo
  haber numerado y consumido un secuencial sin que nos enteremos.

  Por eso **tu deduplicación tiene que ser por `orderCode`**: el reintento llega con el mismo
  `orderCode` y debe devolver **el mismo documento** con `reused: true`, en vez de numerar otro.

  <Warning>
    **No la bases en un header de idempotencia: no te mandamos ninguno.** La llamada al
    proveedor lleva solo `x-api-key` y `Content-Type`. La llave natural
    —`país + orderCode + operación`— es lo único que liga un reintento con el intento
    original, en los dos extremos.
  </Warning>
</Note>
