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.

EventoQuando disparaUso típico
messages.receivedChegou mensagem (ou você mandou pelo celular)Caixa de entrada, chatbot, CRM
messages.sentMensagem enviada pela APIRegistrar histórico do envio
message.delivered / message.readEntregue e lida pelo destinatárioStatus de entrega na interface
connection.statusStatus mudou para connected, disconnected ou logged_outAlertar o cliente antes que ele perceba
groups_participants.join e afinsEntrada, saída ou promoção em grupoControle 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

  1. 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.
  2. 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.
  3. Proteja a URL. Como não há HMAC, coloque um token longo e aleatório no caminho, confira o User-Agent e rejeite sessionId que não existe na sua base.
  4. Não devolva 404 durante deploy. Se a rota some por alguns segundos, as tentativas param. Prefira 503, que entra no ciclo de reenvio.
  5. 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.

Teste a API de WhatsApp da D-API

Trial de 3 dias com acesso completo. Sem cartão, sem fidelidade.