Webhook WhatsApp: como configurar na API oficial
Fundador e CEO da Chatsac11 min de leitura

Você enviou uma mensagem pela API e não sabe se ela chegou. Um cliente respondeu e o seu sistema nem percebeu. O webhook do WhatsApp resolve os dois casos: a Meta avisa o seu servidor no instante em que algo acontece.
Este guia explica o que é o webhook, como ele funciona na API oficial e como configurar do zero, com os detalhes conferidos na documentação da Meta.
O que você vai ver neste guia
- O que é um webhook do WhatsApp e quando a Meta o dispara
- Os dois tipos de requisição que o seu endpoint precisa tratar
- O que você precisa ter pronto antes de configurar
- O passo a passo no painel do app e na conta do WhatsApp Business
- O formato de uma mensagem recebida e de uma notificação de status
- Como validar a assinatura e evitar eventos duplicados
O que é um webhook do WhatsApp?
Um webhook é uma requisição HTTP com um JSON que um servidor envia para outro quando algo acontece. Na API oficial, a documentação da Meta diz que os servidores dela enviam esses webhooks para um servidor que você designa, para avisar sobre mensagens recebidas, o status das mensagens enviadas, eventos de chamada e mudanças na conta, como upgrades de capacidade de mensagens e a qualidade dos templates.
A diferença para uma chamada comum de API é a direção. Em uma chamada comum, o seu sistema pergunta. No webhook, a Meta avisa. Você não precisa consultar a API de tempos em tempos para saber se um cliente respondeu.
Se você ainda está montando a base da integração, veja primeiro como funciona a integração da API do WhatsApp com sistemas web. O webhook é a metade que recebe. A outra metade é o envio, que usa o token de acesso.
Como o webhook funciona na API oficial do WhatsApp?
O fluxo tem três peças: o seu endpoint HTTPS, a verificação inicial e as notificações de evento. Você cria o endpoint, a Meta confirma que ele é seu com uma requisição GET e, depois disso, passa a enviar um POST a cada evento dos campos que você assinou. O guia completo da API do WhatsApp mostra onde o webhook se encaixa no conjunto.
O endpoint precisa tratar dois tipos de requisição:
| Item | Verificação (GET) | Notificação (POST) |
|---|---|---|
| Quando acontece | Ao salvar ou editar a Callback URL ou o Verify token no painel | A cada evento dos campos que você assinou |
| O que chega | Parâmetros hub.mode, hub.challenge e hub.verify_token na URL | Um JSON no corpo e o cabeçalho X-Hub-Signature-256 |
| O que você valida | Se o hub.verify_token é igual à string guardada no servidor | Se o HMAC-SHA256 do corpo bate com o cabeçalho |
| O que você responde | Status 200 e o valor de hub.challenge | Status 200 |
Dois detalhes valem desde já. O certificado do servidor precisa ser válido: segundo a página de criação do endpoint, certificados autoassinados não são aceitos. E não existe API para buscar webhooks antigos, então grave o payload quando ele chegar.
O que você precisa para configurar o webhook?
Você precisa de um app da Meta com a API do WhatsApp, uma conta do WhatsApp Business com um número, um servidor público em HTTPS e duas strings: o verify token e o app secret. Antes de começar, confira esta lista:
- Um app no painel de desenvolvedores da Meta, com o produto WhatsApp.
- Uma conta do WhatsApp Business (WABA) e um número. Se ainda não tem, veja como ativar a API oficial do WhatsApp.
- Um servidor público com HTTPS e certificado TLS válido. Durante os testes, a Meta oferece um endpoint de teste que mostra os payloads no console, mas diz que, antes de usar o app em produção, você precisa do seu próprio endpoint.
- Um verify token. É uma string de sua escolha. Você a guarda no servidor e a informa no painel.
- O app secret. Fica nas configurações básicas do app e serve para validar a assinatura.
- A permissão certa. Para os webhooks de mensagens e chamadas, o app precisa da permissão
whatsapp_business_messaging. Os demais webhooks pedemwhatsapp_business_management. Quem usa o próprio sistema gera um token de usuário do sistema com essas permissões. Veja como gerar e proteger o token da API do WhatsApp.
Como configurar o webhook do WhatsApp passo a passo?
São cinco passos: criar o endpoint, publicá-lo, informar a URL e o verify token no painel, assinar o campo messages e testar. A ordem importa, porque o painel só salva a configuração se o endpoint já responder à verificação.
- Crie o endpoint com GET e POST. O GET compara o
hub.verify_tokencom a string guardada no servidor. Se for igual, responde 200 com ohub.challenge. O POST recebe os eventos. Um exemplo curto vem na seção de assinatura, mais abaixo. - Publique em HTTPS. Use um domínio público com certificado válido. Um endereço local não é alcançável pela Meta.
- Informe a URL e o verify token no painel. Vá em App Dashboard, WhatsApp, Configuration, e preencha os campos Callback URL e Verify token. Se o app foi criado com o caso de uso "Connect with customers through WhatsApp", o caminho é App Dashboard, Use cases, Customize, Configuration. Ao salvar, a Meta envia o GET de verificação. Se o endpoint responder 200 com o
hub.challenge, o painel salva e mostra a lista de campos que você pode assinar. Se responder outra coisa, a Meta considera o endpoint não verificado e não envia webhooks. - Assine o campo
messages. Esse campo cobre as mensagens que os usuários enviam para o seu número e o status das mensagens que você envia. Assine outros campos só se tiver uso para eles, como o de status dos templates. - Inscreva o app na conta do WhatsApp Business. A página de gestão de webhooks, escrita para o contexto do Embedded Signup, diz que é preciso inscrever o app em cada conta de mensagens que deve enviar webhooks. A chamada é um POST para a rota de apps inscritos da conta:
curl -X POST 'https://graph.facebook.com/<API_VERSION>/<WABA_ID>/subscribed_apps' \
-H 'Authorization: Bearer <ACCESS_TOKEN>'
Uma resposta de sucesso devolve "success": true. Para conferir quais apps estão inscritos, use um GET na mesma rota. Por fim, mande uma mensagem de um celular para o número da API e veja se o POST chega ao servidor. O painel também permite enviar um payload de teste.
Existe um caminho alternativo: configurar o webhook pela API de assinaturas do Graph, que exige um token de app e usa whatsapp_business_account como valor do objeto.
Como é o payload de uma mensagem recebida?
Quando um cliente escreve para o seu número, a Meta envia um POST com um JSON cujo valor traz um array messages. É assim que você distingue uma mensagem recebida de um status. O exemplo abaixo, abreviado, é o que a documentação mostra para uma mensagem de texto:
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "102290129340398",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "15550783881",
"phone_number_id": "106540352242922"
},
"contacts": [
{ "profile": { "name": "Sheena Nelson" }, "wa_id": "16505551234" }
],
"messages": [
{
"from": "16505551234",
"id": "wamid.HBgLMTY1MDM4Nzk0MzkVAgASGBQzQTRB...",
"timestamp": "1749416383",
"type": "text",
"text": { "body": "Does it come in another color?" }
}
]
},
"field": "messages"
}
]
}
]
}
Os campos que mais importam no dia a dia:
entry.idé o ID da conta do WhatsApp Business.metadata.phone_number_ididentifica o número da empresa que recebeu a mensagem. É o ID que você usa para responder.contactstraz o nome do perfil e owa_iddo cliente.messages.idé o ID único da mensagem, que começa comwamid..messages.typediz o tipo (texto, imagem, áudio e outros). O conteúdo muda conforme o tipo, e a Meta mantém uma referência para cada um.
Como é a notificação de status de uma mensagem enviada?
Quando você envia uma mensagem, o webhook avisa o que aconteceu com ela. Em vez de um array messages, o JSON traz um array statuses, que não descreve o conteúdo da mensagem, só o andamento dela. Segundo a referência de status, os valores são:
sent: a mensagem saiu dos servidores da Meta (um tique).delivered: chegou ao aparelho do usuário (dois tiques).read: foi exibida em uma conversa aberta no aparelho (dois tiques azuis).failed: não foi possível enviar ou entregar (triângulo vermelho). Nesse caso o JSON inclui o arrayerrors, com código, título e detalhes.played: a primeira vez que uma mensagem de voz é reproduzida no aparelho (microfone azul).
Segundo a referência do webhook messages, cada mensagem enviada pode gerar até três webhooks, um para sent, um para delivered e um para read. Há uma exceção: quando o usuário recebe a mensagem com a conversa já aberta, ela é entregue e lida ao mesmo tempo, e o webhook delivered não é enviado. Por isso, não monte um fluxo que depende de receber os três em sequência.
Um status abreviado, como na documentação:
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "102290129340398",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "15550783881",
"phone_number_id": "106540352242922"
},
"statuses": [
{
"id": "wamid.HBgLMTY1MDM4Nzk0MzkVAgARGBI3MTE5MjVB...",
"status": "delivered",
"timestamp": "1750263773",
"recipient_id": "16505551234"
}
]
},
"field": "messages"
}
]
}
]
}
O id do status é o ID da mensagem que você enviou. É por ele que você liga o status ao envio original.
Como validar a assinatura do webhook?
Toda notificação POST vem com o cabeçalho X-Hub-Signature-256, no formato sha256= seguido do hash. Para validar, gere um HMAC-SHA256 do corpo da requisição usando o app secret como chave e compare com o valor do cabeçalho, sem o prefixo sha256=. Se forem iguais, o payload é válido. Se forem diferentes, a documentação manda tratar o payload como inválido. A página geral de webhooks do Graph diz que você não é obrigado a validar, mas deveria.
Calcule o hash sobre o corpo exatamente como chegou, antes de qualquer conversão. O exemplo abaixo, em Node com Express, junta a verificação GET e a validação do POST. Verify token e app secret ficam em variáveis de ambiente:
const express = require("express");
const crypto = require("crypto");
const app = express();
const VERIFY_TOKEN = process.env.VERIFY_TOKEN;
const APP_SECRET = process.env.APP_SECRET;
// guarda o corpo bruto para calcular o hash
app.use(express.json({ verify: (req, _res, buf) => { req.rawBody = buf; } }));
// 1) verificação: a Meta chama com GET
app.get("/webhooks", (req, res) => {
const mode = req.query["hub.mode"];
const token = req.query["hub.verify_token"];
const challenge = req.query["hub.challenge"];
if (mode === "subscribe" && token === VERIFY_TOKEN) {
return res.status(200).send(challenge);
}
return res.sendStatus(403);
});
// 2) eventos: a Meta chama com POST
app.post("/webhooks", (req, res) => {
const received = req.get("X-Hub-Signature-256") || "";
const expected = "sha256=" +
crypto.createHmac("sha256", APP_SECRET).update(req.rawBody).digest("hex");
const a = Buffer.from(received);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.sendStatus(401);
}
res.sendStatus(200); // responde primeiro
// depois: gravar req.body e enfileirar o processamento
});
app.listen(3000);
Nunca coloque o app secret no código nem em mensagens de chat.
O webhook do WhatsApp tem custo?
Nas páginas de webhooks da Meta não aparece tarifa para receber notificações. A cobrança descrita na página de preços da Meta é por mensagem entregue de empresa para usuário, e a Meta diz que não cobra mensagens de usuário para empresa. Segundo a Meta, desde 1º de outubro de 2026 as mensagens de serviço também são cobradas, depois da faixa gratuita de 1.000 por mês para cada número comercial. Regra conferida na página da Meta em 8 de outubro de 2026. O seu servidor tem o custo de hospedagem de sempre.
Quais são as boas práticas e os erros comuns do webhook?
O erro mais comum é tratar o webhook como uma chamada que só acontece uma vez. A Meta repete a entrega quando não recebe 200, e isso gera duplicatas. As práticas abaixo vêm da documentação da Meta, exceto onde está indicado.
- Responda 200 e processe depois. A Meta considera entregue o POST que recebe 200. Qualquer outra resposta, ou falha de entrega, dispara novas tentativas. Gravar o evento e responder logo é uma prática de engenharia nossa, não uma regra da Meta, mas evita que um processamento lento vire reenvio.
- Aceite duplicatas. Segundo a visão geral de webhooks da Meta, se um POST falha, a entrega é repetida logo em seguida e depois com frequência decrescente por até 7 dias. A página geral de webhooks do Graph ainda fala em 36 horas, então não conte com a janela inteira. A documentação do WhatsApp manda o servidor tratar a deduplicação. Use o ID da mensagem como chave: o
messages.idpara mensagens recebidas e, para status, ostatuses.idjunto com ostatus, já que o mesmo ID aparece em até três webhooks. - Trate cada evento de forma individual. Os POSTs podem vir agregados em lote, com no máximo 1.000 atualizações segundo a página de criação do endpoint, mas a Meta avisa que o lote não é garantido. Percorra todos os itens de
entrye dechanges. - Guarde o payload. Não há API para consultar webhooks antigos. O tamanho máximo de um payload é 3 MB, segundo a documentação de webhooks.
- Valide a assinatura. Sem a validação, qualquer pessoa que descobrir a URL pode enviar eventos falsos ao seu sistema.
- Considere o mTLS. A Meta oferece TLS mútuo e avisa que os IPs dos servidores de webhook mudam, o que torna uma lista de IPs liberados trabalhosa.
- Monitore o endpoint. Se ele ficar fora do ar, as tentativas continuam por até 7 dias, segundo a Meta. Depois disso, o evento sem confirmação é descartado.
Se o webhook não chega, siga a ordem que a Meta sugere: confirme que o endpoint aceita requisições, envie um payload de teste pelo painel, confira se o app está no modo Live (alguns webhooks não são enviados no modo Dev) e, se precisar, use o endpoint de teste da Meta para saber se o problema está no seu código. Confira também a assinatura do campo messages e a inscrição do app na conta.
Quem prefere montar o fluxo sem escrever um servidor do zero pode receber os eventos em uma ferramenta de automação. No n8n, esse papel é do node WhatsApp Trigger, que registra a própria URL no app no lugar de um endpoint seu. Veja como fazer isso no guia de n8n com WhatsApp.
Perguntas frequentes
Quando vale a pena construir o webhook por conta própria?
Construir o endpoint faz sentido quando o seu time precisa de controle total sobre os eventos, como gravar cada status em um sistema próprio. Se o objetivo é apenas atender os clientes pelo WhatsApp, manter servidor, assinatura e fila de eventos é trabalho que muitos times preferem evitar. A Chatsac é uma plataforma de atendimento e CRM que roda na API oficial da Meta. Veja como funciona a API oficial do WhatsApp com a Chatsac. E no seu caso, o gargalo está em receber os eventos ou em organizar o atendimento depois que eles chegam?
Perguntas frequentes
Fontes
- https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/overview
- https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/create-webhook-endpoint
- https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/reference/messages/status
- https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/reference/messages
- https://developers.facebook.com/docs/graph-api/webhooks/getting-started
- https://developers.facebook.com/documentation/business-messaging/whatsapp/solution-providers/manage-webhooks
- https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing


