Skip to main content
Subscribe to updates
Get an email whenever a new entry lands here — new events, breaking changes and API reference updates. One click to unsubscribe.
Subscribe

21 October 2026 — Import and export the catalog

The backoffice has a new screen, Import & export (Operation → Import & export): download a copy of a vendor’s catalog, edit it outside the backoffice and import it again, reviewing every change before it is written.
  • Import & export — new manual. Two formats: Full backup (JSON), with categories, modifiers, price lists, products and menus, to keep a copy or move the catalog to another environment; and Editable spreadsheet (Excel), with categories, products and prices in flat rows, to change many at once.
  • Review first — importing never writes right away: the file is analyzed, you review what would be created, updated and deleted, and only then apply it. Before applying, Fire saves a backup of the current data.
  • Merge and Replace — Merge creates and updates and deletes nothing. Replace leaves the data exactly as in the file and deletes what is not in it; it is reserved for platform administrators, who can also Undo an applied import.
  • Affected combinations — the detail lists the store × channel × Fulfillment Type combinations that use a menu or price list that changes.
Importing does not synchronize: the changes reach stores and channels only when you synchronize from Menu assignment.
Updated in EN / ES / PT.

13 October 2026 — API keys guide and sale prices in the backoffice

A new guide covers API keys end to end: where to create one, what vendor scope means, and which scope each endpoint needs.
  • API keys — create keys under Developers → API Management with Create API Key: pick a name, the scopes and an optional expiration. Select a vendor in the dashboard before you create the key: with All vendors selected the key has no vendor binding, and endpoints that require one answer 403.
  • Scopes — every scope in the dashboard, mapped to the endpoints it unlocks, including cash-management:write and kiosks:write.
  • Managing keys — you can edit a key’s scopes without changing its secret; name, description and expiration are fixed once created, and there is no built-in rotation (create a new key, switch, then revoke the old one).
  • Header — send the key in x-api-key. Authorization: Bearer pk_live_... still works as a legacy alias; if you send both, x-api-key wins.
  • List menus and Get menu now link to the guide for the menu:read scope and the vendor binding.
The backoffice manuals for the catalog are rewritten around sale prices and prices by fulfillment type:
  • Price lists — sale prices now live here, next to the price, and also apply inside combos. How far a sale reaches, and why a suggested price is only a struck price, never charged.
  • Menus — a menu no longer has a fulfillment type of its own: it takes the one from the assignment row. Three lenses (day, fulfillment type, prices) and the new Overrides tab.
  • Menu assignment — sale prices travel with Sync, batches drop from 50 to 20 rows, and price edits saved from the preview only reach aggregators, not POS or Kiosk.
  • Modifier groups — adding a group to a product copies it: later edits to the group don’t reach products that already have it. Different questions per fulfillment type.
  • Products — combos have no price of their own: the customer pays the sum of the options picked. The “from” reference price, sales inside a combo and prices by fulfillment type.
Updated in EN / ES / PT.

6 October 2026 — New endpoint: list a store’s terminals

You can now read which devices a store has and what state they are in: POS registers, self-service kiosks and KDS kitchen displays.
  • GET /external/stores/{storeId}/terminals — returns each terminal’s type, status and lastSeenAt, and its externalId (for kiosks, the device ID on the QR screen). By default it returns active and suspended terminals; ask for revoked ones with status=REVOKED. Filter by type and trim the response with fields. Uses the store:read scope you already have for the store endpoints.

5 October 2026 — The partial day report in receipt printing

Print the day close accepts "partial": true to print how the day is going so far without closing it (X report): same template as the close, with a PARCIAL — NO ES CIERRE band and the cut time.
  • Only the store’s open day; any other date responds 409 PRINT_DAY_NOT_OPEN.
  • The response carries subject.partial: true, and freshness.asOf is the cut time.
  • Without partial, the endpoint behaves exactly as before.
Updated in EN / ES / PT.

30 September 2026 — The store fiscal block has the same shape in every country

The fiscal block in List stores and Get store is no longer Brazil-specific. secondaryGovIdType, secondaryGovIdNumber and metadata are always present, null when the store doesn’t have them, same as store.storeFiscalConfig in order.completed.
  • Colombia: metadata carries claveTecnica, rangoFacturacion and rangoNotaCredito (the DIAN numbering ranges).
  • Ecuador, Chile, Argentina, Venezuela: the three keys are present, as null. They used to be absent.
  • Brazil: unchanged.
The order events (order.cancelled, order.invoiced, order.reversed) carry the same block as order.completed: in Colombia, the cancellation includes the ranges used to issue the credit note.

28 September 2026 — External API menu endpoints documented

Two endpoints join the External API, alongside Get store and List stores: reading a store’s menus by API key, the query-side counterpart to the menu.updated webhook.
  • List menus — which ternas (store × channel × fulfillment type) of a store currently have a generated menu, without the menu body.
  • Get menu — the last generated menu of one terna, in the same shape as menu.updated, with a sync block telling you whether it reached the channel.
Design is closed but not implemented yet — there is nothing to call today. This entry exists so you can build against the contract ahead of the release.
Updated in EN / ES / PT.

25 September 2026 — Cash handed over and change in the order events

The two cash fields of payments.paymentMethods[] in the events that carry the V4 order snapshot (order.opened, order.completed, order.invoiced, order.cancelled, order.reversed). The event versions do not change.
  • customerCashAmount is a number and carries the real amount. Until 24 September 2026 it always travelled as the string "0", even on cash payments. Now it is the cash the customer handed over: for a 22.9 bill paid with a 50 note, 50; 0 on methods that are not cash.
  • changeAmount is listed — the change the till gave back, as a number: 27.1 in the example above, 0 on methods that are not cash, null when the till did not send it. It already travelled in the events; it was missing from the reference.
  • If your consumer checked that customerCashAmount is a string, it now fails. Read it as a number. Events of orders injected before 24 September still carry "0", so a replay of an older order does too.
Updated in EN / ES / PT.

23 September 2026 — Catalog Agent user manual

New manual for anyone managing the catalog with the Catalog Agent, the AI chat that proposes product tags and applies them only with human approval.
  • Catalog Agent — how to chat or upload a file to tag products, which decisions the agent asks for (mode, new terms, aliases), and why an approval can come back partial when someone edits the product in the meantime.
Updated in EN / ES / PT.

16 September 2026 — cStat is emitted again, inside countryData

This supersedes what a later entry says. On 15 September we announced that cStat was no longer emitted. Consumers asked for it back — without it a cancellation does not say whether the authority accepted it — so it returns. Only cStat: docType, dataAutorizacao and sefazCancellation stay out.
  • Brazil: authority.countryData.cStat. The code the authority resolved this document with: 100 on an authorization, 135 on a cancellation. It is the authority’s own vocabulary, so it travels beside chaveAcesso and protocolo, not at the root of the block.
  • A cancellation carries its own code, not the invoice’s. order.reversed reads 135 — the cancellation event registered at SEFAZ — while the order.invoiced that preceded it keeps 100. Verified end to end in staging.
  • It travels as the provider sends it, number or string. We do not normalise a type the authority did not choose.
  • Through the fiscal callback it already worked: anything inside document that is not canonical reaches countryData untouched. Send cStat there and it arrives — no change was needed on your side.
  • mensagemSefaz stays out. Only the code comes back.
  • Rejections still emit no event. A rejected document stores its code but fires neither order.invoiced nor order.reversed, so cStat does not reach you for that case.
Updated in EN / ES / PT.

15 September 2026 — KDS bump printing, zoom, and Android Fire Agent

Kitchen print is now a store rule (comanda and/or fiscal on one station). Tablets need their own Fire Agent. Zoom and the operator reprint printer are separate from that rule.
  • Print on bump — By screen or By station, documents and fiscal timing. Arm the queue on the KDS screen. A dashboard alert fires if the print station has no active screen.
  • Screen actions — station/ticket zoom (timer double-tap, default key Q). If the printer fails after a fiscal-ready bump, the ticket shows Queued: printer failed.
  • Operator board — Operator fiscal printer on the supervisor PC (not the kitchen queue).
  • Android installation — APK on the KDS tablet. kds-agent.fire.rest must resolve to 127.0.0.1. Token and printer name must match fire-kds.
  • Stations / Routing — station item-type veto is gone. Categories live only in the routing strategy.
Updated in EN / ES / PT.

15 September 2026 — Cancellation dates and rejected documents

Two fixes to what the fiscal callback stores, and therefore to what order.invoiced and order.reversed carry. The event versions do not change.
  • A cancellation keeps the invoice’s dates. authority.issuedAt and authority.authorizedAt now stay as the invoice had them, even when the cancelled callback sends its own. Before, they took the cancellation’s time while compensates.issuedAt still pointed at the invoice, so the same block told two stories. Use authority.cancelledAt for when the document was annulled.
  • A negative outcome stores no receipt data. On rejected, denied and error, Fire ignores documentNumber, providerDocId, issuedAt, authorizedAt, the amounts, pdfUrl, xmlUrl and graphic even if the provider sends them; documentType, docSubtype, the country’s document keys, failure, provider and metadata are kept. A rejected document used to read like an authorized one, with a number and an authorizedAt on it. A document that already had receipt data keeps it.
Updated in EN / ES / PT.

15 September 2026 — Structured fiscal block and new fiscal event versions

The fiscal block of the three fiscal events is now what Fire stores on the order, with one shape for every country: the authority’s verdict in authority, plus the document’s journey and what it replaces. Two new guides explain the whole cycle.
  • Breaking — the fiscal block of order.invoiced, order.cancelled and order.reversed is structured. Canonical fields move into authority (documentType, documentNumber, issuedAt, cancelledAt…), amounts into authority.amounts, and the authority’s own identifiers (chaveAcesso, claveAcceso, cufe, protocolo…) into authority.countryData. dataAutorizacao becomes authority.authorizedAt; docType, cStat and sefazCancellation are no longer emitted. Every previous path has exactly one new path: see Path changes.
  • Breaking — on a cancellation the block moves from cancellation.metadata.fiscal to cancellation.fiscal, and cancellation.metadata is no longer emitted. When the order had no authorized document, the fiscal key is absent — before it was null, so a check for === null stops matching.
  • Breaking — the fiscal callback moved every canonical field out of document to the root (documentType, docSubtype, documentNumber, issuedAt, authorizedAt, cancelledAt, authorizationMode, providerDocId, totalAmount, taxAmount, currencyCode, pdfUrl, xmlUrl, graphic); document now holds only the country’s identifiers. Renames: countryCode → country, docType → documentType (SALE_INVOICE or CREDIT_NOTE, the only two accepted), error → failure (with scope and details), providerSpecific → metadata, emittedAt → issuedAt. A sender using the previous names receives 400 naming the field — for docType, on authorized and cancelled. In Ecuador numeroAutorizacion is retired: the authorized identifier is claveAcceso. cnpjEmitente is not part of the contract.
  • order.cancelled carries the fiscal block in every country with an authorized document; before it was Brazil only.
  • history and compensates — order.invoiced and order.reversed carry every stop of the document’s journey, oldest first. compensates points at the document the current one replaces, so it is filled on order.reversed and null on order.invoiced.
  • authority.providerIdentity and authority.providerMetadata — the callback’s provider and metadata now reach the order and the events, with the same names as in the fiscal numbering. null when not sent; PlugNotas (Brazil) never sends them.
  • How fiscal works in Fire — the two acts (numbering and authorization), the two blocks on the order, and the two ways a document reaches Fire.
  • From the callback to the events — which event fires for each callback and where every field lands.
Flows and handlers that read the previous paths — fiscal.chaveAcesso, fiscal.protocolo, cancellation.metadata.fiscal.* — read undefined on the new versions, without an error. Update them before relying on these events.
In Brazil authority.authorizedAt carries the SEFAZ date with a conventional midnight time, so it can read earlier than issuedAt. Use issuedAt for the moment of the sale.
Not backwards compatible for the fiscal block; the rest of the order snapshot is unchanged. The previous versions stay available from each event’s version tabs. Updated in EN / ES / PT.

