Skip to main content
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 the webhooks: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.
  • PRODUCTS finalizes both the menu and the product dimensions of the vendor; the menu sync pushes products downstream, and your integrator reports the outcome as PRODUCTS.
  • 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:
  1. If eventId is present, resolves the single pending sync-log row that matches it, guarded by vendorId. Otherwise, resolves the affected entities from type (PRODUCTS → menu and products; any other → that entity only) and targets every pending row for the vendor across those entities.
  2. Finalizes the resolved row(s): sets the status you sent, stamps the completion time, and records message as the error detail when FAILED. The number of rows flipped is returned as updated.
  3. If no rows were pending, it is an idempotent no-op200 with updated: 0.
  4. Recomputes the affected menu’s syncStatus from its finalized rows:
    • any dimension still pending → PENDING
    • all terminal and all succeeded → SYNCED
    • all terminal and any failed → FAILED
  5. 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 returns 200 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:
Retrying only on 5xx is not enough. The most likely transient failure, Fire finalizing the rows, comes back as 400 DOMAIN_ERROR, not 500. Retry on that code too. 400 VALIDATION_ERROR is the one 400 you should not retry: it means the body itself is invalid.
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

With eventId (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.
The lock is indefinite: only a finalizing callback releases it. If the callback never arrives, the vendor stays locked (its next publish cannot start) until manual intervention. Always send the callback, even on FAILED.

Relation to the publication flow

This callback is the counterpart of the autoPublish 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.

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.