> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fire.rest/llms.txt
> Use this file to discover all available pages before exploring further.

# Status do pedido KDS

> Endpoint de entrada para o qual seu KDS faz POST quando um pedido da cozinha muda de status (preparando, pronto, despachado). O Fire registra o evento, deduplica e aplica anti-regressão para que o status do pedido nunca retroceda.

Este endpoint é **de entrada** — seu Sistema de Tela de Cozinha (KDS) faz POST nele sempre que um pedido avança na cozinha: a cozinha começou a **prepará-lo**, ficou **pronto** para entrega, ou foi **despachado** (entregue / retirado). O Fire autentica a requisição, correlaciona com o pedido, aplica idempotência e um guard anti-regressão, e registra o evento no seu log de eventos KDS para observabilidade.

<Note>
  **Este endpoint é assíncrono.** O Fire autentica, roda o guard de source-of-truth + tenancy, deduplica e **enfileira** o evento — então responde **`202 Accepted`** com um `webhookEventId` (tipicamente em menos de 100 ms). O evento é registrado um instante depois por um worker em segundo plano (normalmente em \~2 segundos). Para verificar o resultado, consulte [`GET /v1/webhooks/events/{webhookEventId}`](#verificar-o-resultado). Problemas corrigíveis pelo cliente (payload inválido, `eventId` errado, tenant errado) são rejeitados **sincronamente** com `4xx` **antes** do `202`.
</Note>

<Note>
  **Um evento de dispatch, vários reportes de status.** Diferente do callback fiscal — onde cada ação carrega seu próprio `eventId` — o KDS reporta toda a jornada (`preparing` → `ready` → `dispatched`) contra **um** `eventId`: o que o Fire emitiu ao despachar o pedido ao seu device. São distinguidos por `eventType`, não por `eventId`. Veja [Idempotência e a jornada](#idempotência-e-a-jornada).
</Note>

## Tipos de evento

O ciclo de vida do KDS tem uma ordem estrita — um pedido é **preparado** antes de ficar **pronto**, e fica **pronto** antes de ser **despachado**:

| `eventType`        | Significado                                                | Rank |
| ------------------ | ---------------------------------------------------------- | ---- |
| `order.preparing`  | A cozinha começou a preparar o pedido                      | 1    |
| `order.ready`      | O pedido está preparado e pronto para entrega / retirada   | 2    |
| `order.dispatched` | O pedido saiu da cozinha (entregue ou retirado) — terminal | 3    |

Os valores são **minúsculos, com ponto** (`order.preparing`, não `ORDER_PREPARING`).

## Autenticação

Este endpoint requer uma **API key vendor-scoped com o escopo `webhooks:kds`** (binding de conta + vendor). O Fire valida que o pedido pertença a essa conta e vendor. Keys sem o escopo, ou sem binding de vendor, são rejeitadas com `403 Forbidden`.

<ParamField header="x-api-key" type="string" required>
  Sua API key vendor-scoped do Fire com escopo `webhooks:kds`. Gere uma em **Developers → Gestão de API** para a conta/vendor cujos pedidos esta key vai reportar.
</ParamField>

<ParamField header="Authorization" type="string">
  `Bearer <token>` opcional — aceito como alternativa legada ao `x-api-key`. Envie um ou outro.
</ParamField>

## Corpo da requisição

<ParamField body="eventType" type="string" required>
  O evento de ciclo de vida do KDS. `order.preparing`, `order.ready` ou `order.dispatched` (minúsculo, com ponto).
</ParamField>

<ParamField body="providerEventId" type="string" required>
  O id próprio do seu KDS para esta entrega. Armazenado para auditoria/forense — **não é a chave de idempotência**. O Fire deduplica por `(orderId, eventId, eventType)`, então você pode enviar um `providerEventId` novo a cada retentativa. Use o id de evento nativo do seu KDS se tiver; senão, um UUID.
</ParamField>

<ParamField body="occurredAt" type="string" required>
  Timestamp ISO 8601 UTC de quando o evento ocorreu no KDS — não quando foi enviado.
</ParamField>

<ParamField body="orderId" type="string" required>
  UUID do pedido no Fire. Corresponde a `data.orderId` nos eventos de pedido. O Fire correlaciona o evento com este pedido; ele deve existir previamente.
</ParamField>

<ParamField body="eventId" type="string" required>
  UUID de correlação — o `event.id` do envelope que o Fire emitiu ao **despachar o pedido ao seu device**. Ecoe-o exato; nunca o invente.

  * **Verificação de fonte da verdade.** Um `eventId` que não referencie um evento do Fire para esse pedido é rejeitado com `400` antes do `202`.
  * **Um eventId para toda a jornada.** Envie o **mesmo** `eventId` para `preparing`, `ready` e `dispatched` desse dispatch — são distinguidos por `eventType`. (Cada dispatch a um **device diferente** carrega seu próprio `eventId`, então dois devices nunca colidem.)
</ParamField>

<ParamField body="stationName" type="string">
  Estação do KDS de origem, opcional (ex. `Cozinha quente`, `Despacho 1`). Armazenada para observabilidade.
</ParamField>

<ParamField body="metadata" type="object">
  Saco livre opcional de campos extras. Armazenado como está, sem validação.
</ParamField>

### Exemplos

Os três reportes do mesmo dispatch compartilham **um `eventId`** (o do dispatch) e diferem apenas no `eventType` e `providerEventId`:

```json order.preparing theme={null}
{
  "eventType": "order.preparing",
  "providerEventId": "evt_2026-05-26_000122",
  "occurredAt": "2026-05-26T18:28:00.000Z",
  "orderId": "9f1c0e8a-1234-4abc-9def-0123456789ab",
  "eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "stationName": "Cozinha quente"
}
```

```json order.ready theme={null}
{
  "eventType": "order.ready",
  "providerEventId": "evt_2026-05-26_000123",
  "occurredAt": "2026-05-26T18:30:00.000Z",
  "orderId": "9f1c0e8a-1234-4abc-9def-0123456789ab",
  "eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "stationName": "Cozinha quente"
}
```

```json order.dispatched theme={null}
{
  "eventType": "order.dispatched",
  "providerEventId": "evt_2026-05-26_000124",
  "occurredAt": "2026-05-26T18:42:11.000Z",
  "orderId": "9f1c0e8a-1234-4abc-9def-0123456789ab",
  "eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "stationName": "Cozinha quente"
}
```

## Resposta

Em caso de sucesso o endpoint responde **`202 Accepted`** — o evento foi autenticado, validado, deduplicado e **enfileirado**. Um `202` **não** significa que o evento já foi registrado; isso acontece de forma assíncrona. Use o [endpoint de status](#verificar-o-resultado) para confirmar.

O body traz **dois ids distintos**: `eventId` é o id que **você** enviou (echo), `webhookEventId` é o id do **Fire** para o registro enfileirado. Mesma forma que o [callback fiscal](/pt/api-reference/fiscal-callback#resposta).

<ResponseField name="received" type="boolean">
  Sempre `true` quando a requisição foi aceita e enfileirada.
</ResponseField>

<ResponseField name="duplicate" type="boolean">
  `true` quando esta tripla exata `(orderId, eventId, eventType)` já foi ingerida — o registro existente é retornado e nada é re-enfileirado. `false` para um reporte novo (incluindo um `eventType` diferente do mesmo dispatch — isso é um passo novo, não uma duplicata).
</ResponseField>

<ResponseField name="eventId" type="string">
  Echo do `eventId` que você enviou (o `event.id` do dispatch).
</ResponseField>

<ResponseField name="webhookEventId" type="string">
  O id do Fire para o registro enfileirado. Passe-o para `GET /v1/webhooks/events/{webhookEventId}` para consultar o resultado. Em uma duplicata é o **mesmo** id retornado na primeira vez.
</ResponseField>

<ResponseField name="status" type="string">
  Status atual na fila — `queued` → `processing` → `processed` (e `retry` / `failed` / `dead` / `ignored`).
</ResponseField>

<ResponseField name="firstReceivedAt" type="string">
  Timestamp ISO 8601 UTC de quando o Fire recebeu **pela primeira vez** este reporte. Estável entre retentativas.
</ResponseField>

<ResponseField name="message" type="string">
  Resumo legível.
</ResponseField>

<ResponseExample>
  ```json 202 — aceito (passo novo, enfileirado) theme={null}
  {
    "received": true,
    "duplicate": false,
    "eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "webhookEventId": "9e6c8af8-af80-4967-9422-c096ab43c0e7",
    "status": "queued",
    "firstReceivedAt": "2026-05-26T18:30:00.512Z",
    "message": "Event accepted and queued for processing."
  }
  ```

  ```json 202 — duplicado (mesmo orderId + eventId + eventType) theme={null}
  {
    "received": true,
    "duplicate": true,
    "eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "webhookEventId": "9e6c8af8-af80-4967-9422-c096ab43c0e7",
    "status": "processed",
    "firstReceivedAt": "2026-05-26T18:30:00.512Z",
    "message": "Event already received; no action needed."
  }
  ```

  ```json 400 — eventId incorreto / erro de validação theme={null}
  {
    "success": false,
    "error": "VALIDATION_ERROR",
    "message": "eventId does not reference an event emitted by Fire for this orderId. Echo the event.id from a V4 envelope you received for this order."
  }
  ```

  ```json 401 — API key ausente ou inválida theme={null}
  {
    "success": false,
    "error": "UNAUTHORIZED",
    "message": "API key required. Use x-api-key: pk_live_... header"
  }
  ```

  ```json 403 — falta escopo / não é seu tenant theme={null}
  {
    "success": false,
    "error": "FORBIDDEN",
    "message": "webhooks:kds requires a vendor-scoped API key (account + vendor binding). Generate one from /developers/firepos-api-management."
  }
  ```

  ```json 503 — auth store temporariamente inacessível (retente) theme={null}
  {
    "success": false,
    "error": "SERVICE_UNAVAILABLE",
    "message": "API key verification is temporarily unavailable (auth store unreachable). Retry the request."
  }
  ```
</ResponseExample>

## Verificar o resultado

Como o processamento é assíncrono, o `202` apenas confirma que o evento foi **enfileirado**. Para ver se foi registrado, consulte o endpoint de status com o `webhookEventId` retornado pelo `202`:

```
GET https://app.fire.rest/api/v1/webhooks/events/{webhookEventId}
x-api-key: <sua key webhooks:kds>
```

<ResponseField name="status" type="string">
  Ciclo de vida da fila: `queued` → `processing` → `processed` (concluído) · `failed` / `dead` (desistiu após retentativas) · `retry` (aguardando a próxima tentativa) · `ignored` (tratado, sem ação — ex. um duplicado ou um evento não-avançante).
</ResponseField>

<ResponseField name="attempts" type="number">Tentativas de processamento até agora.</ResponseField>
<ResponseField name="result" type="object | null">Em caso de sucesso, o resultado do worker — ex. `{ "kind": "recorded" }` (avançou o pedido) ou `{ "kind": "ignored" }` (não-avançante).</ResponseField>
<ResponseField name="error" type="object | null">`{ "message": "…" }` quando a última tentativa falhou; `null` caso contrário.</ResponseField>

Um `404` é retornado para ids desconhecidos — ou ids de outro tenant — sem vazar existência. Autentique com a mesma key `webhooks:kds` que usou para o evento.

## Idempotência e a jornada

O Fire deduplica pela tripla **`(orderId, eventId, eventType)`** — *não* por `providerEventId` (que você pode regenerar livremente). É isso que faz a jornada funcionar:

| Cenário                                                                                       | Resultado                                                                                            |
| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `preparing`, depois `ready`, depois `dispatched` — **mesmo `eventId`**, `eventType` diferente | cada um é um **passo novo** → `202` `duplicate:false`. O mesmo `eventId` é esperado, não um conflito |
| O **mesmo** reporte reenviado — mesma `(orderId, eventId, eventType)`                         | `202` `duplicate:true` — registro existente retornado, não reprocessado                              |
| `eventId` não emitido pelo Fire para esse `orderId`                                           | `400`                                                                                                |
| Pedido/evento fora da conta + vendor da sua API key                                           | `403`                                                                                                |
| Auth store momentaneamente inacessível                                                        | `503` — transitório, **retente**                                                                     |

<Note>
  **Esta é a diferença chave em relação ao callback fiscal.** Lá, um `eventId` carrega exatamente **uma** ação, então reusá-lo para outro `eventType` é um conflito (`409`). Aqui, um `eventId` de dispatch carrega legitimamente **toda a jornada** (`preparing` → `ready` → `dispatched`) — o `eventType` é o que distingue os passos. Devices diferentes recebem `eventId`s de dispatch diferentes, então seus reportes nunca colidem.
</Note>

## Anti-regressão

O status do pedido nunca deve retroceder. O Fire rastreia o **estágio máximo alcançado** pelo pedido (`order.dispatched` > `order.ready` > `order.preparing`) e compara cada evento de entrada com ele:

* Um evento que **avança** o pedido (ex. `order.ready` depois de `order.preparing`) é registrado como o novo status.
* Um evento que **não avança** — uma regressão (ex. `order.preparing` chegando depois de `order.ready`) ou uma repetição do mesmo status — ainda é **registrado para observabilidade**, mas marcado como não-avançante com um motivo, e **não** retrocede o pedido.

Isso torna o endpoint seguro contra entregas fora de ordem ou atrasadas: envie os eventos em qualquer ordem e o Fire mantém o pedido no seu estágio mais avançado.

## Relacionado

<CardGroup cols={2}>
  <Card title="Injetar pedido" icon="paper-plane" href="/pt/api-reference/orders">
    O endpoint de injeção que cria o pedido que este evento referencia.
  </Card>

  <Card title="Callback fiscal" icon="receipt" href="/pt/api-reference/fiscal-callback">
    O webhook de entrada irmão — mesmo modelo async + idempotência + correlação.
  </Card>

  <Card title="Autenticação" icon="lock" href="/pt/authentication">
    Como funcionam as API keys, escopos e o binding de parceiro e vendor.
  </Card>
</CardGroup>