4 September 2026 — Coupons on order lines

Orders can now arrive with coupons. order.completed carries who financed each discount, on the line and on the order.
  • orderLines[].rewardId — the coupon’s redemption code, or null. Selected modifiers carry it too: on a combo the discount usually sits on the modifiers, not on the container. Two shapes are both valid and neither is a bug: null with a discount (a catalog markdown, no coupon), and a code with discountValue: "0" (the coupon changed the list price instead of discounting it).
  • data.marketing.coupons[] — was reserved for future use; now carries { rewardId, name, metadata } per coupon. metadata.scope is product, order or shipping, and metadata.amount is the money it took off. A coupon with scope: "order" appears only here: its amount reaches the lines already spread across them, and nothing links the slices back to it.
On kiosk orders totals.discountValue is the total across every level — the order coupon and the per-line discounts together, because the source spreads the order coupon into the lines before sending. Adding it to the sum of orderLines[].discountValue counts the same money twice. Use one or the other, not both.
value in a coupon’s metadata is the rule’s nominal figure — a percentage, or points — not currency. The money is always amount. And baseValue: null means the list price is unknown, which is not the same as zero. Backwards compatible: both fields are additions on the existing shape, and rewardId is null on every channel that does not send coupons. Updated in EN / ES / PT.

3 September 2026 — KDS Fire credentials, ticket rows, and station categories

Kitchen print and cancel need the right Fire host and key. Ticket cards can now sit on one to three rows. Products get a routing category and a kitchen thumbnail.
  • Fire API credentials — account default vs vendor override. The base URL is the Fire host only; fire-kds appends print and cancel paths.
  • Station categories — codes used as item_type in routing, plus product thumbs on the category view.
  • KDS Fire credentials (technical) — vendor row → account default → env. Print reads FISCAL_PRINT_* only. Cancel may fall back to FIRE_*.
  • Screen actions — Ticket rows (1–3) reserve space for notes. If Fire rejects a cancel, the operator sees the rejection and the policy detail; the job stays failed.
Updated in EN / ES / PT.

3 September 2026 — The catalog: products, categories and modifier groups

Three new manuals for the screens that feed everything else. A menu invents nothing — it picks from the catalog — so this is where the work actually starts.
  • Products — the four types, the switches that decide whether something sells, price, modifiers, combos and suggestions.
  • Categories — the blocks customers browse with, their schedule, and channel exclusivity.
  • Modifier Groups — the questions asked at order time, and the options that answer them.
  • Modifier options are catalog products. To offer extra cheese there has to be an extra cheese product; its price is read from that product, never typed on the group.
  • You only set two numbers on a group: minimum and maximum. Required/optional and single/multiple are derived from them, so a group cannot contradict itself.
  • Channel exclusivity cascades. Marking a category exclusive takes it and its products out of the Golden Menu.
  • A combo has no pricing tab, and its listed price is a calculated reference, not what you charge. The real price comes from the destination’s price list.
The pricing tab is country-dependent: in Brazil it is simplified to the final price plus the fiscal category (NCM). Product variants are planned but have no screen yet.
Updated in EN / ES / PT.

3 September 2026 — Menus: building the menu and getting it to the channel

Two new manuals for the pair of screens that decide what is sold and where: the Golden Menu and the custom menus that inherit from it, and the matrix that puts each menu into each store, channel and fulfillment type.
  • Menus — Golden and custom, inheritance, the create dialog, the Structure and Overrides tabs, and the price and day lenses.
  • Menu assignment — the store x channel x fulfillment matrix, bulk assignment, Sync and its warnings, and the sync preview.
  • The fulfillment type is chosen once and cannot be changed. It is the only field on the menu with no way back: getting it wrong means creating the menu again.
  • Saving a menu does not publish it — there is no publish button in the editor. The menu reaches a channel only when somebody syncs the corresponding row on the assignment screen.
  • Sync flattens the menu fresh, with no versioning. It sends the menu and the price list exactly as they are saved at that second; an earlier state cannot be republished.
  • A row can end up Synced and still have dropped products. A product with no price in the assigned list is left out of the payload rather than published at zero, and only the warnings chip says so.
Aggregator channels receive their events, but their outcome is not yet reflected in the sync status on this screen. The menu History tab is also still empty.
Updated in EN / ES / PT.

2 September 2026 — Out of stock: turning products off during service

New manual for the Out of stock screen: taking a product off sale in one store when the kitchen runs out, without editing the menu and without anyone having to undo it later.
  • Out of stock — the turn-off dialog, scope by channel, the mandatory reason, restoring, and the Audit tab.
  • A turn-off never outlives the store’s closing time. The ceiling is the end of the store’s business day, not a fixed number of hours: a product turned off today is selling again when the store opens tomorrow.
  • Scope is a channel and fulfillment type pair. A product can be turned off for the kiosk while it keeps selling at the till.
  • As a combo option, the product stays selectable. If it is also sold inside modifier groups, the dialog names them and the turn-off records them, but channel availability is per product — there is nowhere to put an option in either contract.
  • The reason is mandatory and immutable. Changing the expiry moves the time only — the reason stays as the record of why the product was turned off.
  • Publishing the menu closes the turn-off — but only if it covered the whole scope. A store-wide turn-off survives a publication that reached one channel, because the others really are still out of sale. The outcome is Replaced by a sync.
  • A turn-off is saved even when the channel is not notified. Notifying is reported separately from saving, and turn-offs whose notification did not land are counted in the header and flagged on their row.
The turn-off does propagate to the sales channels: products/listing per product for X-Mart channels, and product.availability_changed per channel for the aggregators — in all three directions (turning off, restoring, expiring). The row stays as Fire’s operational record — what stopped being sold, when and why — and never enters the menu snapshot: that separation is deliberate, not a pending stage. What does not propagate are products sold only as a modifier option: neither contract has anywhere to put them.
Updated in EN / ES / PT.

