Webhook na API de WhatsApp: como receber mensagens e eventos
O webhook é a URL do seu sistema que a API chama sempre que algo acontece no WhatsApp: mensagem nova, mensagem lida, conexão que caiu. Sem ele, sua aplicação só fala; com ele, ela também escuta e reage.
O papel do webhook numa integração de WhatsApp
Enviar mensagem é a parte simples. O difícil é saber o que aconteceu depois: o cliente respondeu? Leu? O número desconectou no meio da madrugada? Numa API de WhatsApp, quem responde a essas perguntas é o webhook. A cada evento, a API faz um POST para uma URL que você controla, com um JSON descrevendo o ocorrido.
Isso inverte a lógica de integração. Em vez de o seu backend ficar perguntando "chegou algo?" a cada poucos segundos, ele só trabalha quando existe trabalho. Para um produto com centenas de conexões, é a diferença entre uma fila tranquila e milhares de requisições inúteis por minuto.
Como configurar: uma URL ou uma URL por evento
O caminho mais curto é informar a URL ao criar a conexão (campo webhookUrl) ou depois, com POST /api/v1/sessions/{sessionId}/webhook. Quando você quer escolher quais eventos recebe, use o endpoint de configuração completa:
curl -X POST https://api.d-api.cloud/api/v1/sessions/minha-sessao/webhook-config \
-H "Authorization: SUA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"type": "per_event",
"events": {
"messages.received": { "enabled": true, "webhookUrl": "https://app.suaempresa.com/wa/k7f2q9/mensagens" },
"connection.status": { "enabled": true, "webhookUrl": "https://app.suaempresa.com/wa/k7f2q9/conexao" }
}
}'Os dois modos atendem necessidades diferentes:
single: todos os eventos habilitados vão para a mesma URL. Bom para começar ou quando um único serviço recebe tudo e distribui internamente.per_event: cada evento tem seu destino. Útil quando atendimento, monitoramento e analytics são serviços separados.
Evento desabilitado não é enviado, então ligue só o que você vai processar.
Envelope e eventos que você vai usar primeiro
Todo evento chega no mesmo envelope: event (nome do evento), sessionId (qual conexão gerou), data (o conteúdo específico), timestamp em ISO 8601 e traceId, que vale guardar nos logs para cruzar com o suporte. Os headers são Content-Type: application/json e User-Agent: Deliverify-Webhook/1.0.
| Evento | Quando dispara | Uso típico |
|---|---|---|
messages.received | Chegou mensagem (ou você mandou pelo celular) | Caixa de entrada, chatbot, CRM |
messages.sent | Mensagem enviada pela API | Registrar histórico do envio |
message.delivered / message.read | Entregue e lida pelo destinatário | Status de entrega na interface |
connection.status | Status mudou para connected, disconnected ou logged_out | Alertar o cliente antes que ele perceba |
groups_participants.join e afins | Entrada, saída ou promoção em grupo | Controle de membros |
Um detalhe que pega muita gente: não existe evento de edição separado. Mensagem editada chega como messages.received com type: "edited_message".
O payload de uma mensagem recebida
É o evento que mais importa. O data traz o id da mensagem, o type (texto, imagem, áudio, resposta de lista e outros), o conteúdo em message, quem mandou em from, se veio de grupo em is_group e, para mídia, o link em media_url:
{
"event": "messages.received",
"sessionId": "cliente-042",
"timestamp": "2026-01-24T22:51:32.601Z",
"traceId": "c17dee440402792623e3ad6d925cb000",
"data": {
"id": "AC9831DDA691236BA3CE4909A187B703",
"type": "text",
"message": "Quero remarcar para sexta",
"timestamp": 1769295092000,
"fromMe": false,
"is_group": false,
"from": { "jid": "[email protected]", "name": "Marina" },
"from_name": "Marina",
"media_url": null
}
}Repare em fromMe: ele vem true quando alguém respondeu pelo próprio celular do número conectado. Se o seu robô reage a toda mensagem, filtre esse caso para não responder a si mesmo.
Política de entrega: o que a API garante e o que fica com você
Na D-API, se o seu endpoint falhar, a entrega é repetida até 7 vezes com backoff exponencial, com intervalos de aproximadamente 5s, 10s, 20s, 40s, 80s e 160s. Cada tentativa espera no máximo 30 segundos pela resposta. Respostas 404 e 410 são tratadas como falha permanente e encerram as tentativas. Há também um circuit breaker por URL e deduplicação de eventos com janela de 5 minutos.
Na prática, uma queda curta do seu servidor ou um deploy demorado não faz você perder mensagens. Uma rota apagada por engano, que devolve 404, faz. Por isso vale monitorar a taxa de erro do endpoint de webhook como qualquer rota crítica.
Checklist do receptor de webhook
- Responda 2xx em milissegundos. Grave o evento numa fila e devolva
200. Chamar LLM, CRM ou banco pesado antes de responder estoura os 30 segundos e gera reenvio. - Seja idempotente pelo
data.id. A deduplicação da API cobre janelas curtas; um reenvio pode chegar depois. Guarde os IDs processados e ignore repetidos. - Proteja a URL. Como não há HMAC, coloque um token longo e aleatório no caminho, confira o
User-Agente rejeitesessionIdque não existe na sua base. - Não devolva 404 durante deploy. Se a rota some por alguns segundos, as tentativas param. Prefira 503, que entra no ciclo de reenvio.
- Logue o
traceId. Sem dado pessoal no log, só o identificador do evento.
app.post('/wa/:token/mensagens', async (req, res) => {
if (req.params.token !== process.env.WA_WEBHOOK_TOKEN) return res.sendStatus(401)
const { event, sessionId, data, traceId } = req.body
await queue.add('wa-event', { event, sessionId, data, traceId }, { jobId: data.id })
res.sendStatus(200)
})O jobId igual ao ID da mensagem faz a própria fila descartar duplicados. O processamento real (responder, salvar, chamar a IA) acontece no worker. Esse é o mesmo desenho usado num chatbot de WhatsApp com IA.
Quando trocar HTTP por RabbitMQ
Se o seu volume é alto ou você já opera um broker, a D-API pode publicar os eventos direto num RabbitMQ seu, configurado por conexão em /sessions/{sessionId}/rabbitmq-config. Alguns eventos de sincronização de histórico só existem nesse canal. Veja a página da integração com RabbitMQ.
Para entender o caminho completo, da conexão do número ao primeiro evento, leia como funciona a API de WhatsApp. Se o seu produto vai receber eventos de muitos clientes ao mesmo tempo, o desenho por conexão está em múltiplos números e na página de API de WhatsApp para SaaS.
Perguntas frequentes
Qual a diferença entre webhook e consultar a API de tempos em tempos?
Consultar periodicamente (polling) obriga seu sistema a perguntar se há novidade, gastando requisições e chegando atrasado. Com webhook, a API avisa sua URL no momento em que o evento acontece, e você só processa o que realmente mudou.
O webhook de WhatsApp da D-API tem assinatura HMAC?
Não. Os eventos de WhatsApp chegam sem assinatura. A recomendação é usar uma URL secreta, com um token longo no caminho, e conferir no receptor o User-Agent e se o sessionId pertence a uma conexão sua.
O que acontece se meu servidor ficar fora do ar?
A entrega é repetida até 7 vezes com intervalos crescentes, de cerca de 5 segundos até 160 segundos. Se o servidor voltar dentro dessa janela, o evento chega. Respostas 404 ou 410 encerram as tentativas para aquela URL.
Posso mandar eventos diferentes para URLs diferentes?
Sim. No modo per_event cada evento tem a própria URL, o que permite, por exemplo, mandar mensagens recebidas para o serviço de atendimento e mudanças de conexão para o serviço de monitoramento.
Como testar o webhook localmente?
A API precisa alcançar sua URL pela internet. Durante o desenvolvimento, use um túnel que exponha a porta local com HTTPS e cadastre essa URL temporária na conexão de teste. Em produção, troque pela URL definitiva.
Continue lendo
Teste a API de WhatsApp da D-API
Trial de 3 dias com acesso completo. Sem cartão, sem fidelidade.