Menu sync status
API
Menu sync status
Inbound endpoint your integrator POSTs to when it finishes publishing a vendor’s menu/products downstream. Fire finalizes the vendor’s pending sync logs and recomputes the menu’s sync status. One status per vendor by default (all-or-nothing), unless you send eventId to target a single aggregator assignment.
POST
Menu sync status
This endpoint is inbound: your integrator (the system that publishes Fire’s catalog downstream, an aggregator, an XMART client, a POS, etc.) POSTs to it once it finishes the asynchronous publish of a vendor’s products. Fire authenticates the request, resolves the vendor, finalizes every sync log that was left pending for that vendor, and recomputes the affected menu’s
syncStatus. This is the callback that closes the loop opened by a menu/products publication event carrying autoPublish.
This endpoint is synchronous. Fire authenticates, resolves the vendor, finalizes the pending sync logs, recomputes the menu status, and returns
200 OK with the number of rows it flipped (updated). There is no queue and no polling; unlike the aggregator order status and KDS webhooks, the work is done before the response returns.The correlation id is optional. If you send
eventId (aggregator channels only), Fire closes only that assignment’s sync-log row. If you omit it, the only key is vendorId, and Fire applies the result to all of the vendor’s pending sync logs for the entity resolved from type (all-or-nothing): if the vendor had several assignments and only some failed, you still send one FAILED, and every pending row for that vendor goes to FAILED, because without eventId Fire cannot tell which assignment failed. In that case, correctness relies on Fire’s per-vendor lock, since there is never more than one publish batch pending for a vendor at a time. See Correlation & the vendor lock.Authentication
This endpoint requires a vendor-scoped API key with thewebhooks:xmart scope (account + vendor binding). Fire enforces that the vendorId in the body belongs to that vendor. Keys without the scope, or without a vendor binding, are rejected with 403 Forbidden.
string
required
Your Fire vendor-scoped API key with scope
webhooks:xmart. Generate one from Developers → API Management for the account/vendor whose sync results this key may report.string
Optional
Bearer <token>, accepted as a legacy alternative to x-api-key. Send one or the other.Request body
string
required
The vendor identifier in dotted form (e.g.
100.6.1350), the same value Fire uses on the sync logs and stores. It must belong to the vendor bound to your API key.Outbound publication payloads carry the numeric legacy vendor id (e.g.
1350) inside list. This callback is different: send the dotted id.string
required
Which entity your integrator published. Compared case-insensitively.
PRODUCTSfinalizes both the menu and the product dimensions of the vendor; the menu sync pushes products downstream, and your integrator reports the outcome asPRODUCTS.- Any other value (
STORES, …) finalizes only that entity’s pending rows.
string
required
The publish result for the vendor. Enum:
SUCCESS | FAILED.string
Optional detail (failure reason, provider trace). Stored on the finalized rows as the error detail when
status is FAILED; ignored (and cleared) when status is SUCCESS. If omitted while status is FAILED, Fire stores a generic default failure message instead.string
The
event.id from the Fire envelope your integrator received for this assignment (menu.updated / product.updated), format evt_<12 hex> (e.g. evt_9f2c41ab77de). One per assignment (store × channel × fulfillment).When present, Fire closes only the sync-log row for that assignment, instead of sweeping every pending row for the vendor. Aggregator channels only: omit it for other integrators, which get the vendor-wide sweep described above.type — what gets finalized
Examples
PRODUCTS — publish succeeded
PRODUCTS — publish failed (with detail)
PRODUCTS — aggregator channel, single assignment failed (eventId)
What Fire does
Once authenticated and resolved, Fire, in a single synchronous pass:- If
eventIdis present, resolves the single pending sync-log row that matches it, guarded byvendorId. Otherwise, resolves the affected entities fromtype(PRODUCTS→ menu and products; any other → that entity only) and targets every pending row for the vendor across those entities. - Finalizes the resolved row(s): sets the
statusyou sent, stamps the completion time, and recordsmessageas the error detail whenFAILED. The number of rows flipped is returned asupdated. - If no rows were pending, it is an idempotent no-op →
200withupdated: 0. - Recomputes the affected menu’s
syncStatusfrom its finalized rows:- any dimension still pending →
PENDING - all terminal and all succeeded →
SYNCED - all terminal and any failed →
FAILED
- any dimension still pending →
- Finalizing the rows releases the vendor lock: there are no more pending rows for those entities, so the next publish batch for the vendor can start.
Response
On success the endpoint returns200 OK with the number of sync-log rows it flipped, wrapped in Fire’s standard success envelope. A 200 means the work is done: the logs are finalized and the menu status is recomputed.
boolean
Always
true on a 200 response.boolean
Always
true when the request was processed.number
How many pending sync-log rows were finalized. Without
eventId, this can be any count across the vendor’s pending rows; 0 on an idempotent no-op. With eventId, it’s 0 or 1: at most the one assignment row that matched.A failure while finalizing rows or recomputing the menu status comes back as
400 DOMAIN_ERROR, not 500, even though it’s a server-side failure (e.g. a transient database error). See Idempotency & retries: a naive “retry only on 5xx” policy will not retry this case.Idempotency & retries
The callback is safe to re-run. It keys off the vendor’s pending rows, so:
The endpoint is safe to re-run in all of these cases: a retry after a successful finalize is a clean no-op (
updated: 0), and a retry after DOMAIN_ERROR re-attempts the same finalize.
Correlation & the vendor lock
WitheventId (aggregator channels): Fire matches the row directly by that id, guarded by vendorId. No ambiguity: the callback closes exactly the assignment it refers to.
Without eventId: the only key is vendorId. Fire relies on a per-vendor lock: while a publish batch is in flight, the vendor’s rows are pending and no second batch can start, so all pending rows for the vendor belong to the batch this callback finalizes.
Relation to the publication flow
This callback is the counterpart of theautoPublish flag Fire sets on the last publication request per vendor in a menu/products publication event. That flag tells your integrator to publish the batch downstream; when the publish finishes, your integrator reports the outcome here so Fire can finalize the sync logs and recompute the menu’s syncStatus.
Related
Menu publication
The publication flow this callback closes: how Fire emits the menu/products a vendor must publish.
Aggregator order status
The sibling inbound webhook for delivery status, same auth model, but asynchronous (queue + polling).
Menu updated
The outbound menu publication event carrying the catalog to publish.
Authentication
How API keys, scopes, and vendor binding work.