15 August 2026 — The fiscal block: country identifiers, voiding and provider

fiscalRepresentation drops its fixed per-country fields and now carries the order’s current document, with the previous ones in history.
  • Breaking — sequential, serie and claveAcceso are no longer fields of the block. The authority identifiers now live in countryData, in the vocabulary of the country that numbered: claveAcceso, establecimiento, puntoEmision, secuencial and ambiente in Ecuador; numeroControl, numeroFactura and serie in Venezuela. Iterate the keys, do not index them: a channel reading countryData.claveAcceso outright works in Ecuador and breaks with the first country added. The fields that mean the same everywhere —documentNumber, issuedAt, authorizationMode, numberingStatus— did not move.
  • history and compensates — when a cancellation numbers, the credit note becomes the top document, compensates points at the invoice it voids, and the whole invoice moves down into history. Every history entry has the same keys as the block above, so they read the same.
  • environment — which environment Fire numbered in: SANDBOX or PRODUCTION. It is ours, not the authority’s; the authority’s still travels inside countryData with its own code.
  • providerCode, providerIdentity and providerMetadata — these used to be a single object mixing three things. providerCode is our adapter identifier; providerIdentity is the provider’s block (name, version, reference) and has a shape; providerMetadata is an opaque bag and you should not program against its keys. The numbering endpoint’s response now returns exactly the same three fields, under the same names.
If your reconciliation assumes documentNumber is always the sale’s, revisit it: after a cancellation the number on top is the credit note’s. What the customer walked away with is not lost — it is in history — but you have to go there for it.
Documented on order.opened, order.completed, order.cancelled, order.invoiced, order.reversed, in the endpoint reference and in the Integrating fiscalization guide. Updated in EN / ES / PT.

13 August 2026 — Fiscal numbering now travels in every order event

Orders numbered by the Fiscal Gateway before injection now carry those identifiers in every event of the order, so you no longer need a second call to print or reconcile.
  • data.fiscalRepresentation — series, sequential, document number, access key and the QR (graphic), exactly as printed at the till. The key always travels: it arrives as null when numbering was not attempted — aggregators, countries without fiscal representation, or numbering turned off — and carries the block when it was. Branch on the value (if (data.fiscalRepresentation)), not on the key’s presence. 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 — a charged sale left with no fiscal receipt arrives with null identifiers and the reason in failure. Carrying the block does not mean the document is authorized: the authority’s verdict stays in lastKnown.fiscal.status. The block itself never changes, even after the authority authorizes or rejects.
  • data.lastKnown.fiscal.sourceEvent — now reports real provenance instead of deriving it from the status. A processing seeded at injection used to be reported as fiscal.callback even though no callback had occurred; it now says order.injected. Account for the new value if you branch on this field.
  • Documented on order.opened, order.completed, order.invoiced and order.cancelled.
Updated in EN / ES / PT.

11 August 2026 — BOH API: qty_base derived server-side with item_unit_id

On purchase order lines (POST /procurement/orders, add-lines, and line update), qty_base is now optional when the line references item_unit_id — not only unit_code. The server derives qty_base = qty × factor_to_base from the referenced unit, so external integrators referencing a purchase unit by UUID no longer need to know or recompute its conversion factor. If you send an explicit qty_base anyway, BOH validates it against the derived value (tolerance 0.001) and returns purchase_order_qty_base_mismatch (422) on disagreement — same behavior as unit_code. If item_unit_id doesn’t resolve to an active unit and qty_base was omitted, the response is now the typed error item_unit_not_found (404). Updated in EN / ES / PT.

11 August 2026 — BOH API: store resolution by fiscal ID in purchase orders (Phase 19)

tax_id is now a first-class field on BOH stores (RUC, CNPJ, CUIT, NIT, RUT, RFC, or any fiscal code up to 64 characters). It is optional, not unique, and accepted in POST /identity/stores and PATCH /identity/stores/{id}. When creating a purchase order via the API you can now identify the receiving store with any of three mutually exclusive fields:
  • store_id — existing UUID (unchanged).
  • external_store_id — cross-system external identifier.
  • store_tax_id (new) — fiscal identifier. Returns 422 with purchase_order_store_tax_id_ambiguous if multiple active stores share the value (e.g. Ecuador RUC shared across branches) — use store_id or external_store_id in that case.
Combined with Phase 17–18 ERP fields, ERPs can now create purchase orders using only external identifiers — no internal UUIDs needed. Updated in EN / ES / PT.

11 August 2026 — BOH API reference restructured: one page per endpoint

The BOH API tab has been fully restructured into individual endpoint pages. Each endpoint now has its own menu entry showing the HTTP method (GET, POST, PATCH, DELETE), interactive request/response examples, and a Try it button to test the endpoint directly from the docs. The new structure covers all 63 endpoints across 6 sections: Identity, Catalog, Recipes, Operations, Procurement, and Webhooks. Updated in EN / ES / PT.

11 August 2026 — BOH API: purchase orders — supplier SKU resolution and external_user_id

Two additions to the purchase orders reference: supplier_sku on lines — a third item identifier for ERP integration. Instead of item_id or external_item_id, send supplier_sku (case-insensitive) and BOH resolves the item directly from the order’s supplier catalog, deriving base_unit_id automatically. Error: purchase_order_supplier_sku_not_found (404). external_user_id on create — the caller’s user identifier is now accepted when creating a purchase order and stored as actor_external_user_id. Previously the field was silently ignored. Updated in EN / ES / PT.

10 August 2026 — KDS manuals: device pairing, operator board, line strike, and display defaults

New and updated KDS user manuals covering recent fire-kds product work: Pair a kitchen device — new guide. Enroll kitchen TVs with a 6-digit code from KDS → All Stores, manage paired terminals, and understand device vs email sign-out. Operator board — new guide. Supervisor list/detail with live timers, filters, collect codes, and cancel / ready / dispatch overrides. Screen actions — line strike before bump, dispatch waiting for assembly, new-order alert, and richer display settings (store defaults, customer name by channel/fulfillment). Order display — fulfillment filters (e.g. hide delivery from the turnero). Overview — store-level KDS options (display defaults, line strike, cancellation reasons) and links to the new guides. Updated in EN / ES / PT.

7 August 2026 — BOH API: operations, identity, bulk sync, and procurement endpoints

The BOH API reference now covers the full set of endpoints needed to build a complete integration: Identity — new section. Discover your account context (GET /identity/me), list vendors, and fully manage stores and suppliers (create, update, archive/unarchive). Catalog: Bulk sync — new section. Three bulk PUT endpoints:
  • PUT /catalog/units — upsert units by code + unit_group_code; global units are skipped safely.
  • PUT /identity/suppliers — upsert suppliers by external_supplier_id.
  • PUT /catalog/classifications/assignments — replace all classification assignments for an item or store atomically.
Operations — new section. Covers all inventory movement types:
  • Goods receipts (create, list, get) — supports external_store_id and external_supplier_id so you don’t need to pre-fetch UUIDs.
  • Stock counts (create, list) — FULL or PARTIAL scope, with area_breakdown for collaborative field-count sessions.
  • Waste events (create, list) — lines by item, item tag, or subrecipe snapshot.
  • Transfers (create, list) — atomic debit/credit between stores.
  • Production batches (create, list, get) — records recipe execution with actual output and optional ingredient overrides.
  • Tracking transactions (get status, list) — poll any async write via its tracking_id.
Procurement — new section. Full purchase-order lifecycle (POST /procurement/orders with idempotency key, list/get, submit, confirm, add/update/remove lines, cancel, close, and fulfillment status), plus PUT /procurement/par-levels to upsert stock targets per item/store and GET /procurement/suggested-order to retrieve recommended reorder quantities. Purchase orders also support ERP integration via external identifiers: external_supplier_id, external_item_id, and unit_code resolve internal records server-side (no BOH UUIDs needed), external_reference tags the order with your document code (filterable on the list endpoint), and lines accept informational amounts (tax_amount, delivery_amount, total_amount, markup_amount). Updated in EN / ES / PT.

7 August 2026 — BOH manuals: channel-scoped recipe lines, collaborative counts, account currency

Three updates to the BOH user manuals reflecting recent product changes: Recipes — channel-scoped lines (Phase 16) The “Service complements” model has been replaced by channel-scoped lines on a single recipe. Each recipe line now has an optional service_codes field:
  • Lines without service_codes are general and always apply.
  • Lines with service_codes: ["DELIVERY"] only apply when the order’s channel matches.
  • A single published recipe per product and store replaces the old BASE + COMPLEMENT pair.
Updated: Recipes — Channel-scoped lines. Stock counts — collaborative field-count sessions New section documenting field-count sessions: multiple devices can count different inventory areas of the same store simultaneously. Each device claims an exclusive area, counts it, and marks it ready. The admin device finalizes the session, which creates a normal stock count. Updated: Stock counts — Collaborative counting sessions. Catalog — account currency New section documenting the account currency setting. Each BOH account now has a default ISO 4217 currency (set in Account & access → Account settings) used across procurement costs, supplier item prices, and reports. Updated: Catalog — Account currency. Updated in EN / ES / PT.

7 August 2026 — Price lists: new user manual

Price lists let you run different prices per channel, location or campaign without maintaining each one by hand. The manual is now available: Price lists.
  • Connected lists — a list can follow a base list. Change the price once and it reaches all of them; any product that needs its own price sets one and stops following, just for that product. Formulas like =P*1.15 stay live: when the base moves, the list recalculates itself.
  • Contextual prices — the same product can be worth a different amount inside a combo. Those prices used to be buried in each combo’s configuration; they’re now visible and editable from the product row, with the percentage against the standalone price.
  • Bulk edit with commercial rounding — apply a percentage or amount to many products at once, reaching the prices inside combos too, and round to .99, .90 or a whole number so you don’t end up selling at 13.42.
  • Comparison mode — overlay another list as a reference to see, product by product, where the two diverge.
  • Blast radius before saving — a summary of which connected lists receive the change and, more importantly, which one gets nothing because every product you touched has its own price there.
  • Connecting an existing list — a list that was born as a copy and drifted can be connected to a base list. Whatever matches the base starts following it, whatever has its own price stays put: no price moves at the moment you connect.
Time-based pricing (day-parting) is not available yet, and this phase works on the final price with taxes included — net price and reference price come later. The manual states both limits explicitly.

6 August 2026 — Component health heartbeats for kiosks, KDS and POS

Kiosks, KDS stations and POS terminals can now report that they are alive, and Fire’s availability dashboard reads the fleet from those beats. The endpoint is POST /external/component-health and needs an API key with the component-health:write scope.
  • Component health — one beat per cycle with componentType, componentId, storeId and status. Optional sentAt, offlineSince, degradedReason, appVersion and a free-form details. Answers 204 No Content.
  • X-Heartbeat-Interval — every 204 carries the cadence in force, in seconds. Adopt it on the next cycle: that is how the interval is reconfigured without shipping a release.
  • A componentId must be stable — if it changes between reboots, Fire sees a different component: the old one is retired after 7 days and the new one starts with no history.
  • degradedReason uses a shared vocabulary — printer_down, pinpad_down, backend_unreachable, queue_backlog, peripheral_other. The details keys for kds_station are still to be agreed with the KDS team.
status accepts only online and degraded. There is no down: a device cannot declare itself dead — Fire infers the outage from the missing heartbeat, after two missed intervals.

4 August 2026 — New assignedAt field on menu and product events

