Skip to main content
Deprecated. This is the v0 order.completed contract, kept only as a historical reference. Use the current v1.1 contract for new integrations.
order.completed fires when an order is successfully injected and paid. It carries the V4 order snapshot as trigger.data — every field your flow needs to act on the order without calling back into Fire.

Trigger condition

Fire emits order.completed exactly once per order, the first time both of these are true at injection time:
  • order.status === "COMPLETED"
  • order.paymentStatus === "SUCCEEDED"
Orders that are still PENDING payment, or that fail payment, never produce order.completed. Cancellations after completion produce a separate order.cancelled event — they do not retract order.completed.

What’s in trigger.data

trigger.data is the V4 order snapshot — the same object that’s persisted in flow_queue.trigger_data and exposed to your flow’s templates. The top-level keys, in the order they appear:

Example — real production payload (BR, sanitized)

The example below is taken from a real flow_queue.trigger_data row (Brazilian sandbox tenant, KIOSK channel, dine-in service). PII fields are replaced with placeholders; all other fields and shapes are verbatim.
Money values are strings holding the amount as an integer scaled ×10,000 ("229000" is 22.9 BRL, not 229,000). This avoids floating-point drift across multiple integrations. Parse with a decimal library, never parseFloat. The exception is paymentMethods[].totalBill, which the source sometimes ships as a JSON number — handle both.

Field reference

Top-level identifiers

string
Fire’s internal order UUID. Stable across deliveries; use together with event.id for traceability.
string | null
Short, human-readable code shown on receipts and KDS displays (e.g. 95K, OC-br-001). null when the channel doesn’t assign one.
string
Business day this order belongs to, in YYYY-MM-DD. Computed in store-local time, so an order placed at 01:00 may belong to the previous business day depending on the store’s day-end cutoff.
string
The order ID as provided by the channel/aggregator on injection. Use it when reconciling with upstream systems (POS, aggregator dashboards).
string | null
ISO 8601 UTC timestamp of when the order was originally placed. Distinct from event.createdAt, which is when the flow execution started.
string
Always "COMPLETED" for this event.
string
Always "SUCCEEDED" for this event.
boolean
true if loyalty points were redeemed on this order.
boolean
true if the customer accumulated loyalty points.
boolean
true if any discount was applied.
string
Free-text customer note for the whole order. Empty string when not set.

data.store

object
Snapshot of the store at the moment the order was completed.

data.client

object | null
Customer who placed the order. null for fully anonymous channel orders. For BR “consumidor final” orders, client is populated with placeholder values (govIdType: "FINAL_CONSUMER", govIdNumber: "00000000000").

data.payments

object
Money breakdown.

data.fulfillment

object
How the order is being delivered.

data.kds

object
Kitchen-display context.

data.device and data.operator

object
{ uid, name, platform, metadata.ip } — originating device. Fields may be null for non-physical channels.
object
{ uid, name, session.uid } — staff/cashier who processed the order. All fields null for self-service channels (kiosk, web).

data.orderLines

object[]
Ordered products. Fully camelCase (transformed by the V4 builder).

data.marketing, data.metadata, data.channel

object | null
Loyalty + coupons. null in most countries today; reserved for future use.
object
Free-form bag for order-level extras. Often {}.
object
{ uid, code, metadata }. code examples: KIOSK, APP, IFOOD, RAPPI.

Fiscal data

Fiscal data is included only when the store has fiscal emission enabled (store.storeFiscalConfig.enabled === true). For non-fiscal countries or stores without configuration, all three locations below are absent or null.
order.completed carries fiscal information in three distinct locations. Each serves a different purpose:

1. data.store.storeFiscalConfig — emitter identity & provider config

Identifies the legal entity emitting the document and how to authenticate with the fiscal provider. Credentials are intentionally NOT here — the fiscal node fetches them per provider/account.

2. data.payments.metadata.fiscal — order-level fiscal aggregates

SEFAZ-style aggregate totals, ready to be forwarded to a fiscal provider (your fiscal provider in Brazil). Values are strings × 10000.

3. data.orderLines[n].metadata.fiscal — per-line fiscal classification

Per-product fiscal codes. Used by the fiscal provider to classify each line on the document.
In addition, per-tax metadata lives inside each taxes[n].metadata (in payments.totals[].taxes[], orderLines[].price.totalPrice[].taxes[], and orderLines[].lineTotals[].taxes[]) with codes like cst, cBenef, cClassTrib, reducao, rateNominal, rateEffective.

Country variations

The example above is from a Brazilian store with fiscal emission enabled — the most complex case. The V4 shape is identical across countries; what changes is how much fiscal data is populated. Today, only Brazil carries the per-tax / per-line aggregates (payments.metadata.fiscal, orderLines[n].metadata.fiscal, lineTotals[n].taxes[]). Other countries have those blocks present but null / empty.
Brazilian stores with storeFiscalConfig.enabled === true carry the full fiscal payload — see the Fiscal data section above. Country markers:
  • store.locationInfo.country.code: "BR" · name: "Brasil" · timezone: "America/Sao_Paulo"
  • store.locationInfo.currencyCode: "BRL"
  • store.storeFiscalConfig.govIdType: "CNPJ" (14 digits)
  • store.storeFiscalConfig.secondaryGovIdType: "INSCRICAO_ESTADUAL"
  • payments.totals[].currency_code: "BRL", paymentMethods[].currencyCode: "BRL", orderLines[].selectedCurrency: "BRL"
  • Populated: payments.metadata.fiscal (vBC / vNF / vICMS / vPIS / vCOFINS / vTotTrib …), orderLines[].metadata.fiscal (ncm / cfop / csosn), lineTotals[].taxes[] (ICMS, PIS, COFINS, IBS_*)

Quick reference table

As more countries get a dedicated fiscal pipeline, their fiscal events will land as fiscal.*.{cc} (e.g. fiscal.authorized.co, fiscal.authorized.ec). Until then, only order.completed and order.cancelled fire for non-BR stores — fiscal blocks remain null / empty.

Handler example

Common pitfalls

  • Decimals as strings × 10000. payments.totals[0].total === "229000" means 22.9 BRL. Use a decimal library; never parseFloat.
  • Casing is mixed in payments.totals[] and parts of paymentMethods[]. Read both currencyCode and currency_code defensively. The V4 builder transforms most of the snapshot but passes payment objects through.
  • fulfillment.delivery may be present even for non-delivery services with placeholder zeroes. Always branch on fulfillment.service.code.
  • client may be a populated “FINAL_CONSUMER” placeholder in BR — it is not null. Treat govIdType === "FINAL_CONSUMER" as anonymous for analytics.
  • event.id is the flow execution ID, not the order ID. Use event.id for idempotency (it changes per delivery), and orderId for business key.
  • Multi-tenant routing. Use store.account.uid, store.vendor.uid, and store.code to route to the right tenant in your system, even though Fire already scopes the flow on its side.

order.cancelled

Fires when this order is later cancelled.

order.invoiced

Brazil only — fires once SEFAZ authorizes the order’s fiscal document.