Skip to content

Eventos webhook

Hub emite 10 eventos webhook. Esta pagina documenta cada um. Pra contrato geral (HMAC, retry), ver Webhook contract.

Eventos de mensagem

message.received

Disparado pra cada mensagem nova recebida pelo chip (ou enviada manualmente do celular pareado, se receive_self_chat=true).

{
"event": "message.received",
"timestamp": "2026-04-30T12:34:56.789Z",
"data": {
"message_id": "01HZTQMSG...",
"chip_id": "01HZTQCHIP...",
"wa_message_id": "BAE5...",
"from": "5511988887777@s.whatsapp.net",
"to": "5511999998888:30@s.whatsapp.net",
"direction": "in",
"type": "text",
"content": { "text": "ola" },
"timestamp": "2026-04-30T12:34:55.000Z",
"sender": {
"jid": "5511988887777@s.whatsapp.net",
"name": "Maria",
"phone_number": "5511988887777",
"lid": "12345678901234@lid",
"is_business": false,
"verified_business_name": null
},
"chat": {
"jid": "5511988887777@s.whatsapp.net",
"is_group": false,
"name": null,
"participants": null,
"participants_count": null
}
}
}

Campos chave

CampoNotas
direction'in' recebida; 'out' enviada do celular pareado (precisa opt-in)
sender.jidJID do humano que enviou (em grupo == participant, em 1-1 == from)
sender.namepushName (editavel pelo proprio remetente)
sender.phone_numbertelefone “puro” (so digitos). Vazio quando WA nao expoe
sender.lidLID alternate quando WA expoe — cross-match LID↔telefone
sender.is_businesstrue se conta WhatsApp Business verificada
sender.verified_business_namenome verificado pelo WA (null em conta pessoal)
chat.is_groupderivado de chat.jid terminar em @g.us
chat.participantsso em grupo: [{jid, admin: 'admin'|'superadmin'|null}]

Tipos de content por type

// type: text
{ "text": "..." }
// type: image / audio / document / video
{ "mimetype": "...", "media_id": "01HZTQ...", "caption": "...", ... }
// type: location
{ "lat": -23.5505, "lng": -46.6333, "name": "...", "address": "..." }
// type: reaction
{ "emoji": "❤️", "to_wa_message_id": "BAE5..." }
// type: unknown (protocolo Baileys que nao sabemos parsear)
{ "kind": "..." }

message.status

Mudanca de status de mensagem outbound (sent → delivered → read → failed).

{
"event": "message.status",
"timestamp": "...",
"data": {
"message_id": "01HZTQMSG...",
"chip_id": "01HZTQCHIP...",
"wa_message_id": "BAE5...",
"status": "delivered"
}
}

message.transcribed

Audio transcrito (so pra apps com transcribe_audio_mode != 'off').

{
"event": "message.transcribed",
"timestamp": "...",
"data": {
"message_id": "01HZTQMSG...",
"chip_id": "01HZTQCHIP...",
"status": "success",
"transcription": {
"text": "ola, queria confirmar meu pedido",
"language": "pt",
"duration_seconds": 8.5,
"cost_cents": 0.085,
"provider": "openai",
"model": "whisper-1"
},
"error": null
}
}

Em falha: status: "failed", transcription: null, error: "...".

Eventos de chip

chip.connected

Chip pareou ou reconectou e o socket Baileys esta open.

{
"event": "chip.connected",
"timestamp": "...",
"data": {
"chip_id": "01HZTQCHIP...",
"phone_number": "5511999998888"
}
}

chip.disconnected

⚠️ So em close TERMINAL (apos badSession streak ou loggedOut/multidevice/replaced). Closes transient (badSession recuperavel, connectionLost, etc) nao disparam webhook — recuperam em segundos via reconnect automatico.

{
"event": "chip.disconnected",
"timestamp": "...",
"data": {
"chip_id": "01HZTQCHIP...",
"reason": "loggedOut",
"will_reconnect": false,
"is_terminal": true,
"status_code": 401,
"consecutive_bad_session": 0
}
}

chip.logged_out

Chip foi marcado como logged_out (sessao Baileys destruida, precisa re-parear). Disparado junto com chip.disconnected mas separado pra app reagir especificamente.

{
"event": "chip.logged_out",
"timestamp": "...",
"data": { "chip_id": "01HZTQCHIP..." }
}

chip.banned

Detector automatico de ban marcou chip como banned. Critico — fila pausada, requer intervencao manual.

{
"event": "chip.banned",
"timestamp": "...",
"data": {
"chip_id": "01HZTQCHIP...",
"reason": "401 persistent + 0 inbound 1h"
}
}

chip.qr_loop

Chip ficou em pairing por mais que 5min — sintoma de QR esquecido. Re-notifica a cada 30min ate 24h, depois envia 1x final e para.

{
"event": "chip.qr_loop",
"timestamp": "...",
"data": {
"chip_id": "01HZTQCHIP...",
"pairing_for_minutes": 7
}
}

chip.bad_session_streak

Preventivo. Disparado quando consecutiveBadSession==2 (penultimo close antes de virar terminal real). Avisa antes de cair.

{
"event": "chip.bad_session_streak",
"timestamp": "...",
"data": {
"chip_id": "01HZTQCHIP...",
"streak": 2
}
}

chip.silent

Chip esta connected mas sem atividade ha mais que 2h — sintoma de socket fantasma (WA parou de rotar eventos). Cobre o caso kill -9 em sessao anterior + outros sintomas silenciosos.

{
"event": "chip.silent",
"timestamp": "...",
"data": {
"chip_id": "01HZTQCHIP...",
"silent_for_minutes": 145
}
}

Resumo — quando reagir

EventoAcao recomendada
message.receivedprocessa mensagem; se chatbot, responda
message.statusatualiza status na sua UI
message.transcribedsalva texto da transcricao
chip.connectedatualiza UI (“chip ativo”)
chip.disconnectedalerta operador: chip caiu terminal
chip.logged_outalerta CRITICO: precisa re-parear
chip.bannedalerta CRITICO: troca de chip imediato
chip.qr_looplembrete: alguem esqueceu QR
chip.bad_session_streakatencao: chip pode cair em breve
chip.silentinvestigar: chip parece fantasma

Como sua app deve listar eventos que escuta

Hoje hub manda todos os eventos pra app que tem can_receive=true no chip. Filtro por tipo de evento por app esta em backlog (P3). Ate la, ignore os que nao usa.

Versionamento de eventos

Adicao de campo nao-breaking entra direto. Renomear/remover campo virara versao nova do evento (message.received.v2) ou novo evento. Hoje todos os eventos sao v1 implicito.