Webhooks do WhatsApp: eventos, segurança e novas tentativas
Como funcionam os webhooks do WhatsApp: eventos de mensagem e status, handler confiável, assinatura da Meta, retries, idempotência e eventos perdidos.
Por OmniChannels.ai Editorial Team · Revisado por BroadNet Messaging Solutions Team
Integração
Resposta curta
Um webhook do WhatsApp é um endpoint HTTPS no seu servidor que recebe eventos: status de entrega das mensagens que você enviou e mensagens que os clientes enviam para você. Com a OmniChannels.ai, os status chegam como SUBMITTED, SENT, DELIVERED, READ, FAILED ou REJECTED. Guarde o corpo bruto, responda 2xx rapidamente, deduplique pelo ID da mensagem e processe de forma assíncrona. A Meta assina seus próprios webhooks; nossa documentação não define cabeçalho de assinatura, então proteja o seu endpoint no nível do transporte e da aplicação.
Nesta página
- O que são webhooks do WhatsApp e por que usá-los?
- Quais eventos e status vou receber?
- Como configuro o endpoint?
- Como é o payload?
- Como escrevo um handler confiável?
- Como protejo um webhook do WhatsApp?
- O que acontece quando a entrega falha?
- Como recupero eventos perdidos?
- Exemplo prático: o pipeline de notificações de uma varejista
- Quais são os erros comuns?
- Como a OmniChannels.ai ajuda
Pontos principais
- Os webhooks enviam por push status e mensagens recebidas ao seu endpoint HTTPS para que você não precise fazer polling; os status do WhatsApp são normalizados para SUBMITTED, SENT, DELIVERED, READ, FAILED e REJECTED.
- Um handler confiável faz três coisas, nesta ordem: armazena o evento bruto, devolve 2xx e só então processa de forma assíncrona e idempotente.
- Os status podem chegar fora de ordem ou duplicados, então atribua uma ordem de avanço a eles e nunca deixe um SENT tardio sobrescrever um DELIVERED já armazenado.
- A Meta assina os webhooks enviados a apps com o cabeçalho X-Hub-Signature-256, mas a especificação da API da OmniChannels.ai não define assinatura de webhook, então use HTTPS, um caminho imprevisível e validação do corpo.
- Se eventos foram perdidos, leia o status do WhatsApp por lote no endpoint bulk-insights em vez de reenviar mensagens.
Este guia é para engenheiros que precisam receber eventos do WhatsApp de forma confiável: status de entrega das mensagens que enviam e mensagens recebidas de clientes. Ele explica como os webhooks funcionam, o que construir no handler, como a segurança difere entre os webhooks da Meta e os nossos e o que fazer quando eventos se perdem.
O que são webhooks do WhatsApp e por que usá-los?
Webhooks do WhatsApp são callbacks HTTP. Quando uma mensagem muda de estado ou um cliente escreve para você, a plataforma envia um POST com um corpo JSON ao seu endpoint. Você não precisa fazer polling e vê os eventos conforme acontecem.
Duas famílias de eventos importam:
- Eventos de status das mensagens que você enviou: enfileirada, enviada, entregue, lida, com falha.
- Mensagens recebidas de clientes, que abrem ou estendem a janela de atendimento ao cliente de 24 horas. Veja nosso guia da janela.
Uma chamada de envio apenas informa que as mensagens foram enfileiradas. O webhook é onde você descobre o que aconteceu com cada destinatário.
Quais eventos e status vou receber?
Na OmniChannels.ai, todos os canais informam os mesmos status normalizados, então um único handler pode atender WhatsApp, SMS e os demais.
| Status | Significado | Final? |
|---|---|---|
SUBMITTED |
Aceita pela plataforma e enfileirada | Não |
SENT |
Entregue ao canal | Não |
DELIVERED |
Confirmada no dispositivo do destinatário | Normalmente; READ pode vir depois |
READ |
Aberta pelo destinatário, onde o canal informa leituras | Sim |
FAILED |
Não entregue; o evento traz um motivo, quando disponível | Sim |
REJECTED |
Recusada, por exemplo por conteúdo bloqueado ou remetente não registrado | Sim |
Trate os status como uma progressão que pode chegar fora de ordem e espere novos valores ao longo do tempo. Não falhe diante de um status que você não reconhece. Veja status de entrega de mensagens explicados.
Como configuro o endpoint?
Exponha um endpoint HTTPS, informe a URL ao seu provedor e teste com o seu próprio número.
- Crie um endpoint que aceite
POSTcom um corpo JSON, por exemplohttps://api.example.com/webhooks/omnichannels. - Envie a URL à nossa equipe ou ao administrador da sua conta para configurá-la na sua conta. Os revendedores podem ter um webhook separado por subconta.
- Envie uma mensagem de teste para o seu próprio número e confirme que os eventos chegam.
Durante o desenvolvimento, um túnel como o ngrok dá ao seu servidor local uma URL HTTPS pública. Se você também conectar um app diretamente à Meta, a verificação de endpoint da Meta é uma etapa separada: uma requisição GET com um verify token e um valor hub.challenge, à qual você responde 200 com o challenge, como descrito na documentação de endpoint de webhook da Meta.
Como é o payload?
Varia por canal. A especificação da API não define um único esquema de webhook, então registre primeiro o corpo bruto e mapeie os campos de que precisa a partir de eventos reais da sua conta. O exemplo mostra o tipo de informação que um evento de entrega traz e é apenas ilustrativo.
{
"messageId": "2603121407537573731",
"channel": "SMS",
"destination": "447700900123",
"status": "DELIVERED",
"timestamp": "2026-10-10T09:15:42Z",
"reason": null
}
Não programe com base nesses nomes de campos sem conferir um evento real. Peça ao seu engenheiro de onboarding exemplos de payload por canal e guarde-os como fixtures de teste. Para a documentação mais ampla, veja a referência de webhooks.
Como escrevo um handler confiável?
Faça três coisas, nesta ordem: armazene o evento bruto, confirme com um 2xx e depois processe de forma assíncrona. O handler abaixo segue o padrão da nossa documentação.
import express from "express";
const app = express();
// Capture o corpo bruto para guardá-lo exatamente como foi recebido.
app.post(
"/webhooks/omnichannels",
express.json({ verify: (req, _res, buf) => { req.rawBody = buf.toString("utf8"); } }),
async (req, res) => {
try {
await db.webhookEvents.insert({ receivedAt: new Date(), body: req.rawBody });
} catch (err) {
return res.sendStatus(500); // o armazenamento falhou: deixe o evento ser reenviado
}
res.sendStatus(200); // confirme rápido
queue.publish("status-events", req.body); // faça o trabalho de verdade em outro lugar
},
);
// Worker: processamento idempotente
async function processEvent(event) {
const id = event.messageId ?? event.message_id ?? event.id; // mapeie por canal
const status = event.status;
const rank = { SUBMITTED: 1, SENT: 2, DELIVERED: 3, READ: 4, FAILED: 4, REJECTED: 4 };
const current = await db.messages.findOne({ providerId: id });
if (!current) return; // mensagem desconhecida: registre e investigue
if ((rank[status] ?? 0) <= (rank[current.status] ?? 0)) return; // duplicado ou desatualizado
await db.messages.update({ providerId: id }, { status, updatedAt: new Date() });
}
from datetime import datetime, timezone
from flask import Flask, request
app = Flask(__name__)
RANK = {"SUBMITTED": 1, "SENT": 2, "DELIVERED": 3, "READ": 4, "FAILED": 4, "REJECTED": 4}
@app.post("/webhooks/omnichannels")
def omnichannels_webhook():
raw = request.get_data(as_text=True)
try:
db.webhook_events.insert({"received_at": datetime.now(timezone.utc), "body": raw})
except Exception:
return "", 500 # o armazenamento falhou: deixe o evento ser reenviado
queue.publish("status-events", raw) # processe de forma assíncrona
return "", 200 # confirme rápido
Os objetos db e queue são o seu próprio armazenamento e fila de jobs. O mapa rank é o que torna o processamento idempotente: um evento duplicado ou desatualizado não representa um avanço, então é ignorado.
Regras para um handler confiável
- Responda em poucos segundos. Não faça trabalho pesado antes de responder.
- Devolva
2xxapenas depois que o evento estiver armazenado. Se o armazenamento falhar, devolva5xx. - Deduplique pelo ID da mensagem. O mesmo status pode chegar mais de uma vez.
- Nunca reenvie uma mensagem a partir do handler. Decida sobre novas tentativas em um job separado, depois de conferir o status.
- Guarde o corpo bruto para diagnóstico e para reproduzir eventos depois de uma correção.
Como protejo um webhook do WhatsApp?
Depende de quem envia ao seu endpoint. A Meta assina os webhooks que envia a apps registrados nela. A especificação da API da OmniChannels.ai não define cabeçalho de assinatura de webhook, então não espere por um.
| Meta para o seu próprio app | OmniChannels.ai para o seu endpoint | |
|---|---|---|
| Assinatura | Cabeçalho X-Hub-Signature-256, conforme a documentação da Meta |
Nenhuma definida na especificação da API |
| Verificação | HMAC-SHA256 do payload bruto com o segredo do app, comparado com o cabeçalho | Não se aplica |
| Seus controles | Verificar a assinatura em todo POST |
HTTPS com certificado válido, um caminho imprevisível, validação rigorosa do corpo |
Para o esquema da Meta, a documentação dela diz para gerar um hash HMAC-SHA256 do payload JSON usando o segredo do seu app e compará-lo com o valor após sha256= no cabeçalho X-Hub-Signature-256. O próprio HMAC é definido na RFC 2104. Calcule-o sobre os bytes brutos, não sobre um objeto serializado de novo, e compare em tempo constante.
Para o nosso endpoint:
- Use apenas HTTPS, com um certificado válido.
- Use um caminho longo e imprevisível e troque-o se vazar.
- Valide o formato do corpo e rejeite qualquer coisa inesperada.
- Trate os eventos como notificações. Antes de uma ação irreversível, como um reembolso ou um bloqueio por fraude, confirme o estado com uma consulta.
O que acontece quando a entrega falha?
As novas tentativas dependem de quem envia. A documentação da Meta diz que ela repete uma entrega com falha com frequência decrescente por até 7 dias, o que pode gerar notificações duplicadas. Esse é um motivo para ser idempotente mesmo que você raramente veja duplicatas. Para eventos da nossa plataforma, confirme o comportamento de novas tentativas com o seu engenheiro de onboarding em vez de presumir que seja igual ao da Meta.
De todo modo, construa pensando tanto em perda quanto em duplicação: seu endpoint pode estar fora do ar durante um deploy, e uma regra de firewall pode descartar requisições silenciosamente.
Como recupero eventos perdidos?
Consulte o lote, não reenvie a mensagem.
| Necessidade | Chamada | Observações |
|---|---|---|
| Ler o status do WhatsApp por destinatário | GET /whatsapp/message/bulk-insights |
Filtre um lote por status ou destination; paginado com page e size |
| Reenviar relatórios de entrega de SMS | POST /sms/resendDlr |
Filtre por startDate, endDate, senderId e messageStatus |
curl "https://api.broadnet.me/whatsapp/message/bulk-insights?batch_Id=2609091405000000001&page=0&size=100" \
-H "Authorization: Bearer $BROADNET_TOKEN"
batch_Id é o ID devolvido pela chamada de envio, e page começa em zero. Execute uma conciliação noturna que leia os lotes do dia anterior e preencha as lacunas.
Checklist de solução de problemas
- A URL está configurada na conta ou subconta correta?
- O endpoint é acessível por HTTPS com um certificado válido?
- Ele responde
2xxrapidamente ou dá timeout? - Uma regra de firewall ou de WAF está bloqueando as requisições?
- Você registra o corpo bruto antes de fazer o parsing, para que um erro de parser não esconda o evento?
Exemplo prático: o pipeline de notificações de uma varejista
A "Souq Rafiq" (sintética), uma varejista dos Emirados Árabes Unidos, envia atualizações de pedidos por WhatsApp e quer um status preciso na sua ferramenta de pedidos.
- Os pedidos são enviados com
sendbulk, e obatchIdé guardado no pedido. Veja enviar uma mensagem de WhatsApp por API. - O endpoint do webhook grava cada evento em uma tabela e depois devolve
200. - Um worker ordena os status e atualiza o estado da mensagem do pedido.
- Eventos
FAILEDcriam uma tarefa para o suporte com o motivo, e um fallback por SMS é avaliado conforme o fallback entre canais. - As mensagens recebidas de clientes são encaminhadas à caixa de entrada compartilhada para que os atendentes respondam dentro da janela.
- Um job noturno chama o
bulk-insightspara os lotes de ontem e corrige o que tiver sido perdido.
Quais são os erros comuns?
- Trabalho pesado antes de responder, que causa timeouts e entregas repetidas.
- Confirmar antes de armazenar, o que perde eventos quando o armazenamento falha.
- Confiar na ordem. Um
SENTtardio sobrescrevendoDELIVERED. - Programar com base no payload ilustrativo em vez de eventos reais.
- Serializar o JSON de novo antes de verificar uma assinatura, o que altera os bytes.
- Reenviar a partir do handler, o que pode gerar loops.
- Limites: este guia descreve o comportamento documentado por nós. A política de novas tentativas e os campos do payload da sua conta devem ser confirmados durante o onboarding.
Como a OmniChannels.ai ajuda
A OmniChannels.ai envia por push status de entrega e mensagens recebidas de WhatsApp, SMS, RCS e outros canais ao seu webhook em um único formato normalizado, com webhooks separados por subconta para revendedores. A BroadNet é uma Meta Business Solution Provider oficial, então os requisitos de webhook da própria Meta são tratados por nós, e você trabalha com a nossa API. Leia a referência de webhooks e a documentação da API de WhatsApp ou veja como os eventos aparecem na caixa de entrada compartilhada.
Perguntas frequentes
O que é um webhook do WhatsApp?
Um webhook do WhatsApp é uma URL no seu servidor que a plataforma chama com um HTTP POST sempre que algo acontece, como uma mensagem ser entregue, lida ou falhar, ou um cliente enviar uma mensagem para você. Ele substitui o polling. Você expõe um endpoint HTTPS, compartilha-o com o seu provedor e processa os eventos JSON que ele recebe.
Como verifico a assinatura de um webhook do WhatsApp?
Para um webhook que a Meta envia diretamente ao seu próprio app, a documentação da Meta diz para calcular um HMAC-SHA256 do payload bruto com o segredo do seu app e compará-lo com o cabeçalho X-Hub-Signature-256. Para o webhook da OmniChannels.ai, a especificação da API não define cabeçalho de assinatura, então conte com HTTPS, um caminho imprevisível e a validação do corpo.
O que acontece se o meu endpoint de webhook estiver fora do ar?
A documentação da Meta diz que ela repete as entregas com falha com frequência decrescente por até 7 dias, o que pode gerar duplicatas. Para eventos da nossa plataforma, confirme o comportamento de novas tentativas com o seu engenheiro de onboarding e use o endpoint bulk-insights para ler o status do WhatsApp por destinatário de um lote. No SMS, o endpoint resendDlr reenvia os relatórios.
Como trato eventos de webhook duplicados?
Torne o processamento idempotente. Busque a mensagem pelo ID, compare a ordem do status recebido com a do armazenado e ignore eventos que não representem um avanço. Aplicar o mesmo evento duas vezes deve ter o mesmo efeito que aplicá-lo uma vez. Guarde o corpo bruto de cada evento para poder reproduzi-lo depois de corrigir um bug.
Com que rapidez o meu endpoint deve responder?
Em poucos segundos. Guarde o evento bruto, devolva um 2xx e faça o trabalho de verdade em uma fila ou worker. Não chame outros serviços, não envie mensagens nem execute consultas pesadas antes de responder. Se o armazenamento falhar, devolva um 5xx para que o remetente tente de novo, em vez de confirmar um evento que você perdeu.
Posso usar um webhook para enviar uma resposta automaticamente?
Sim, mas não de dentro do handler. Confirme o evento e depois decida a resposta em um job separado. Dentro da janela de atendimento ao cliente de 24 horas você pode enviar uma mensagem livre; fora dela, precisa de um template aprovado. Nunca reenvie uma mensagem a partir do próprio handler do webhook, para evitar loops e duplicatas.
Fontes
Continue lendo
Mais guiasIntegração
Enviar mensagem de WhatsApp por API: cURL, Node, Python, PHP
Como enviar mensagem de WhatsApp por API: exemplos funcionais em cURL, Node.js, Python e PHP para templates e mensagens de sessão, além de rastreamento e erros.
10 min de leitura
Integração
Integração do WhatsApp com CRM: 3 formas de conectar e sincronizar
Integração WhatsApp e CRM explicada: conectores nativos, middleware ou API com webhooks, fluxo de dados, mapeamento de campos, sincronia de consentimento e checklist.
10 min de leitura
WhatsApp
Mensagens gratuitas na API do WhatsApp Business em 2026
Quais mensagens da API do WhatsApp Business são grátis em 2026: 1.000 mensagens de serviço por número, janela de entrada gratuita de 72 horas e o que é cobrado.
9 min de leitura
