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

# order.opened

> An order was injected and is OPEN — it exists, but nobody has paid yet. The entry point for deferred-payment flows: cook, invoice, or dispatch before the money arrives.

<Tabs>
  <Tab title="v1.1 · current">
    You are reading the **current (v1.1)** contract for `order.opened`. **v1.1 adds** `data.fiscalRepresentation`: the fiscal numbering the point of sale obtained before injecting the order. It **always** travels: `null` when numbering was not attempted, and populated when it was — `numberingStatus` tells you how it ended. Carrying content does **not** mean the document is authorized. Additive only — nothing you already read changed.

    The block carries the order's **current** fiscal document: the fields that mean the same in every country at the top, the authority identifiers inside `countryData` in that country's own vocabulary, and the previous documents in `history`. When a cancellation numbers, the credit note moves to the top and the invoice moves down into history — with `compensates` pointing at it.
  </Tab>

  <Tab title="v1 · previous">
    The **v1** contract is still valid: v1.1 only adds one block, nothing before it changed.
  </Tab>
</Tabs>

`order.opened` fires when an order is injected **already open** — it exists in Fire, the kitchen can start, but no payment has been confirmed. It carries the same **V4 order snapshot** as [`order.completed`](/en/events/order-completed), so anything you can do on a completed order you can also do here.

This is the event that makes deferred payment possible. Without it, an unpaid order would be invisible to your integrations until the money arrived.

## Trigger condition

Fire emits `order.opened` **once**, at injection, when:

* `order.status === "OPEN"`

That is the only condition. Unlike `order.completed`, there is **no payment guard** — `paymentStatus` is typically `"PENDING"` and that is expected.

<Warning>
  `order.opened` does **not** fire for orders injected as `COMPLETED` or `CANCELLED`. Those orders never "open": they skip the deferred-payment cycle entirely and produce only [`order.completed`](/en/events/order-completed). Emitting `order.opened` for them would risk dispatching the same order to the kitchen twice.
</Warning>

|                      |                                                                        |
| -------------------- | ---------------------------------------------------------------------- |
| Coverage             | Global (every country, every channel)                                  |
| Idempotency key      | `event.id` (= `flow_executions.id`)                                    |
| Fires more than once | No, unless retried — use `event.id` to dedup                           |
| Ordering             | Not guaranteed across orders — sort by `data.createdAt` if you need it |
| Retries              | Up to 5 attempts with exponential backoff                              |

## The order's life after this event

`order.opened` is the **first** of up to three events for the same order. Knowing the sequence matters, because the same order will reach your endpoint more than once:

```
order.opened      the order exists, nobody paid       status: OPEN
   ↓  (minutes later — the courier collects, the customer pays)
order.completed   the charge settled the full total   status: COMPLETED
   ↓  (if a fiscal document is authorized)
order.invoiced    SEFAZ authorized the NFC-e / NF-e   (Brazil)
```

An order that is cancelled before payment produces [`order.cancelled`](/en/events/order-cancelled) instead of `order.completed`.

