Skip to main content
Deprecated. This is the v0 order.completed contract, kept only as a historical reference. Use the current v1 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.
CoverageGlobal (every country, every channel)
Idempotency keyevent.id (= flow_executions.id)
Fires more than onceNo, unless retried — use event.id to dedup
OrderingNot guaranteed across orders — sort by data.createdAt if you need it
RetriesUp to 5 attempts with exponential backoff

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:
KeyTypeAlways present
orderIdstring (UUID)yes
orderCodestring | nullyes
businessDayDatestring (YYYY-MM-DD)yes
externalOrderIdstringyes
redeemPointsbooleanyes
accumulatePointsbooleanyes
discountbooleanyes
createdAtstring | null (ISO 8601 UTC)yes
orderCommentstring (may be "")yes
paymentStatusstring (always "SUCCEEDED")yes
statusstring (always "COMPLETED")yes
marketingobject | nullyes
storeobjectyes
deviceobjectyes
channelobjectyes
operatorobjectyes
clientobject | nullyes
paymentsobjectyes
kdsobjectyes
metadataobject (often {})yes
orderLinesobject[]yes
fulfillmentobjectyes

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.
{
  "orderId": "21ec1f6c-c301-4528-b999-7836c1d21c6c",
  "orderCode": "OC-br-001",
  "businessDayDate": "2026-03-31",
  "externalOrderId": "7805610b-97cf-461f-a2d6-d86f63a80833",
  "redeemPoints": false,
  "accumulatePoints": false,
  "discount": false,
  "createdAt": "2026-05-06T01:22:59.028Z",
  "orderComment": "Comentario de prueba orden",
  "paymentStatus": "SUCCEEDED",
  "status": "COMPLETED",
  "marketing": null,
  "store": {
    "uid": "a4019cad-bbac-4269-9f8d-f29654e92c45",
    "code": "BR-SP-001",
    "name": "Loja Centro - SP",
    "phone": "1132094347",
    "address": "Av. Paulista 1578, Bela Vista, São Paulo - SP",
    "externalId": "a4019cad-bbac-4269-9f8d-f29654e92c45",
    "vendor": {
      "uid": "100.2.1",
      "name": "Sandbox Brand",
      "description": "Sandbox Brand",
      "loyaltyPlan": true
    },
    "account": {
      "uid": "100",
      "name": "Sandbox",
      "description": "Sandbox"
    },
    "locationInfo": {
      "city":     { "uid": "1", "code": "SAO", "name": "São Paulo" },
      "country":  { "uid": "6", "code": "BR",  "name": "Brasil" },
      "location": { "lat": "-23.5952979", "lon": "-46.6866818" },
      "timezone": "America/Sao_Paulo",
      "currencyCode": "BRL"
    },
    "storeFiscalConfig": {
      "enabled": true,
      "company": {
        "govIdType": "CNPJ",
        "govIdNumber": "00000000000000",
        "legalName": "Sandbox LTDA",
        "tradeName": "Sandbox"
      },
      "govIdType": "CNPJ",
      "govIdNumber": "00000000000000",
      "secondaryGovIdType": "INSCRICAO_ESTADUAL",
      "secondaryGovIdNumber": "000000000000",
      "metadata": {
        "neverstop":   { "url": "", "enabled": false },
        "storeCode3S": "50000001",
        "serialNumber": 1
      }
    }
  },
  "device": {
    "uid": "device_kiosk_001",
    "name": "KIOSK",
    "platform": "android",
    "metadata": { "ip": "10.0.0.0" }
  },
  "channel": {
    "uid": "c784d4ba-23c7-4929-b2f0-1a1960d9cdc2",
    "code": "KIOSK",
    "metadata": {}
  },
  "operator": {
    "uid": "op_001",
    "name": "Operator Name",
    "session": { "uid": "sess_001" }
  },
  "client": {
    "uid": "usr_consumidorfinal_001",
    "name": "CONSUMIDOR",
    "lastName": "FINAL",
    "email": "consumidor@example.com",
    "phone": "0000000000",
    "govIdType": "FINAL_CONSUMER",
    "govIdNumber": "00000000000",
    "externalId": null,
    "metadata": {
      "fiscal": null,
      "gender": "",
      "birthdate": ""
    },
    "billingInformation": {
      "email": "",
      "phone": "0000000000",
      "address": "",
      "govIdType": "FINAL_CONSUMER",
      "externalId": "",
      "govIdNumber": "00000000000",
      "businessName": ""
    }
  },
  "payments": {
    "totals": [
      {
        "taxes": [
          { "base": "229000", "name": "ICMS",   "rate": "0.04",   "amount": "9200",
            "metadata": { "cst": "90", "cBenef": "SP040100" } },
          { "base": "229000", "name": "PIS",    "rate": "0.0165", "amount": "3800",
            "metadata": { "cst": "01" } },
          { "base": "229000", "name": "COFINS", "rate": "0.076",  "amount": "17400",
            "metadata": { "cst": "01" } }
        ],
        "total": "229000",
        "subtotal": "197400",
        "discounts": [],
        "taxes_value": "31600",
        "currency_code": "BRL",
        "discount_value": "0",
        "subtotal_before_taxes": "197400"
      }
    ],
    "shippingCost": [],
    "extraCharges": [],
    "discounts": [],
    "paymentMethods": [
      {
        "mid": "",
        "tid": "",
        "processor": "CREDIT_CARD",
        "card": {
          "bin": "MASTERCARD",
          "mask": "",
          "brand": "MASTERCARD",
          "holder": "",
          "card_country": "",
          "last_four_digits": "0000"
        },
        "acquirer": { "code": "00000000000000", "name": "ACQUIRER NAME" },
        "voucher": "",
        "metadata": {},
        "totalBill": 22.9,
        "currencyCode": "BRL",
        "exactPayment": false,
        "transactionId": "tx_a1b2c3d4",
        "referenceNumber": null,
        "transactionDate": {
          "date": "2026-04-17T15:41:55.000Z",
          "timeZoneName": "America/Sao_Paulo"
        },
        "transactionType": "",
        "authorizationCode": "000000000000",
        "paymentMethodCode": "",
        "transactionStatus": "APPROVED",
        "customerCashAmount": "0"
      }
    ],
    "metadata": {
      "fiscal": {
        "vBC":      "229000",
        "vNF":      "229000",
        "vCBS":     "1100",
        "vIBS":     "100",
        "vPIS":     "3800",
        "vDesc":    "0",
        "vICMS":    "9200",
        "vProd":    "229000",
        "vIBSUF":   "100",
        "vCOFINS":  "17400",
        "vIBSMun":  "0",
        "vTotTrib": "31600",
        "vBCIBSCBS":"198700"
      }
    }
  },
  "kds": {
    "metadata": {},
    "orderCode": "OC-br-001",
    "buzzerName": "Leonardo",
    "invoiceEmail": "",
    "invoicePrint": true
  },
  "metadata": {},
  "orderLines": [
    {
      "uid": "b9912637-eb44-4533-a1e5-f5bf2cdd07e8",
      "hash": "0d86fae2b5bc6198",
      "itemId": "39d1bd7fcd45c52f0c824364c2c0cfc402bd72b046cfaaec276a0131908dbf20",
      "itemType": "PRODUCT",
      "itemDescription": "Crunch Salad + Batata Pequena + 1 Tira + Refri",
      "quantity": "1",
      "selectedCurrency": "BRL",
      "updatedAt": "2026-05-06T01:22:59.663Z",
      "price": {
        "unitPrice": [
          {
            "taxes": [],
            "netPrice": "229000",
            "grossPrice": "229000",
            "currencyCode": "BRL",
            "discounts": [],
            "discountValue": "0",
            "taxesValue": "0",
            "subtotalBeforeTaxes": "229000"
          }
        ],
        "totalPrice": [
          {
            "taxes": [
              { "base": "229000", "name": "ICMS",   "rate": "0.04",   "amount": "9200",
                "metadata": { "cst": "90", "cBenef": "SP040100" } }
            ],
            "netPrice": "197400",
            "grossPrice": "229000",
            "currencyCode": "BRL",
            "discounts": [],
            "discountValue": "0",
            "taxesValue": "31600",
            "subtotalBeforeTaxes": "197400"
          }
        ]
      },
      "lineTotals": [ /* same shape as price.totalPrice[n] */ ],
      "modifierGroups": [
        {
          "uid": "e247256ad628b0fd9c45453370e247fef1ad173829cc809c9c6930698d62e56b",
          "description": "Selecione: Escolha seus sanduíches!",
          "selectedModifiers": [
            {
              "itemId": "0104fdb2010be9ac14750a950f81c026b35a49a3c32b36281f41ef650d278b72",
              "itemType": "PRODUCT",
              "itemDescription": "CRUNCH SALAD",
              "quantity": "1",
              "selectedCurrency": "BRL",
              "price": { /* unitPrice / totalPrice arrays — same shape */ },
              "modifierGroups": [],
              "metadata": {
                "redeemed": false,
                "externalCode": "80229#900002186#91198"
              }
            }
          ]
        }
      ],
      "metadata": {
        "fiscal": {
          "ncm": "21069090",
          "cfop": "5101",
          "csosn": "500",
          "vTotTrib": 3.16,
          "fiscalCategoryCode": "2106.90.90"
        },
        "redeemed": false,
        "externalCode": "80229",
        "referenceUnitPrice": null,
        "referenceTotalPrice": null
      }
    }
  ],
  "fulfillment": {
    "service": { "uid": "726c4892-48b9-45da-b066-2a8e83d2cb78", "code": "DINE_IN", "metadata": {} },
    "pickup": {
      "prepDate": "2026-05-06T01:22:59.028Z",
      "prepTime": "",
      "pickupDate": "2026-05-06T01:22:59.028Z",
      "propertyId": "a4019cad-bbac-4269-9f8d-f29654e92c45",
      "prepTimeUnit": "minute"
    },
    "delivery": {
      "city": "São Paulo",
      "country": "Brasil",
      "zipCode": "",
      "latitude": "0",
      "nickName": "HOME",
      "longitude": "0",
      "reference": "",
      "mainStreet": "",
      "propertyId": 1,
      "deliveryDate": null,
      "secondaryStreet": ""
    }
  }
}
Money values are strings expressed as integer minor units × 10000 (e.g. "229000" = 22.9000 BRL). 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

orderId
string
Fire’s internal order UUID. Stable across deliveries; use together with event.id for traceability.
orderCode
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.
businessDayDate
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.
externalOrderId
string
The order ID as provided by the channel/aggregator on injection. Use it when reconciling with upstream systems (POS, aggregator dashboards).
createdAt
string | null
ISO 8601 UTC timestamp of when the order was originally placed. Distinct from event.createdAt, which is when the flow execution started.
status
string
Always "COMPLETED" for this event.
paymentStatus
string
Always "SUCCEEDED" for this event.
redeemPoints
boolean
true if loyalty points were redeemed on this order.
accumulatePoints
boolean
true if the customer accumulated loyalty points.
discount
boolean
true if any discount was applied.
orderComment
string
Free-text customer note for the whole order. Empty string when not set.

data.store

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

data.client

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

payments
object
Money breakdown.

data.fulfillment

fulfillment
object
How the order is being delivered.

data.kds

kds
object
Kitchen-display context.

data.device and data.operator

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

data.orderLines

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

data.marketing, data.metadata, data.channel

marketing
object | null
Loyalty + coupons. null in most countries today; reserved for future use.
metadata
object
Free-form bag for order-level extras. Often {}.
channel
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.
"storeFiscalConfig": {
  "enabled": true,
  "company": {
    "govIdType":   "CNPJ",
    "govIdNumber": "00000000000000",
    "legalName":   "Sandbox LTDA",
    "tradeName":   "Sandbox"
  },
  "govIdType":            "CNPJ",
  "govIdNumber":          "00000000000000",
  "secondaryGovIdType":   "INSCRICAO_ESTADUAL",
  "secondaryGovIdNumber": "000000000000",
  "metadata": {
    "neverstop":    { "url": "", "enabled": false },
    "storeCode3S":  "50000001",
    "serialNumber": 1
  }
}

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.
"metadata": {
  "fiscal": {
    "vBC":      "229000",
    "vNF":      "229000",
    "vICMS":    "9200",
    "vPIS":     "3800",
    "vCOFINS":  "17400",
    "vCBS":     "1100",
    "vIBS":     "100",
    "vIBSUF":   "100",
    "vIBSMun":  "0",
    "vTotTrib": "31600",
    "vBCIBSCBS":"198700",
    "vDesc":    "0",
    "vProd":    "229000"
  }
}

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.
"metadata": {
  "fiscal": {
    "ncm":               "21069090",
    "cfop":              "5101",
    "csosn":             "500",
    "vTotTrib":          3.16,
    "fiscalCategoryCode":"2106.90.90"
  }
}
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

