Webhook: receber as mensagens no seu servidor
Seu sistema recebe cada mensagem que chega ao WhatsApp, assinada, e, se quiser, os avisos de conexão. Veja o que chega, como validar e os limites.
Com o webhook, o seu servidor recebe um aviso (um POST em JSON) a cada mensagem que chega ao seu WhatsApp, sem ficar consultando. A mensagem sai do seu ambiente Coloquia direto para o endereço que você escolher: o conteúdo não passa pelo nosso painel, que guarda só o endereço e o segredo.
Como ligar
- No portal, abra Conectar a IA, clique em Configurar o webhook e informe o endereço do seu servidor:
https, público e na porta 443. - Copie o segredo (aparece uma única vez; se perder, gere outro) e use Enviar teste para receber um evento de exemplo (
event=webhook.test).
Pela API, as mesmas ações ficam em /api/v1/webhook (GET, PUT, DELETE), /api/v1/webhook/secret e /api/v1/webhook/test. Se a sua conta tem passkey, ligar, trocar o endereço e gerar segredo só funcionam no portal, com a confirmação da passkey.
O que chega
Cada entrega traz três cabeçalhos: X-Coloquia-Id (o identificador do evento, igual ao event_id do corpo), X-Coloquia-Timestamp (segundos Unix) e X-Coloquia-Signature.
{"event_id": "00112233445566778899aabbccddeeff", "event": "message.received", "message_id": "ID-DE-EXEMPLO",
"chat": "[email protected]", "sender": "[email protected]", "type": "text",
"text": "Bom dia!", "timestamp": "2026-10-13T12:00:00Z", "from_me": false, "stored": true}
Por padrão chegam só as mensagens que outras pessoas mandam para você nas conversas. O resto você liga em O que enviar (veja abaixo).
Se o seu sistema responde sozinho, ignore os eventos com from_me igual a true, a menos que você tenha ligado Mensagens enviadas pelo seu número. Em ambientes que ainda não foram atualizados (a atualização é feita por nós), as mensagens do próprio número podem chegar mesmo com a opção desligada, e um sistema que reage a elas responde às próprias respostas, sem parar.
Mídia não é enviada. Foto, áudio, vídeo e documento chegam com o type, a legenda em text e uma referência em media_reference; o arquivo você busca pela sua IA conectada.
O que enviar
Na tela do webhook, o bloco O que enviar tem quatro opções, todas desligadas no começo. Ligar qualquer uma amplia o que sai do seu ambiente, então o portal pede confirmação (e a passkey, se a sua conta tiver). Desligar nunca é recusado: a escolha fica guardada na hora e chega ao seu ambiente em alguns segundos (a tela mostra "Aplicando" enquanto isso). Também dá para desligar pela API (PUT /api/v1/webhook com o mesmo endereço e o campo em false), mesmo com passkey na conta; ligar, só no portal.
- Mudanças de conexão (
connection_events): eventosconnection.changed, explicados abaixo. - Mensagens enviadas pelo seu número (
forward_self): chegam também comomessage.received, comfrom_meigual atrue, tanto as que você escreve no celular quanto as que a sua IA envia. Vem desligado porque um sistema que responde sozinho reagiria às próprias respostas: se ligar, ignore os eventos comfrom_meigual atrueantes de responder. - Canais (
forward_channels): as publicações dos canais que o seu número segue, comchatterminando em@newsletter. - Listas de transmissão (
forward_broadcasts): as mensagens das listas de transmissão, comchatterminando em@broadcast.
Os status dos seus contatos nunca são enviados: são publicações para todos os contatos, não conversas. Em um ambiente que ainda não recebeu a atualização (feita por nós), a tela avisa que as opções chegam com ela: a sua escolha fica guardada e, até lá, só as mensagens recebidas são enviadas. Se a configuração do seu ambiente proibir uma opção, ela aparece como proibida pela configuração do ambiente: não é enviada, e as outras continuam valendo.
Ao trocar o endereço ou religar o webhook, as opções voltam a desligadas: ligue de novo as que quiser para o destino novo.
O evento de conexão
Com Mudanças de conexão ligado, o seu servidor recebe um aviso quando o número muda de situação. Ele não traz número, conversa nem mensagem:
{"event_id": "ffeeddccbbaa99887766554433221100", "event": "connection.changed", "type": "connection",
"state": "disconnected", "reason": "transport_lost", "at": "2026-10-13T12:00:00Z"}
O campo state diz o que aconteceu:
connected: o número está conectado e recebendo mensagens.disconnected: a conexão caiu. Quedas que voltam em menos de 5 segundos não geram aviso. Se o WhatsApp restringiu o número, o evento traz tambémconnection_problem, com o tipo da restrição emkind.logged_out: o número saiu da conta (pelo celular ou pelo portal). A entrega de mensagens para até um novo pareamento.pairing_required: o ambiente espera um novo pareamento. Abra o portal para conectar de novo.paired: o pareamento acabou de terminar.
at é o horário da mudança, e reason é um rótulo técnico, útil para o suporte. Ao ligar a opção, o seu servidor recebe na hora o estado atual, com o at de quando ele começou: um sistema configurado agora já sabe, por exemplo, que o número espera pareamento.
Como validar a assinatura
A assinatura é sha256= seguido do HMAC-SHA256, com o seu segredo, de <timestamp>.<corpo>. Use o corpo exatamente como chegou, sem reescrever o JSON.
import hashlib, hmac, json, time
def verify_webhook(headers, raw_body, secret, prefix="X-Coloquia"):
timestamp = headers.get(prefix + "-Timestamp", "")
try:
signature = headers.get(prefix + "-Signature", "").encode("ascii")
fresh = abs(int(time.time()) - int(timestamp)) <= 300
signed = timestamp.encode("ascii") + b"." + raw_body
except (ValueError, TypeError, UnicodeError):
return False
expected = "sha256=" + hmac.new(secret.encode("utf-8"), signed, hashlib.sha256).hexdigest()
if not fresh or not hmac.compare_digest(expected.encode("ascii"), signature):
return False
try:
event = json.loads(raw_body)
except (ValueError, UnicodeError):
return False
event_id = event.get("event_id") if isinstance(event, dict) else None
return isinstance(event_id, str) and bool(event_id) and event_id == headers.get(prefix + "-Id")
Responda com um status 2xx em até 10 segundos. A mesma entrega pode chegar mais de uma vez, de mensagem ou de conexão: guarde o event_id, ignore o que já processou e responda 2xx também à repetição.
Limites
- Cada evento tem até cinco tentativas, por até cinco minutos. Respostas
4xx(menos 408 e 429) não são repetidas. A fila fica na memória do seu ambiente: 256 eventos. O que passar disso, ou estiver na fila quando o ambiente reiniciar, é perdido. Depois de um reinício, a entrega volta sozinha em alguns minutos; o que chegar nesse intervalo não é enviado. - Depois de 50 eventos seguidos sem sucesso, o webhook é desligado e você recebe um e-mail. O mesmo acontece se o endereço deixar de ser aceito (domínio vencido, ou que passou a apontar para uma rede interna). Para religar, salve o endereço de novo. As mensagens continuam todas disponíveis para a sua IA, com ou sem webhook.