<Note>
  If your flow issues a fiscal document on `order.opened`, the **same order** will pass through your fiscal node again on `order.completed`. That second pass is expected and harmless: Fire detects the existing document and returns an idempotent "already invoiced" result instead of issuing a second one. See [Deferred payment](#deferred-payment-policy) below.
</Note>

## What's in `trigger.data`

`trigger.data` is the **V4 order snapshot** — byte-for-byte the same structure `order.completed` carries, with two differences you should expect:

| Field                       | On `order.opened`         | On `order.completed`          |
| --------------------------- | ------------------------- | ----------------------------- |
| `status`                    | `"OPEN"`                  | `"COMPLETED"`                 |
| `paymentStatus`             | usually `"PENDING"`       | `"SUCCEEDED"`                 |
| `payments.paymentMethods[]` | what the POS **declared** | what was actually **charged** |

That last row is the one that surprises integrators. Read it carefully.

### The declared method is not the charged method

At `order.opened` nobody has paid, so `payments.paymentMethods[]` carries the method the POS **announced** when it created the order — often the marketplace (`IFOOD`, `RAPPI`) or a placeholder. `transactionStatus` is `"PENDING"` and `transactionId` is usually empty.

When the charge lands, Fire **overwrites** that array with the real tenders and emits `order.completed`. Same order, same field, different meaning:

```json order.opened — declared theme={null}
{
  "paymentMethodCode": "CASH",
  "processor": "IFOOD",
  "totalBill": 35.9,
  "transactionStatus": "PENDING",
  "transactionId": ""
}
```

```json order.completed — actually charged theme={null}
{
  "paymentMethodCode": "CREDIT_CARD",
  "processor": "CIELO",
  "card": { "brand": "VISA", "lastFourDigits": "4242" },
  "totalBill": 35.9,
  "transactionStatus": "APPROVED",
  "transactionId": "A1",
  "authorizationCode": "AUTH-A1"
}
```

<Warning>
  Never treat `payments.paymentMethods[]` on `order.opened` as settlement evidence. It is an intention, not a fact. If you need to know what was really collected, wait for `order.completed` or call [Get order](/en/api-reference/get-order), which exposes `settlement`.
</Warning>

## Deferred payment policy

`data.policy.deferredPayment` is the reason this event exists. It tells you whether this order is **allowed to be acted on before payment** — cooked, invoiced, dispatched.

The policy is resolved **once**, when the order is injected, from the combination of channel × fulfillment × declared payment method. It is then **stamped immutably** on the order, and every later event echoes it without recalculating. Two events for the same order always carry an identical `policy`.

```json theme={null}
"policy": {
  "deferredPayment": {
    "eligible": true,
    "resolvedAt": "2026-08-02T15:55:42.407Z",
    "configVersion": "fnv1a:3144c6fb",
    "resolvedFrom": {
      "channelCode": "APP",
      "fulfillmentCode": "DELIVERY",
      "paymentMethod": "CASH"
    }
  }
}
```

| Field           | Type                | Meaning                                                                                                                                      |
| --------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `eligible`      | `boolean`           | `true` → act now, the money comes later. `false` → this order is pre-paid or the policy could not be resolved; wait for `order.completed`.   |
| `resolvedAt`    | `string` (ISO 8601) | When the decision was made — at injection, not at emission.                                                                                  |
| `configVersion` | `string \| null`    | Fingerprint of the configuration used. For forensics: if two orders decided differently, compare this. `null` when it could not be computed. |
| `resolvedFrom`  | `object`            | The three inputs behind the decision. `paymentMethod` is the **declared** method, which is why it may not match what was eventually charged. |

**Why immutable?** Because the decision must stay auditable. If the store's configuration changes an hour later, an order already in flight must keep behaving the way it was told to — and you must be able to prove why. Same pattern as `store.storeFiscalConfig`.

<Note>
  `policy` is present on **every** order event (`order.opened`, `order.completed`, `order.invoiced`, `order.cancelled`), not just this one. An order with `eligible: false` still carries the block — it just says the answer was no.
</Note>

## Last known state

`data.lastKnown` is an **advisory** snapshot of what Fire knew about the order's kitchen and fiscal state at the moment the event was emitted.

```json theme={null}
"lastKnown": {
  "kds": null,
  "fiscal": { "status": "processing", "sourceEvent": "fiscal.callback" }
}
```

| Field    | Type             | Meaning                                                                                                         |
| -------- | ---------------- | --------------------------------------------------------------------------------------------------------------- |
| `kds`    | `object \| null` | Last known kitchen state. `null` when nothing has run yet.                                                      |
| `fiscal` | `object \| null` | Last known fiscal state, with the event that produced it. `null` when no fiscal document exists or is expected. |

<Warning>
  **`lastKnown` is a hint, never a source of truth.** It can be stale, and on `order.opened` it is frequently `null` simply because nothing has happened yet. Do not gate an irreversible action on it — if you are about to issue a fiscal document, refunds are not a thing you want to discover you needed. Check the real state first, or rely on Fire's own idempotency.

  Fire itself follows this rule: its fiscal node re-reads the document state from source before emitting, and ignores `lastKnown` entirely.
</Warning>

`fiscal.status` values you may see: `pending`, `processing`, `authorized`, `contingency`, `cancelling`, `cancelled`, `rejected`, `denied`, `error`. Fire also tracks two internal states for orders with no document yet — those are reported as `null` here rather than leaking bookkeeping into your contract.

## Everything else

The remaining blocks — `store`, `client`, `channel`, `orderLines`, `fulfillment`, `kds`, `device`, `operator`, `marketing`, `metadata`, `payments.totals` — are identical to `order.completed`. Rather than duplicate them, see the [`order.completed` field reference](/en/events/order-completed#field-reference).

## Common pitfalls

<AccordionGroup>
  <Accordion title="Treating order.opened as a sale">
    It is not. Nobody paid. Counting `order.opened` in revenue reporting will inflate your numbers and double-count once `order.completed` arrives for the same `orderId`.
  </Accordion>

  <Accordion title="Expecting order.opened for every order">
    Pre-paid orders (kiosk, web checkout) are injected already `COMPLETED` and never emit it. If your integration depends on `order.opened` firing first, it will silently skip those orders. Subscribe to both.
  </Accordion>

  <Accordion title="Reading the payment method as final">
    See [above](#the-declared-method-is-not-the-charged-method). On `order.opened` it is what the POS declared, not what was collected.
  </Accordion>

  <Accordion title="Processing the same order twice">
    The same `orderId` reaches you on `order.opened` and again on `order.completed`. That is by design. Make your handler idempotent per `(orderId, action)`, not per `orderId`.
  </Accordion>
</AccordionGroup>

## Next

* [`order.completed`](/en/events/order-completed) — the same order, once the money lands
* [`order.cancelled`](/en/events/order-cancelled) — if it dies before payment
* [Confirm payment](/en/api-reference/confirm-payment) — the endpoint that settles an open order
* [Get order](/en/api-reference/get-order) — read `settlement` to see how much has actually been collected

## `data.fiscalRepresentation`

The **fiscal numbering** the point of sale obtained *before* injecting the order:
it charges, requests the identifiers, prints the receipt, and only then injects.
That is why it travels on the order and not in a separate fiscal event — by the
time the order is born, this already happened.

<Warning>
  **The presence of this block does NOT mean the document is authorized.** These
  are the numbers printed at the till; the tax authority's verdict is in
  `lastKnown.fiscal.status`. A ticket that says "authorized" just because the
  block is present states something that may never have happened.
</Warning>

**The key always travels.** It arrives as `null` when numbering was not
attempted — aggregators, countries without fiscal representation, or merchants
with numbering turned off — and carries the block when it was.

Carrying the block means **numbering was attempted, not that it succeeded**:
`numberingStatus` tells you how the attempt ended, and `failure` why, when it did
not end well.

Branch on the value, not on the key's presence:

```js theme={null}
if (data.fiscalRepresentation) {
  // numbering was attempted — read numberingStatus to see how it went
}
```

| Field               | What it is                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `numberingStatus`   | How the **numbering act** ended: `GENERATED`, `PENDING`, `FAILED_RETRYABLE`, `FAILED_FINAL`, `UNAVAILABLE`. **Not the authority's verdict** — that lives in `lastKnown.fiscal.status`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `documentNumber`    | The receipt's visible number, composed per country (`005-004-000000042`). It is presentation and **Fire builds it**, not the authority: reconcile with `countryData`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `issuedAt`          | When it was **numbered**. Not the authorization date.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `authorizationMode` | `ONLINE`, `OFFLINE` or `BATCH`. A provider concept, not universal.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `providerCode`      | Identifier of the adapter that numbered.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `countryData`       | The authority identifiers, in the vocabulary of the **country that numbered** — and only that country's. Ecuador: `numeroComprobante` (the human-readable document number, already assembled by the provider), `claveAcceso`, `establecimiento`, `puntoEmision`, `secuencial`, `ambiente`. Venezuela: `numeroControl`, `numeroFactura`, `serie`. **Iterate it; do not index blindly** — a new key here is not a breaking change. It is the same block the numbering endpoint returns and the authority callback carries. The per-country reference, with each regime's keys, is in [`countryData` by country](/en/api-reference/fiscal-documents#countrydata-by-country). |
| `graphic`           | The printable artifact the provider returned (QR and the like), verbatim. `null` if it returned none.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `failure`           | Why there is **no** receipt. `null` when numbering succeeded.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `providerIdentity`  | **Who numbered, on the provider's side**: `{ "name": "hio.fiscalization", "version": "2026.08.1", "reference": "HIO-91f3c2" }`. Unlike the bag below, **it has a shape**: all three fields are part of the contract and always come through, with `null` when they do not apply. `reference` is **the provider's own support reference** — the identifier you quote back to them so they can find the operation in their records; it is not the `Idempotency-Key` the channel sent. It does not carry `providerCode`: that one is ours and travels at the top.                                                                                                            |
| `providerMetadata`  | **The provider's diagnostic bag**, exactly as it returned it: in Ecuador with HIO you get `{ "deviceUid": "4B8E…", "externalStoreCode": "K000" }`. It is **opaque** — the provider owns the keys and may change them without notice, so do not program against them; it is for pasting into a ticket, not for branching. **It is exactly the same field the numbering endpoint returns**, same name and same content: all three provider fields read the same at both ends.                                                                                                                                                                                               |
| `environment`       | Which environment **Fire** numbered in: `SANDBOX` or `PRODUCTION`. It is ours, not the authority's — the authority's travels inside `countryData` with the country's own code.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `compensates`       | Which document this one voids. Present **only** when `documentType` is `CREDIT_NOTE`. It is a **pointer**, not a copy: look its `documentNumber` up in `history` for the whole document. `reason` is the canonical code — the printed wording is authored per company and resolved in the numbering endpoint's response.                                                                                                                                                                                                                                                                                                                                                  |
| `history`           | The order's **previous** documents, oldest first. Empty while there was only one; when a cancellation numbers, the invoice moves down here and the credit note sits on top. Every entry has **the same shape** as the block above, so they read alike. Documents only: a failed attempt does not appear.                                                                                                                                                                                                                                                                                                                                                                  |

```json theme={null}
"fiscalRepresentation": {
  "numberingStatus": "GENERATED",
  "documentNumber": "005-004-000000042",
  "countryData": {
    "numeroComprobante": "005-004-000000042",
    "claveAcceso": "1208202601000000000000110050040000000421234567810",
    "establecimiento": "005",
    "puntoEmision": "004",
    "secuencial": "000000042",
    "ambiente": "2"
  },
  "authorizationMode": "ONLINE",
  "issuedAt": "2026-08-13T08:11:29.744Z",
  "providerCode": "hio",
  "graphic": { "qr": "1208202601000000000000110050040000000421234567810" },
  "failure": null,
  "providerIdentity": { "name": "hio.fiscalization", "version": "2026.08.1", "reference": "HIO-91f3c2" },
  "providerMetadata": { "deviceUid": "4B8E21F9A0D35C7A", "externalStoreCode": "K004" },
  "environment": "PRODUCTION",
  "compensates": null,
  "history": []
}
```

**The authority's verdict does not alter it.** What the customer took home
printed does not change because the authority later authorizes or rejects — that
is what `lastKnown.fiscal` is for, and that is what does move.

**What does replace it is a new document.** The block carries the order's
**current** fiscal document. While there was only one, it was always the invoice;
when a cancellation produces a credit note, the note is what sits on top —
`documentType` says which one — and the invoice **moves down into `history`**,
whole and with its own authority identifiers. It is not lost: it moves.
`compensates` points at it by number, so the relationship stays explicit.

### When numbering fails

A sale can be charged and end up **with no fiscal receipt**. That case travels
too, and you must handle it: the identifiers come back `null` and the reason is
in `failure`.

```json theme={null}
"fiscalRepresentation": {
  "numberingStatus": "FAILED_FINAL",
  "documentNumber": null,
  "issuedAt": null,
  "providerCode": "hio",
  "graphic": null,
  "failure": { "code": "RUC_INVALIDO", "scope": "FUNCTIONAL", "message": "Tax ID not enabled" }
}
```

Branch on `failure.scope`:

* **`TECHNICAL`** — print "pending" and carry on. It may resolve on its own.
* **`FUNCTIONAL`** — some data is wrong and retrying will not fix it. Needs correction.

<Note>
  **`lastKnown.fiscal.sourceEvent` now reports real provenance.** It used to be
  derived from the status, so a `processing` seeded at injection was reported as
  `fiscal.callback` even though no callback had occurred. That case now says
  `order.injected`. If you branch on this field, account for the new value.
</Note>
