Skip to main content

Configurar webhooks

Gerencie todo o ciclo de vida do webhook via API pública — ou use a página Webhooks do painel (/webhooks). Um webhook é configurado por número; uma vez configurado, os eventos são entregues automaticamente (não é necessário vincular chave de API).
Página de Webhooks do Pilot Status

A página de Webhooks — criar, editar, desativar ou excluir um webhook e inspecionar seus eventos de entrega.

Para payloads e a lista completa de eventos, consulte a referência de eventos.

Endpoints

Escopo por número

Um webhook pertence a um único número do WhatsApp.
  • Com uma chave com escopo de número, o número vem da própria chave; um whatsappNumberId no corpo deve corresponder a ele (caso contrário, 400 NUMBER_MISMATCH).
  • Com uma chave com escopo de tenant, informe o número de destino pelo campo whatsappNumberId do corpo ou pelo cabeçalho x-whatsapp-number-id — omitir ambos retorna 400 NUMBER_REQUIRED; um número fora do seu tenant retorna 404 NUMBER_NOT_FOUND.
  • GET /v1/webhooks lista apenas os webhooks visíveis no escopo da chave (uma chave com escopo de número vê apenas os webhooks do seu próprio número). Um webhook fora do escopo da chave retorna 404 WEBHOOK_NOT_FOUND.

Exemplos

Ler os logs de entrega

GET /v1/webhooks/{id}/logs devolve as tentativas recentes, da mais nova para a mais antiga. Dois campos juntos dizem onde a tentativa morreu: O statusCode null é o caso que vale ler com atenção: nada chegou ao seu servidor, então não existe status. O response traz então a cadeia de causas, da mais externa para a mais interna, unidas por <- e marcadas com o código de erro do sistema:
Os códigos mais frequentes:
Trate o response como string de diagnóstico, não como contrato. O texto vem do runtime e pode mudar entre versões; decida pelo status e pelo statusCode, e leia o response quando precisar saber o porquê.
Uma tentativa falha é retentada com backoff exponencial antes de ser desistida, então uma linha FAILED sozinha não quer dizer que o evento se perdeu — procure um SUCCESS posterior no mesmo evento.

Controle de eventos

Uma lista events vazia (ou omitida) NÃO dispara NADA — não existe “assinar todos” implícito. Use "*" para assinar todos os eventos.
  • No PATCH, events substitui toda a lista de assinatura (não é uma mesclagem).
  • Eventos que o provedor do número não consegue emitir são descartados silenciosamente.

Regras e erros

O secret de assinatura nunca é retornado por nenhum desses endpoints.

Quantos webhooks por número

Um número pode ter mais de um webhook. O escopo é muitos-para-muitos: todo webhook ativo assinado naquele número recebe os eventos que assinou, e o segundo não substitui o primeiro. Use isso para separar responsabilidades — um endpoint para conversas, outro para saúde e monitoramento. A única recusa é a duplicata exata: a mesma url no mesmo número — 409 WEBHOOK_DUPLICATE. Não existe motivo legítimo para duas, e a integração que criava em vez de atualizar acumulava linhas em silêncio; agora recebe um conflito. Vale também um teto de 50 webhooks por workspace (409 WEBHOOK_LIMIT_REACHED) — deliberadamente folgado, já que um tenant com muitos números pode querer um por número.
Dois endpoints no mesmo número

Verifique a assinatura

Todo webhook criado a partir de 15/09/2026 nasce assinado. A criação cunha um segredo e devolve-o em claro naquele 201 — a única resposta na vida de um segredo que o carrega. Nenhuma leitura o traz de volta.
Webhooks criados antes dessa data não têm segredo, e continuam assim. As entregas deles saem sem assinatura. É deliberado: ligar verificação de assinatura por baixo de uma integração viva é, por si só, uma interrupção. O POST /v1/webhooks/{id}/rotate-secret é como você a liga num deles — e a única forma de recuperar um segredo perdido, já que nenhuma leitura o devolve.Leia o hasSecret de cada webhook para distinguir os dois casos antes de decidir se o seu receptor pode recusar entrega sem assinatura.

Rodar — ou cunhar um para um webhook antigo

A rotação é imediata e não tem janela de sobreposição. O segredo anterior deixa de verificar no instante em que a chamada retorna; entregas já em voo assinam com o valor que o despacho delas carregou. Aceite os dois segredos do seu lado durante um minuto, ou rode num momento de silêncio do número.
Quando um segredo está definido, o cabeçalho x-pilot-status-signature carrega o HMAC-SHA256 do corpo bruto da requisição, em hexadecimal, chaveado com o segredo. Calcule o HMAC sobre os bytes brutos exatamente como recebidos (antes de qualquer parse de JSON) e compare em tempo constante:
Node

Deduplicar retentativas: Idempotency-Key

Quando está presente, o Idempotency-Key é estável por evento: uma retentativa, um replay de backoff e um replay de failover do mesmo evento carregam o mesmo valor — é a chave certa para deduplicar. O mesmo valor também é mesclado no corpo JSON entregue como um campo idempotencyKey de primeiro nível, então dá para ler dos dois lugares.
O cabeçalho não vem em toda entrega. Ele é derivado de um id de mensagem encontrado no payload (messageId / internalMessageId, no topo ou dentro de data). Um payload sem esse id não recebe cabeçalho nenhum nem campo no corpo — isso inclui:
  • todo envelope nativo da Meta Cloud API (messages, smb_message_echoes, message_echoes, os campos de template e de conta …), cujo topo é { object, entry };
  • os eventos number.* de ciclo de vida e os de saúde do número.
Ou seja: o tráfego de conversa de um número Meta não é coberto por esse cabeçalho hoje. Deduplique pelos ids da própria Meta — e leia o aviso sobre wamid repetido na referência de eventos antes de chavear só pelo wamid.

Painel

Tudo acima também está disponível no painel em /webhooks: crie/edite webhooks por número, escolha eventos, pause/retome e inspecione os logs de entrega. A interface de Novo/Editar Webhook inclui o aviso de que message.read só dispara quando o destinatário tem os recibos de leitura do WhatsApp ativados.