Pular para o conteúdo principal

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/orders concorre com o resto do seu tráfego pelo mesmo RateLimit-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:

EventoQuando dispara
ORDER_CREATEDUm cliente finaliza um novo pedido
ORDER_UPDATEDO status do pedido muda (confirmado, em preparo, entregue, cancelado)
ORDER_DELETEDUm 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
}'
CampoObrigatórioDescrição
webhook_urlSimSeu 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_idSimSeu próprio identificador para este merchant, 1–64 caracteres. Incluído em toda entrega.
event_typesNãoQuais eventos receber. Omita para receber todos os tipos de evento.
webhook_headersNãoHeaders customizados enviados em toda entrega. Padrão: nenhum.
max_retryNãoRetentativas em caso de falha, 0–10. Padrão: 3.
ack_http_codesNãoCó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 dos event_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_UPDATED antigo depois de um mais novo, então trate o evento como um sinal: consulte o pedido de novo com GET /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​

FerramentaO que faz
list_webhooksLista todas as configurações de webhook da sua empresa
get_webhookObtém uma configuração de webhook por UUID
create_webhookRegistra uma nova URL de webhook
update_webhookAtualiza parcialmente uma configuração de webhook
delete_webhookRemove 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.