menu.updated v2 and product.updated now carry assignedAt on every category and product.
  • categories[n].assignedAt and products[n].additionalInfo.assignedAt — the date the entity joined the menu, ISO 8601 UTC, no milliseconds. It’s membership data, not edit data: untouched by price, name, image, or order edits; gets a new value when an item is removed from the menu and re-added. Full edge cases in menu.updated → Menu assignment date. Not carried by product.price_updated or product.availability_changed — they only ship their delta.
  • menu.updated / product.updated use taxInfo (not taxesInfo), type: PRODUCTO for standard items, and modifierGroups[n].type: RADIO for single-select groups (CHECKBOX for multiple).
  • storeId is the store’s internal UUID (stores.id), not the store_number — same convention across menu.updated, product.updated, product.price_updated, and product.availability_changed.
  • product.price_updated’s priceInfo doesn’t share a shape with the catalog priceInfo in menu.updated / product.updated — it’s the sale price just saved with its discount, not catalog pricing.
channelReferenceName means the fulfillment (delivery, pickup) in menu.updated’s list.stores[n].channels[n], but the sales channel (iFood, Rappi) in the same field name on product.updated, product.price_updated, and product.availability_changed. Same key, two different things depending on the event.
Updated in EN / ES / PT.

4 August 2026 — Subscribe to the changelog by email

You can now get an email whenever a new entry lands on this page. Subscribe from the button at the top — Buttondown handles the list, so no address is ever stored in the docs, and one click unsubscribes you from any email.
  • One email per entry, in all three languages — English, Español and Português arrive stacked in the same message, so there is nothing to pick.
  • Only a new entry sends — correcting a typo in something already published never re-sends it.
Updated in EN / ES / PT.

2 August 2026 — order.opened and the deferred-payment blocks

Each event advances on its own version line — there is no global contract number: Every addition is backward-compatible (new blocks on an existing shape). Nothing here changes a field you already read, and the previous contract of each event stays online behind its version tab.
  • New event order.opened — fires when an order is injected already open: it exists, the kitchen can start, nobody has paid yet. Carries the same V4 snapshot as order.completed. It does not fire for orders injected as COMPLETED or CANCELLED. This event has no v0 — it was born at v1.
  • data.policy.deferredPayment — added to all four order events (order.opened, order.completed, order.invoiced, order.cancelled). Says whether the order may be cooked, invoiced or dispatched before payment. Resolved once at injection and stamped immutably; every later event echoes the same value.
  • data.lastKnown — added to the same four events. Advisory snapshot of kitchen and fiscal state. Never gate an irreversible action on it — it may be null or stale, and Fire itself ignores it and re-reads from source before issuing anything.
On order.opened, payments.paymentMethods[] is what the POS declared, not what was charged — transactionStatus is PENDING and transactionId is usually empty. Fire overwrites the array with the real tenders when the charge settles, and emits order.completed. Reading the declared method as settlement evidence is the most common mistake with this event.
Updated in EN / ES / PT.

22 July 2026 — BOH user manuals

Added a BOH section to the User manuals tab covering back-of-house inventory administration from the Fire backoffice:
  • Overview and concepts — how catalog, recipes, procurement, movements, counts and reports fit together; the stock flow; map of the BOH menu.
  • Stores and suppliers — BOH stores linked to Restaurant OS and supplier records with item-supplier links (price, purchase unit, SKU).
  • Catalog — unit groups and units, items, interchangeable item tags (FIFO / FEFO / priority / highest stock), classifications.
  • Recipes — sales, production and subrecipes; draft → published → archived lifecycle; channel-scoped lines; sale simulator.
  • Procurement — receiving schedules, purchase order lifecycle, par levels and suggested orders.
  • Receipts and returns — goods receipts (stock entry, PO linking, over-receiving) and supplier returns.
  • Waste and internal consumption — waste reasons catalog, waste events, internal consumption.
  • Transfers and production — transfers between stores and production batches with yield.
  • Stock counts — inventory areas, full/partial counts, and the mobile counting app.
  • Reports — usage, waste, production yield, and balance at a date.
All 10 pages published in EN / ES / PT.

13 July 2026 — Cancel Order: cancellationType field

Added optional cancellationType (string) to the Cancel Order request body. When provided, the cancellation reason ID or code from the catalog is persisted on the order and reported to the payment gateway. Updated in EN / ES / PT.

3 July 2026 — Inject Order: combo discount distribution

Added a new Combo discounts section to the Inject Order reference. When a COMBO product has a container price of 0, the combo’s discountsValue must not be placed on the container line (this produces negative totals). Instead, distribute the discount proportionally across the selectedModifiers:
  • discount_i = ROUND(D × (base_i / B), 2) — proportional share per modifier
  • Every modifier must keep subtotalIncludeDiscounts >= 0 and total >= 0 after the discount
  • The COMBO container must have all price fields at 0
  • SUM(modifier.totalPrice.discountsValue) must equal the combo’s total discount
Includes a before/after JSON example (BRL 17.94 discount over a 7-item combo, base BRL 89.68) and a full breakdown table. Updated in EN / ES / PT.

29 June 2026 — KDS user manuals

Added a KDS section to the User manuals tab covering both operator and backoffice administration:
  • Overview and concepts — how stores, stations, screens, routing, devices and printing fit together; two station types (production vs convergence); kitchen patterns (assembly-only, KITCHEN, multi-station).
  • Set up a store — apply a template (blueprint wizard) or configure from scratch; step-by-step order.
  • Stations — fields, optional station rules by channel / service / item type, step-by-step creation.
  • Screens — device identifier, create and assign stations, screen ↔ station relationship.
  • Routing — decision layers (routing → rules → distribution → convergence), distribution modes, multi-station example.
  • Peripherals, printing and validation — keyboard layouts, ready-pickup printing (one screen per store), order cancellation, go-live checklist and reference routes.
  • Screen actions — bump, hold/unhold, undo, cancel, pagination, settings menu and keyboard shortcuts.
  • Order display — customer-facing waitlist screen (preparing / ready areas, hero on ready, auto-pagination).
All 8 pages published in EN / ES / PT.

22 June 2026 — New guide: Products structure · Menu publication updated

New guide: Products structure

New Products structure page in the Guides tab — covers the COMBO type and modifier overrides:
  • COMBO type — priceInfo.price is always 0; use priceInfo.referencePrice as the product header price.
  • Reference price — sum of (cheapest option × minOptions) across every required modifier group (minOptions ≥ 1).
  • Modifier overrides — productModifiers[n].overrides sets a different price for an option inside a specific combo; takes precedence over the option’s base price in products[].
  • Delta pricing — required groups show +R$ X above the baseline; optional groups show the full add-on price.
  • Removed the menus.sync section — that event no longer exists.
  • Fixed the payload format: event is now a nested object (id, type, executionId, createdAt), not top-level fields.
  • The signature verification step now specifies that the signing secret is obtained under Aggregator integrations in the Fire dashboard.
  • Added a menu structure section describing list, categories, products (type table), and modifierGroups.
Updated in EN / ES / PT.

15 June 2026 — order.completed — new payment method fields

Added 4 fields to payments.paymentMethods[n] in the order.completed event. All fields are nullable and already live in production.
  • idAuth (string | null) — Authorization ID from the payment processor (e.g. SiTef IdAuth). Distinct from authorizationCode.
  • receiptCustomer (string | null) — Full customer-facing receipt text; may be multi-line.
  • receiptMerchant (string | null) — Full merchant-facing receipt text; may be multi-line.
  • acquirer.cnpj (string | null) — Tax ID (CNPJ) of the payment acquirer — Brazil only.
Updated in EN / ES / PT.

15 June 2026 — Payment method details fields

Added 5 optional fields to payments.paymentMethods[n] in Inject Order:
  • id_auth (string | null) — NFCE authorization number (SiTef 952 / IdAuth).
  • receipt_customer (string | null) — Customer receipt copy: printed receipt text for the cardholder (SiTef 121 / ReceiptCustomer).
  • receipt_merchant (string | null) — Merchant receipt copy: printed receipt text for the store (SiTef 122 / ReceiptMerchant).
  • acquirer.cnpj (string) — Acquirer CNPJ for NFCE (SiTef 950 / CNPJAuth). acquirer itself is now documented as nullable — send null for methods without an acquirer.
  • card.media (string) — Card read method: CHIP, MAGNETIC, NFC, MANUAL (SiTef 2090 / Media). card is now documented as nullable — send null for non-card methods.
All fields are optional and already implemented in the validator. Updated in EN / ES / PT.

14 June 2026 — Aggregator order-status webhook

  • New inbound webhook POST /v1/webhooks/aggregators/order-status — your delivery aggregator (Rappi / Uber / Didi / iFood / PedidosYa / Glovo…) POSTs the order’s delivery status as it advances (courier_assigned → on_route → delivered…). Fire mirrors the latest status onto orders.aggregator and logs every event.
  • Status is passthrough — no enum is imposed; the aggregator’s own labels are stored verbatim, and the current status is the one with the latest occurredAt (no anti-regression gate). Friendly translated labels are resolved at display time from the channel catalog.
  • Flexible order resolution — send orderId (Fire UUID) and/or externalOrderId (your reference, matched on metadata.order_id); at least one is required, both vendor-scoped. If both are sent and resolve to different orders → 409.
  • No Fire-emitted eventId to echo — an aggregator status is a spontaneous external event (Fire is not the source of truth here). Idempotency is keyed on (channelCode, providerEventId) + status; channelCode must equal the order’s metadata.channel.code.
  • Auth: vendor-scoped API key with the new webhooks:aggregator scope. Async 202 + queue, same envelope as the fiscal / KDS callbacks.
  • Documented in EN / ES / PT.

12 June 2026 — Aggregator discounts in Inject Order

Documented how to send aggregator platform discounts (iFood, Rappi, UberEats, etc.) in the Inject Order endpoint.
  • Aggregator discounts are a payment method, not a discount row. When an aggregator applies a promotional discount to the customer, the store receives the full amount and the aggregator reimburses the difference — model it as an extra entry in payments.paymentMethods[] with paymentMethodCode: "AGGREGATOR_DISCOUNT", transactionType: "BENEFIT", processor set to the aggregator name, and card: null.
  • payments.discounts[] stays empty for aggregator discounts — that array is only for store-absorbed promos/coupons.
  • New balance rule documented: SUM(paymentMethods[].totalBill) must equal products + extra charges + shipping.
  • New request example with an iFood order (BRL 38.69 CREDIT + BRL 1.00 AGGREGATOR_DISCOUNT = BRL 39.69 gross).
  • Updated in EN / ES / PT.

11 June 2026 — Underscore nomenclature + lean day-close payload

  • Naming (breaking) — store.day-closed → store.business_day_closed and order.status-updated → order.status_updated (underscore nomenclature). Update your event.type switch.
  • store.business_day_closed is now a thin payload — close identity (businessDayId, businessDayDate, timezone, status), timing (openedAt/closedAt), closedBy, and a minimal store (uid, code, externalId, countryCode, timezone, currencyCode). Removed from the event: sales, metrics, summary, byChannel, byPaymentMethod, forceClosedOrders, closureStats, cancelledOrders, metadata — query them by businessDayId when needed. snapshotId renamed to businessDayId (same value).
  • Documented in EN / ES / PT.

10 June 2026 — Canonical order events + kitchen event

Fiscal events drop the country from the name and become canonical order events — still the v1 contract, only the event.type changes:
  • fiscal.authorized.br → order.invoiced and fiscal.cancelled.br → order.reversed. If your integration dispatches on event.type, update your switch — the payload shape does not change.
  • They now fire for all countries: Brazil (SEFAZ via your fiscal provider) and CO/EC/CL/AR/VE via the generic fiscal callback. The country travels in fiscal.countryCode.
  • New event order.status_updated — the KDS advances the order in the kitchen (preparing → ready → dispatched), with a kitchen block and the full journey in history.
  • Fire is the source of truth — inbound webhooks (fiscal callback, KDS statuses) now validate that eventId references an event Fire emitted for that order; otherwise they respond 400 before the 202. Always echo the event.id of an envelope you received.
  • Documented in EN / ES / PT.

