Skip to main content
POST
KDS order status
This endpoint is inbound — your Kitchen Display System (KDS) POSTs to it whenever an order advances in the kitchen: the kitchen started preparing it, it became ready for hand-off, or it was dispatched (delivered / picked up). Fire authenticates the request, correlates it to the order, applies idempotency and an anti-regression gate, and records the event in its KDS event log for observability.
This endpoint is asynchronous. Fire authenticates, runs the source-of-truth + tenant guard, deduplicates, and enqueues the event — then returns 202 Accepted with a webhookEventId (typically under 100 ms). The event is recorded a moment later by a background worker (usually within ~2 seconds). To check the outcome, poll GET /v1/webhooks/events/{webhookEventId}. Client-fixable problems (bad payload, wrong eventId, wrong tenant) are rejected synchronously with 4xx before the 202.
One dispatch event, several status reports. Unlike the fiscal callback — where each action carries its own eventId — the KDS reports the whole journey (preparingreadydispatched) against one eventId: the id Fire emitted when it dispatched the order to your device. They are distinguished by eventType, not by eventId. See Idempotency & the journey.

Event types

The KDS lifecycle has a strict order — an order is prepared before it is ready, and ready before it is dispatched: Values are lowercase, dotted (order.preparing, not ORDER_PREPARING).

Authentication

This endpoint requires a vendor-scoped API key with the webhooks:kds scope (account + vendor binding). Fire enforces that the order belongs to that account and 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:kds. Generate one from Developers → API Management for the account/vendor whose orders this key may report on.
string
Optional Bearer <token> — accepted as a legacy alternative to x-api-key. Send one or the other.

Request body

string
required
The KDS lifecycle event. One of order.preparing, order.ready, or order.dispatched (lowercase, dotted).
string
required
Your KDS’s own id for this delivery. Stored for audit/forensics — it is not the idempotency key. Fire deduplicates on (orderId, eventId, eventType), so you may send a fresh providerEventId on every retry. Use your KDS-native event id if available; otherwise a UUID.
string
required
ISO 8601 UTC timestamp of when the event happened in the KDS — not when it was sent.
string
required
UUID of the order in Fire. Matches data.orderId in the order events. Fire correlates the event to this order; it must already exist.
string
required
Correlation UUID — the event.id of the envelope Fire emitted when it dispatched the order to your device. Echo it exactly; never invent it.
  • Source-of-truth check. An eventId that does not reference a Fire event for that order is rejected with 400 before the 202.
  • One eventId for the whole journey. Send the same eventId for preparing, ready, and dispatched of that dispatch — they are told apart by eventType. (Each dispatch to a different device carries its own eventId, so two devices never collide.)
string
Optional originating KDS station (e.g. Hot line, Despacho 1). Stored for observability.
object
Optional free-form bag of extra fields. Stored as-is, not validated.

Examples

The three reports of the same dispatch share one eventId (the dispatch’s) and differ only by eventType and providerEventId:
order.preparing
order.ready
order.dispatched

Response

On success the endpoint returns 202 Accepted — the event was authenticated, validated, deduplicated, and enqueued. A 202 does not mean the event was recorded yet; that happens asynchronously. Use the status endpoint to confirm. The body carries two distinct ids: eventId is the id you sent (echoed), webhookEventId is Fire’s id for the queued record. Same shape as the fiscal callback.
boolean
Always true when the request was accepted and enqueued.
boolean
true when this exact (orderId, eventId, eventType) was already ingested — the existing record is returned and nothing is re-enqueued. false for a fresh report (including a different eventType of the same dispatch — that’s a new step, not a duplicate).
string
Echo of the eventId you sent (the dispatch’s event.id).
string
Fire’s id for the queued record. Pass it to GET /v1/webhooks/events/{webhookEventId} to poll the outcome. On a duplicate it is the same id returned the first time.
string
Current queue status — queuedprocessingprocessed (and retry / failed / dead / ignored).
string
ISO 8601 UTC timestamp of when Fire first received this report. Stable across retries.
string
Human-readable summary.

Checking the outcome

Because processing is asynchronous, the 202 only confirms the event was queued. To see whether it was recorded, poll the companion status endpoint with the webhookEventId returned by the 202:
string
Queue lifecycle: queuedprocessingprocessed (done) · failed / dead (gave up after retries) · retry (waiting for the next attempt) · ignored (handled, no action needed — e.g. a duplicate or non-advancing event).
number
Processing attempts so far.
object | null
On success, the worker outcome — e.g. { "kind": "recorded" } (advanced the order) or { "kind": "ignored" } (non-advancing).
object | null
{ "message": "…" } when the last attempt failed; null otherwise.
A 404 is returned for unknown ids — or ids that belong to another tenant — with no existence leak. Authenticate with the same webhooks:kds key you used for the event.

Idempotency & the journey

Fire deduplicates on the triple (orderId, eventId, eventType)not on providerEventId (which you may regenerate freely). This is what makes the journey work:
This is the key difference from the fiscal callback. There, one eventId carries exactly one action, so reusing it for a different eventType is a conflict (409). Here, one dispatch eventId legitimately carries the whole journey (preparingreadydispatched) — the eventType is what tells the steps apart. Different devices get different dispatch eventIds, so their reports never collide.

Anti-regression

The order state must never move backwards. Fire tracks the highest stage reached by the order (order.dispatched > order.ready > order.preparing) and compares each incoming event against it:
  • An event that advances the order (e.g. order.ready after order.preparing) is recorded as the new state.
  • An event that does not advance — a regression (e.g. order.preparing arriving after order.ready) or a same-state repeat — is still recorded for observability, but flagged as non-advancing with a reason, and it does not move the order back.
This makes the endpoint safe against out-of-order or late deliveries: send events in any order and Fire keeps the order at its most advanced stage.

Inject order

The order injection endpoint that creates the order this event references.

Fiscal callback

The sibling inbound webhook — same async + idempotency + correlation model.

Authentication

How API keys, scopes, partner and vendor binding work.