Webhooks
O gateway avisa o seu sistema do que acontece: mensagem recebida, entrega, falha, conexão do número. Configure o endereço em Conta → Configurações → Avisos para o seu sistema.
Eventos
| Evento | Quando |
|---|---|
message.received |
Um contato escreveu para o número |
message.queued |
A mensagem entrou na fila |
message.sent |
Saiu pelo WhatsApp |
message.delivered |
Chegou ao aparelho |
message.read |
Foi lida |
message.failed |
Não chegou. Traz error (texto) e reason (código: failed, blocked, invalid_number, assinatura_suspensa ou resposta_vencida, quando a resposta do agente ou do painel esperou mais de 30 min para sair e foi descartada; no número oficial também fora_da_janela, template_invalido, pagamento_meta, limite_da_meta, meta_nao_entregou, midia_invalida, conta_bloqueada e credencial_meta) |
message.echo |
Alguém da empresa respondeu pelo celular ou pelo WhatsApp Web (número QR, ou oficial em coexistência). Traz to, body, id e sent_at; se foi arquivo, media como no message.received, com a url de GET /v1/media/{instance}/{id}: baixe assim que o evento chegar |
template.status |
Número oficial: um template foi aprovado, rejeitado, pausado… Traz name, language, status e reason |
conversation.history |
Número oficial em coexistência: as conversas antigas do WhatsApp Business do celular, por contato (from), em lotes de até 100 messages com id, direction (in/out), body e sent_at. Grave sem abrir a janela de 24 h, sem marcar como não lida e sem acionar o agente; ignore id repetido |
instance.connected |
O número conectou |
instance.disconnected |
O número caiu, com o motivo |
webhook.test |
Só quando você clica em Testar webhook no painel |
Cabeçalhos
| Cabeçalho | O que é |
|---|---|
X-Signature |
sha256= e o HMAC-SHA256 do corpo, com o token do projeto como segredo |
Idempotency-Key |
Identifica a entrega. Ignore repetições |
X-Event |
O nome do evento |
Conferindo a assinatura
Calcule o HMAC sobre os bytes exatos do corpo, como chegaram. Reserializar o JSON muda espaços e ordem e a conta não bate.
$corpo = file_get_contents('php://input');
$esperada = 'sha256='.hash_hmac('sha256', $corpo, $tokenDoProjeto);
if (! hash_equals($esperada, $_SERVER['HTTP_X_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
import { createHmac, timingSafeEqual } from 'node:crypto';
function confere(corpoBruto, assinatura, token) {
const esperada = 'sha256=' + createHmac('sha256', token).update(corpoBruto).digest('hex');
const a = Buffer.from(esperada);
const b = Buffer.from(assinatura ?? '');
return a.length === b.length && timingSafeEqual(a, b);
}
Entrega e reenvio
Responda 2xx para confirmar. Qualquer outra resposta, ou falta de resposta em 15 segundos, é tentada de novo depois de 1 minuto, 5 minutos, 15 minutos, 1 hora e 6 horas. Cada tentativa fica registrada em Integração → Webhooks, onde também dá para reenviar uma entrega que desistiu. O evento webhook.test não é repetido.
Como a mesma entrega pode chegar mais de uma vez, use o Idempotency-Key para ignorar repetições.