9 June 2026 — Event contract v1

The order/fiscal/day-close event contract is now officially v1. All additions are backward-compatible (new optional fields); the previous shape is preserved as v0 (deprecated, historical) — switch with the version selector at the top of each event page.
  • Discounts — order- and product-level discounts now travel as a structured Discount object (priority, type FIXED/PERCENTAGE, value, net_price, discount_value, net_price_after_discount) in payments.discounts, payments.totals[].discounts, orderLines[].price.unitPrice/totalPrice[].discounts and orderLines[].lineTotals[].discounts.
  • Granular taxes — taxes[] now carries the BR tax-reform taxes IBS_UF, IBS_MUN, CBS alongside ICMS/PIS/COFINS, each with reform metadata (cClassTrib, reducao, rateNominal, rateEffective) in addition to cst/cBenef. The breakdown is uniform across countries — LATAM carries its local IVA in the same taxes[] shape; only SEFAZ emission (metadata.fiscal, fiscal.*.br) is BR-only.
  • itemType — full enum documented: PRODUCT / COMBO / MODIFIER / PACKAGING, with the meaning of each.
  • fulfillment.delivery.deliveryConfirmationCode — aggregator delivery/pickup confirmation code (e.g. iFood / Rappi).
  • payments.shippingCost / extraCharges — documented as PriceBlock rows (same shape as totals[]).
  • store.business_day_closed — sales now includes product_discounts, gross_before_discounts, shipping, extra_charges, total_charged, and taxes_by_type (per-tax breakdown with an OTHER reconciliation bucket). (Superseded 11 June — these aggregates are no longer embedded in the event; the day-close payload is now thin. See the entry at the top.)
  • order.cancelled / order.invoiced / order.reversed — carry the v1 order snapshot (they reference order.completed / order.cancelled).
  • All of the above documented in EN / ES / PT with updated examples.

8 June 2026

  • menu.updated: productModifiers[n].overrides[] added — allows setting a different price for a specific modifier option when it belongs to a particular product. Each override targets one productId and provides its own priceInfo.price and priceInfo.salePrice. EN/ES/PT updated.

5 June 2026

  • menus.sync: page removed — Fire sends a single menu.updated event per menu; batch sync is no longer a separate event.
  • menu.updated: event.timezone field removed from the payload. data.groupId added — a UUID that identifies the synchronization batch; multiple events emitted together share the same value, allowing downstream systems to correlate them. Category and product schedules arrays now include full 7-day examples showing different time windows per category (e.g. Burgers 11:00–23:00, Breakfast 07:00–11:00). standardTime field on products documented: true inherits menu-level schedules, false means the product has its own schedules array. EN/ES/PT updated.
  • Inject order: type is now required on every order.products[] item, every selectedModifiers[] item, and every payments.extraCharges[] item. Accepted values: COMBO (product with non-empty modifier groups), PRODUCT (simple sellable product or sellable modifier option), MODIFIER (pure modifier option), PACKAGING (packing-cost item). Payloads that omit type are invalid. Request examples updated in EN/ES/PT.
  • Inject order: shippingMethod.delivery.additionalInfo.deliveryConfirmationCode documented as an optional string for delivery verification codes.

1 June 2026

  • Inject order: new Amounts and price bands and Shipping and discounts sections; three reconciled request examples (simple delivery, line discount + shipping, multi-product + order discount); emphasis on payments.shippingCost[], payments.discounts[], and product discountsValue (EN/ES/PT).

27 May 2026

  • menus.sync: payload example completed (categories, products, modifier groups, schedules); data.menus[] replaced with data.menu (one menu per event); EN/ES/PT pages in webhook reference.
  • menu.updated: general structure aligned with menus.sync — catalog fields (list, categories, products, modifierGroups, scheduledActivities) nested under data.menu; field tables and delete example updated.
  • Menu publication guide (EN/ES/PT): examples and processing steps updated for data.menu.
  • Inject order: optional comment field documented on order.products[]; request example updated (replaces productComment).
  • menu.updated / menus.sync: modifier option productId values must exist in products; example includes prod_size_small and prod_size_large.
  • menu.updated: main payload example indentation fixed under data.menu.
  • Menu webhooks (menu.updated, menus.sync, product.updated): data.country documented and exemplified as ISO 3166-1 alpha-2 (e.g. EC, BR, CO) instead of a numeric country ID.

26 May 2026

  • Added User manuals as a top-level navigation tab.
  • Added FIRE POS V2 manuals for Linking, Cashiers, and Authorization codes in English, Spanish, and Portuguese.
  • Added subtle placeholder images for pending POS screenshots so the guides keep their final visual structure while captures are prepared.
  • Inject order: removed order.stock from the request body (not part of the contract). 200 response example updated to the real envelope (data, isArray, status, method, pathname, duration, traceId).
  • Login (playground): authMethod: none, absolute staging URL in the api: frontmatter, default Content-Type and default grant_type to avoid Missing required fields when using Try it.
  • Inject order: product line price documented with full price band fields and taxes[] (name, rate, amount, optional metadata).
  • Inject order: payments.shippingCost[] and payments.discounts[] documented as the same price-band rows as totals[]; request example updated with sample shipping and discount lines.
  • Cancel order: API reference updated to the aggregator route POST /api/v4/integrations/sales/aggregator/orders/{order_uid}/refund, with refund/cancellation request fields and standard response envelope; moved under Inject order in the API reference.

11 May 2026

  • New Changelog tab (last in the nav) with this page.
  • Removed the List sales channels page and its sidebar entry (all locales).
  • API reference intro: copy adjusted; removed the sales channels card.
  • Inject order: documented the Authorization header (EN). ES & PT: path, headers, and body updated to the current aggregator contract (channel/service objects, device and operator fields, examples).
  • Login (ES & PT): aligned with POST /api/authentication/login and the client-credentials response (accessToken).
  • Spanish homepage (/es/): content updated.
  • Configuration: new Aggregator integrations guide (Fire dashboard: webhook endpoints and test events).