Countrycountry.codeCurrency (effective)govIdType (format)Fiscal aggregates
BrazilBRBRLCNPJ (14 digits)Yes — full SEFAZ aggregates
ArgentinaARARSCUIT (XX-XXXXXXXX-X)No — null / empty
ChileCLCLPRUT (XXXXXXXX-X)No
ColombiaCOCOPNIT (XXXXXXXXX-X)No
EcuadorECUSD (Ecuador’s official currency)RUC (13 digits)No
VenezuelaVEVESRIF (J-XXXXXXXX-X)No
Other countriesvariesvariesvariesNo
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

async function onOrderCompleted(data) {
  const {
    orderId,
    externalOrderId,
    store,
    payments,
    orderLines,
    fulfillment,
    createdAt,
  } = data;

  // 1. Persist for accounting / analytics
  await db.orders.upsert({
    where: { fireOrderId: orderId },
    create: {
      fireOrderId: orderId,
      externalOrderId,
      storeCode: store.code,
      country: store.locationInfo.country.code,
      currency: store.locationInfo.currencyCode,
      // payments.totals[0].total is "229000" minor units × 10000
      totalMinorUnits: BigInt(payments.totals[0]?.total ?? "0"),
      completedAt: new Date(createdAt ?? Date.now()),
      service: fulfillment.service.code,
    },
    update: {},
  });

  // 2. If fiscal-enabled, dispatch to fiscal pipeline
  if (store.storeFiscalConfig?.enabled) {
    await fiscalPipeline.enqueue({
      orderId,
      country: store.locationInfo.country.code,
      emitter: store.storeFiscalConfig.company,
      aggregates: payments.metadata?.fiscal,
      lines: orderLines.map((l) => ({
        itemId: l.itemId,
        ncm: l.metadata?.fiscal?.ncm,
        cfop: l.metadata?.fiscal?.cfop,
      })),
    });
  }

  // 3. If delivery, dispatch to logistics
  if (fulfillment.service.code === "DELIVERY" && fulfillment.delivery) {
    await dispatcher.send({
      orderId,
      address: fulfillment.delivery,
      items: orderLines,
    });
  }
}

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.