Status do pedido KDS
curl --request POST \
--url https://app.fire.rest/api/v1/webhooks/kds/order-status \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"eventType": "<string>",
"providerEventId": "<string>",
"occurredAt": "<string>",
"orderId": "<string>",
"eventId": "<string>",
"stationName": "<string>",
"metadata": {}
}
'import requests
url = "https://app.fire.rest/api/v1/webhooks/kds/order-status"
payload = {
"eventType": "<string>",
"providerEventId": "<string>",
"occurredAt": "<string>",
"orderId": "<string>",
"eventId": "<string>",
"stationName": "<string>",
"metadata": {}
}
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
eventType: '<string>',
providerEventId: '<string>',
occurredAt: '<string>',
orderId: '<string>',
eventId: '<string>',
stationName: '<string>',
metadata: {}
})
};
fetch('https://app.fire.rest/api/v1/webhooks/kds/order-status', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.fire.rest/api/v1/webhooks/kds/order-status",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'eventType' => '<string>',
'providerEventId' => '<string>',
'occurredAt' => '<string>',
'orderId' => '<string>',
'eventId' => '<string>',
'stationName' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.fire.rest/api/v1/webhooks/kds/order-status"
payload := strings.NewReader("{\n \"eventType\": \"<string>\",\n \"providerEventId\": \"<string>\",\n \"occurredAt\": \"<string>\",\n \"orderId\": \"<string>\",\n \"eventId\": \"<string>\",\n \"stationName\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.fire.rest/api/v1/webhooks/kds/order-status")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"eventType\": \"<string>\",\n \"providerEventId\": \"<string>\",\n \"occurredAt\": \"<string>\",\n \"orderId\": \"<string>\",\n \"eventId\": \"<string>\",\n \"stationName\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.fire.rest/api/v1/webhooks/kds/order-status")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"eventType\": \"<string>\",\n \"providerEventId\": \"<string>\",\n \"occurredAt\": \"<string>\",\n \"orderId\": \"<string>\",\n \"eventId\": \"<string>\",\n \"stationName\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"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."
}
{
"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."
}
{
"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."
}
{
"success": false,
"error": "UNAUTHORIZED",
"message": "API key required. Use x-api-key: pk_live_... header"
}
{
"success": false,
"error": "FORBIDDEN",
"message": "webhooks:kds requires a vendor-scoped API key (account + vendor binding). Generate one from /developers/firepos-api-management."
}
{
"success": false,
"error": "SERVICE_UNAVAILABLE",
"message": "API key verification is temporarily unavailable (auth store unreachable). Retry the request."
}
APIs de parceiro
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.
POST
/
api
/
v1
/
webhooks
/
kds
/
order-status
Status do pedido KDS
curl --request POST \
--url https://app.fire.rest/api/v1/webhooks/kds/order-status \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"eventType": "<string>",
"providerEventId": "<string>",
"occurredAt": "<string>",
"orderId": "<string>",
"eventId": "<string>",
"stationName": "<string>",
"metadata": {}
}
'import requests
url = "https://app.fire.rest/api/v1/webhooks/kds/order-status"
payload = {
"eventType": "<string>",
"providerEventId": "<string>",
"occurredAt": "<string>",
"orderId": "<string>",
"eventId": "<string>",
"stationName": "<string>",
"metadata": {}
}
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
eventType: '<string>',
providerEventId: '<string>',
occurredAt: '<string>',
orderId: '<string>',
eventId: '<string>',
stationName: '<string>',
metadata: {}
})
};
fetch('https://app.fire.rest/api/v1/webhooks/kds/order-status', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.fire.rest/api/v1/webhooks/kds/order-status",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'eventType' => '<string>',
'providerEventId' => '<string>',
'occurredAt' => '<string>',
'orderId' => '<string>',
'eventId' => '<string>',
'stationName' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.fire.rest/api/v1/webhooks/kds/order-status"
payload := strings.NewReader("{\n \"eventType\": \"<string>\",\n \"providerEventId\": \"<string>\",\n \"occurredAt\": \"<string>\",\n \"orderId\": \"<string>\",\n \"eventId\": \"<string>\",\n \"stationName\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.fire.rest/api/v1/webhooks/kds/order-status")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"eventType\": \"<string>\",\n \"providerEventId\": \"<string>\",\n \"occurredAt\": \"<string>\",\n \"orderId\": \"<string>\",\n \"eventId\": \"<string>\",\n \"stationName\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.fire.rest/api/v1/webhooks/kds/order-status")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"eventType\": \"<string>\",\n \"providerEventId\": \"<string>\",\n \"occurredAt\": \"<string>\",\n \"orderId\": \"<string>\",\n \"eventId\": \"<string>\",\n \"stationName\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"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."
}
{
"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."
}
{
"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."
}
{
"success": false,
"error": "UNAUTHORIZED",
"message": "API key required. Use x-api-key: pk_live_... header"
}
{
"success": false,
"error": "FORBIDDEN",
"message": "webhooks:kds requires a vendor-scoped API key (account + vendor binding). Generate one from /developers/firepos-api-management."
}
{
"success": false,
"error": "SERVICE_UNAVAILABLE",
"message": "API key verification is temporarily unavailable (auth store unreachable). Retry the request."
}
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.
Os valores são minúsculos, com ponto (
Um
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}. Problemas corrigíveis pelo cliente (payload inválido, eventId errado, tenant errado) são rejeitados sincronamente com 4xx antes do 202.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.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 |
order.preparing, não ORDER_PREPARING).
Autenticação
Este endpoint requer uma API key vendor-scoped com o escopowebhooks: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.
string
obrigatório
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.string
Bearer <token> opcional — aceito como alternativa legada ao x-api-key. Envie um ou outro.Corpo da requisição
string
obrigatório
O evento de ciclo de vida do KDS.
order.preparing, order.ready ou order.dispatched (minúsculo, com ponto).string
obrigatório
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.string
obrigatório
Timestamp ISO 8601 UTC de quando o evento ocorreu no KDS — não quando foi enviado.
string
obrigatório
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.string
obrigatório
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
eventIdque não referencie um evento do Fire para esse pedido é rejeitado com400antes do202. - Um eventId para toda a jornada. Envie o mesmo
eventIdparapreparing,readyedispatcheddesse dispatch — são distinguidos poreventType. (Cada dispatch a um device diferente carrega seu próprioeventId, então dois devices nunca colidem.)
string
Estação do KDS de origem, opcional (ex.
Cozinha quente, Despacho 1). Armazenada para observabilidade.object
Saco livre opcional de campos extras. Armazenado como está, sem validação.
Exemplos
Os três reportes do mesmo dispatch compartilham umeventId (o do dispatch) e diferem apenas no eventType e providerEventId:
order.preparing
{
"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"
}
order.ready
{
"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"
}
order.dispatched
{
"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 responde202 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 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.
boolean
Sempre
true quando a requisição foi aceita e enfileirada.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).string
Echo do
eventId que você enviou (o event.id do dispatch).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.string
Status atual na fila —
queued → processing → processed (e retry / failed / dead / ignored).string
Timestamp ISO 8601 UTC de quando o Fire recebeu pela primeira vez este reporte. Estável entre retentativas.
string
Resumo legível.
{
"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."
}
{
"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."
}
{
"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."
}
{
"success": false,
"error": "UNAUTHORIZED",
"message": "API key required. Use x-api-key: pk_live_... header"
}
{
"success": false,
"error": "FORBIDDEN",
"message": "webhooks:kds requires a vendor-scoped API key (account + vendor binding). Generate one from /developers/firepos-api-management."
}
{
"success": false,
"error": "SERVICE_UNAVAILABLE",
"message": "API key verification is temporarily unavailable (auth store unreachable). Retry the request."
}
Verificar o resultado
Como o processamento é assíncrono, o202 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>
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).number
Tentativas de processamento até agora.
object | null
Em caso de sucesso, o resultado do worker — ex.
{ "kind": "recorded" } (avançou o pedido) ou { "kind": "ignored" } (não-avançante).object | null
{ "message": "…" } quando a última tentativa falhou; null caso contrário.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 |
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 eventIds de dispatch diferentes, então seus reportes nunca colidem.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.readydepois deorder.preparing) é registrado como o novo status. - Um evento que não avança — uma regressão (ex.
order.preparingchegando depois deorder.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.
Relacionado
Injetar pedido
O endpoint de injeção que cria o pedido que este evento referencia.
Callback fiscal
O webhook de entrada irmão — mesmo modelo async + idempotência + correlação.
Autenticação
Como funcionam as API keys, escopos e o binding de parceiro e vendor.

