Skip to main content
You are reading the current (v1.2) contract for order.invoiced. v1.2 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.
order.invoiced fires once the country’s fiscal authority authorizes the fiscal document associated with an order — SEFAZ in Brazil, SRI in Ecuador, DIAN in Colombia, AFIP in Argentina, SII in Chile, SENIAT in Venezuela. It is emitted by Fire’s fiscal pipeline, which integrates with your fiscal provider as the document provider. This event is separate from order.completed: the order is paid first (order.completed), then Fire requests fiscal emission via your fiscal provider, and order.invoiced fires only when the fiscal authority returns the authorization.

Trigger condition

Fire emits order.invoiced once per fiscal document, the first time all of these are true:
  • The order is in a store with fiscal billing enabled (storeFiscalConfig.enabled === true)
  • A fiscal document was emitted to your fiscal provider
  • your fiscal provider reports that the fiscal authority authorized the document (status transitions to authorized; in Brazil this maps to the SEFAZ cStat authorized code)

What’s in trigger.data

Same V4 order snapshot as order.completed plus a top-level fiscal block carrying the authorized document references. Fields vary by country — Brazil is shown below (chaveAcesso, protocolo); other countries carry their own identifiers (cufe in CO, claveAcceso in EC, cae in AR, etc.). See the generic fiscal callback for the per-country contract. The order’s status remains "COMPLETED" and paymentStatus remains "SUCCEEDED" — fiscal authorization does not change order status.

Example — real production payload (BR, sanitized)

data.fiscal reference

object
SEFAZ-authorized document references.

Where the fiscal totals live

The aggregate fiscal values (vBC, vNF, vICMS, etc.) are not inside data.fiscal — they’re in data.payments.metadata.fiscal, the same place order.completed carries them. order.invoiced does not duplicate them; treat the order snapshot as the single source of truth for monetary aggregates. Per-line classification (NCM, CFOP, CSOSN, fiscalCategoryCode) lives in data.orderLines[n].metadata.fiscal. Same as in order.completed. The data.store.storeFiscalConfig block carries the emitter identity (CNPJ, legalName, tradeName) — also unchanged from order.completed.

data.policy and data.lastKnown

Every order event carries these two blocks — not just this one. They were added together with the deferred-payment cycle and are added in v1.1, additive: existing consumers keep working unchanged.
Field-by-field detail lives in order.opened, the event where these blocks matter most.

Handler example

Common pitfalls

  • status === "authorized", not "COMPLETED". The data.status (the order status) is "COMPLETED"; the fiscal status is in data.fiscal.status.
  • pdfUrl and xmlUrl may be ephemeral. In production, your fiscal provider may sign/expire these links. Download and persist the artifacts on receipt rather than linking customers directly to your fiscal provider.
  • cStat is often null. Don’t make logic depend on it. Use status === "authorized" and protocolo as the authoritative signals.
  • No event for rejected / denied / error. If SEFAZ rejects the document, no event fires today. The fiscal document’s status is persisted internally but no flow is triggered. Watch for this in the roadmap.
  • The country no longer lives in the event name. order.invoiced fires for all countries; filter on fiscal.countryCode. The fiscal block fields vary per country (chaveAcesso/protocolo in BR, cufe in CO, claveAcceso in EC, etc.).

order.completed

Fires before this event — the order itself.

order.reversed

Fires later if the document gets cancelled at SEFAZ.

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