Receba atualizações de pedidos com webhooks em vez de polling
Este guia é para um integrador que hoje chama GET /v1/orders periodicamente para descobrir o
que mudou, e quer migrar para webhooks: a OlaClick envia um POST para seu endpoint no momento
em que um evento de pedido acontece, em vez de você precisar perguntar.
O fluxo em resumo
Por que webhooks em vez de polling
- Os limites de taxa são por chave de API (API key), não por endpoint (veja
Limitação de taxa): cada chamada de polling gasta do mesmo orçamento que
qualquer outra chamada da sua integração. Um loop de polling agressivo contra
GET /v1/ordersconcorre com o resto do seu tráfego pelo mesmoRateLimit-Limit. - Latência. Um polling só encontra uma mudança até um intervalo de polling depois que ela aconteceu. Uma entrega de webhook dispara assim que o evento acontece.
Eventos de pedidos e seus payloads
Os tipos de evento de um webhook são configurados por webhook (veja event_types abaixo). Os
relevantes para pedidos são:
| Evento | Quando dispara |
|---|---|
ORDER_CREATED | Um cliente finaliza um novo pedido |
ORDER_UPDATED | O status do pedido muda (confirmado, em preparo, entregue, cancelado) |
ORDER_DELETED | Um pedido é excluído do sistema |
(Um webhook também pode assinar CONNECTION_CREATED, CONNECTION_DESTROYED e
FISCAL_NOTES_REQUEST — não são eventos de pedido, fora do escopo deste guia.)
Toda entrega usa o mesmo envelope, independente do tipo de evento:
{
"event_type": "ORDER_CREATED",
"event_id": "018f1c2e-9b7a-7c3e-8a9e-6a6f6e1b2a10",
"merchant_id": "restaurant_042",
"timestamp": "2026-06-20T15:30:00.000Z",
"data": { "...": "o payload do pedido" }
}
data carrega o pedido ao qual o evento se refere. Trate-o como uma notificação de que algo
mudou, não como um schema fixo para interpretar campo a campo: se seu handler precisa do estado
completo e atual do pedido, busque-o com
GET /v1/orders/{id} usando o id do pedido, em vez de
assumir que todo campo dentro de data está presente e atualizado. Veja a
visão geral de Webhooks para o formato completo de entrega (headers, source,
etc.).
Registrando um webhook
POST /v1/webhooks
Escopo necessário: webhooks:write
curl -X POST https://public-api.olaclick.app/v1/webhooks \
-H "Authorization: Bearer olk_live_..." \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://integrations.example.com/olaclick/webhook",
"merchant_id": "restaurant_042",
"event_types": ["ORDER_CREATED", "ORDER_UPDATED", "ORDER_DELETED"],
"max_retry": 5
}'
| Campo | Obrigatório | Descrição |
|---|---|---|
webhook_url | Sim | Seu endpoint HTTPS. Precisa usar https:// e não pode apontar para localhost ou um endereço privado/interno — ambos são rejeitados localmente antes de qualquer coisa ser salva. |
merchant_id | Sim | Seu próprio identificador para este merchant, 1–64 caracteres. Incluído em toda entrega. |
event_types | Não | Quais eventos receber. Omita para receber todos os tipos de evento. |
webhook_headers | Não | Headers customizados enviados em toda entrega. Padrão: nenhum. |
max_retry | Não | Retentativas em caso de falha, 0–10. Padrão: 3. |
ack_http_codes | Não | Códigos HTTP considerados uma entrega bem-sucedida. Padrão: [200, 201, 202]. |
{
"data": {
"webhook_id": "7a1e9c3a-4b2d-4f7e-9a1b-3c6d8e2f5a90",
"company_id": "5e2a8c1d-6f3b-4a9e-8d2c-1b7f4e9a3c60",
"webhook_url": "https://integrations.example.com/olaclick/webhook",
"merchant_id": "restaurant_042",
"origin": "API",
"webhook_headers": {},
"is_active": true,
"max_retry": 5,
"ack_http_codes": [200, 201, 202],
"event_types": ["ORDER_CREATED", "ORDER_UPDATED", "ORDER_DELETED"],
"signing_secret": "whsec_7f3a1c9e2b4d6f8a0c1e3b5d7f9a2c4e",
"created_at": "2026-06-20T15:00:00.000Z",
"updated_at": "2026-06-20T15:00:00.000Z"
}
}
Gerencie-o depois com GET /v1/webhooks /
GET /v1/webhooks/{id} (webhooks:read),
PATCH /v1/webhooks/{id} e
DELETE /v1/webhooks/{id} (webhooks:write).
Verificando a assinatura
Toda entrega carrega X-OlaClick-Signature: sha256=<hex-encoded-hmac>, calculada sobre o corpo
bruto da requisição com o signing_secret do seu webhook. Verifique-a antes de confiar no
payload:
const crypto = require('crypto');
function verifySignature(rawBody, secret, signatureHeader) {
if (typeof signatureHeader !== 'string') return false;
const expected = Buffer.from(
'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex'),
);
const received = Buffer.from(signatureHeader);
// timingSafeEqual throws when lengths differ, so compare lengths first.
return expected.length === received.length && crypto.timingSafeEqual(expected, received);
}
Use o corpo bruto, não serializado novamente, e uma comparação resistente a timing attacks. Veja a visão geral de Webhooks para os exemplos completos em Node.js e Python.
Retentativas, e como construir um handler rápido e idempotente
Se seu endpoint não responder com um dos ack_http_codes (200, 201, 202 por padrão), a
OlaClick tenta novamente até max_retry vezes com backoff exponencial (30s, 60s, 120s, ...).
Isso significa que seu handler precisa assumir entrega pelo menos uma vez (at-least-once): o
mesmo evento pode chegar mais de uma vez, e um handler lento corre o risco de uma entrega ser
reenviada mesmo estando, na verdade, sendo processada.
- Responda rápido, mas grave antes. Verifique a assinatura, grave ou enfileire o evento de
forma durável (com o seu
event_id), confirme com 2xx e faça o trabalho real (recalcular algo, gravar no seu próprio banco de dados, notificar um entregador) a partir dessa fila. Depois que as retentativas se esgotam, nada reenvia o evento: um evento confirmado e nunca gravado se perde. - Deduplique por
event_id. Mantenha um registro dosevent_ids já processados por pelo menos toda a janela de retentativas e ignore o que já foi tratado, para que uma entrega repetida seja um no-op em vez de processar o pedido duas vezes. - Torne o handler idempotente. Projete a própria atualização (por exemplo, "definir o status local deste pedido para X") de forma que aplicá-la duas vezes tenha o mesmo resultado que aplicá-la uma vez.
- Não deixe um evento antigo sobrescrever um mais novo. As retentativas podem entregar um
ORDER_UPDATEDantigo depois de um mais novo, então trate o evento como um sinal: consulte o pedido de novo comGET /v1/orders/{id}e aplique o estado atual dele em vez do estado do payload.
Quando uma reconciliação via GET /v1/orders ainda é apropriada
Webhooks assumem que seu endpoint está acessível. Se ele ficou fora do ar — um deploy, uma
indisponibilidade, uma URL mal configurada — os eventos que dispararam nessa janela se perdem
assim que max_retry se esgota; nada os reenvia depois. Depois que seu endpoint voltar, faça o
backfill da lacuna com GET /v1/orders, filtrando pela
janela de indisponibilidade:
curl "https://public-api.olaclick.app/v1/orders?filter[start_date]=2026-06-20&filter[end_date]=2026-06-20&filter[time_type]=updated_at" \
-H "Authorization: Bearer olk_live_..."
filter[time_type]=updated_at captura pedidos que mudaram durante a janela, não apenas os
criados nela — mais próximo do que um ORDER_UPDATED perdido teria informado.
filter[status] restringe ainda mais se você só se importa com determinados status. Pagine com
page / per_page se a janela tiver mais de uma página de pedidos.
Fora de uma lacuna de disponibilidade, prefira o webhook: um polling de reconciliação em uma agenda fixa é exatamente o padrão que este guia visa substituir.
Fazendo isso pelo servidor MCP
| Ferramenta | O que faz |
|---|---|
list_webhooks | Lista todas as configurações de webhook da sua empresa |
get_webhook | Obtém uma configuração de webhook por UUID |
create_webhook | Registra uma nova URL de webhook |
update_webhook | Atualiza parcialmente uma configuração de webhook |
delete_webhook | Remove uma assinatura de webhook |
Escopos necessários: webhooks:read (listar/obter), webhooks:write (criar/atualizar/excluir).
Exemplos de prompts:
"Registre um webhook em https://integrations.example.com/olaclick/webhook para eventos de pedido"
"Liste meus webhooks"
"Pare de enviar eventos ORDER_DELETED para meu webhook"
Veja a página do Servidor MCP para todos os parâmetros de cada ferramenta.