22. Identificadores e Correlação de Eventos#
Está seção explica como JIDs, LIDs e números de telefone fluem pelo sistema, e como correlacionar eventos a conversas e mensagens.
Glossario de Identificadores#
| Termo | Formato | Exemplo | O que e |
|---|---|---|---|
| Phone JID | <phone>@s.whatsapp.net |
554196332719@s.whatsapp.net |
Identificador de contato individual |
| Group JID | <id>@g.us |
120363012345678901@g.us |
Identificador de grupo |
| LID | <id>:<device>@lid |
216251804708983:34@lid |
Linked ID — formato interno do WhatsApp para dispositivos vinculados |
| Base LID | <id>@lid |
216251804708983@lid |
LID sem sufixo de dispositivo, usado como chat JID |
| chat_lid | <id>@lid |
42812401807390@lid |
Campo auxiliar nos eventos — LID original do chat antes da resolução para phone JID |
| sender_lid | <id>:<device>@lid |
42812401807390:77@lid |
Campo auxiliar nos eventos — LID original do sender antes da resolução para phone JID |
| RemoteJID | Phone JID ou Group JID | — | Campo no banco que identifica a conversa |
| WhatsAppID | string alfanumerica | 3EB0A1B2C3D4E5F6 |
ID único da mensagem atribuido pelo WhatsApp |
| ExternalID | UUID v4 | a1b2c3d4-e5f6-... |
ID da mensagem na API Catcher |
| InstanceID | UUID v4 | 84c2e480-... |
Qual instância WhatsApp (número conectado) |
| SenderJID | Phone JID | 554196332719@s.whatsapp.net |
Quem enviou a mensagem (util em grupos) |
Normalizacao automática#
A API normaliza automaticamente todos os identificadores:
-
LID → Phone JID: O WhatsApp pode enviar identificadores no formato LID (
@lid). A API tenta resolver LIDs para Phone JID (@s.whatsapp.net) usando: campoSenderAltdo protocolo, registro de identidade de contatos (tabelascontacts/contact_identities), e busca na tabelamessagescomo último fallback. Os campos principais (phone,chat,from,to,sender) sempre contem o phone JID quando a resolução e possível. Quando o LID original estava presente, ele e exposto nos campos auxiliareschat_lidesender_lidpara correlação. -
BR 13→12 digitos: Números brasileiros com 13 digitos (
55XX9XXXXXXXX) são normalizados para 12 digitos (55XXXXXXXXXX), removendo o 9 extra. Isso e aplicado em todas as direcoes (inbound e outbound). -
Formato consistente: O campo
chatem todos os eventos e identico ao camporemote_jidno banco. Você pode agrupar eventos em conversas usandoinstance_id + chat.
Campos LID auxiliares (chat_lid, sender_lid)#
Quando o WhatsApp usa internamente um LID para identificar um contato ou chat, a API expoe o LID original nos campos opcionais chat_lid e sender_lid (omitidos quando vazios). Esses campos são uteis para:
- Correlação de eventos: Quando
phoneestá vazio (primeiro contato via LID, sem mapeamento no registro), usechat_lidpara agruparmessage.sent+message.delivered+message.read+message.playedda mesma conversa. - Correlação retroativa: Quando um
message.receivedchega comphonepreenchido echat_lidpresente, você pode retroativamente associar eventos anteriores que tinhamphonevazio mas o mesmochat_lid. - Debug: Os campos auxiliares permitem diagnosticar quando o WhatsApp opera em modo LID e verificar se a resolução de identidade está funcionando.
Disponibilidade dos campos LID por evento:
| Evento | chat_lid |
sender_lid |
|---|---|---|
message.received |
Sim | Sim |
message.sent |
Sim | — |
message.delivered |
Sim | Sim |
message.read |
Sim | Sim |
message.played |
Sim | Sim |
message.deleted |
Sim | Sim |
message.edited |
Sim | Sim |
Aprendizado automático: A API aprende mapeamentos LID→telefone conforme interage com contatos. Quando um contato responde (
message.receivedcomSenderAlt), o mapeamento e salvo no registro de identidade. A partir dai, todos os eventos futuros para esse LID teraophonepreenchido automaticamente.
Modelo de dados da mensagem#
A tabela messages no banco de cada tenant armazena todas as mensagens (inbound e outbound):
| Campo | Tipo | Descricao |
|---|---|---|
id (UUID) |
UUID | ID público na API (exposto como elemento de message_ids nos eventos) |
instance_id |
string | Qual instância WhatsApp |
direction |
string | "inbound" ou "outbound" |
remote_jid |
string | A conversa. Phone JID (1:1) ou Group JID (grupo) |
sender_jid |
string | Quem enviou. Phone JID do remetente. Util para mensagens de grupo, onde remote_jid e o JID do grupo |
message_type |
string | text, image, video, audio, document, sticker, location, contact, reaction, poll |
content |
string | Texto ou caption |
status |
string | queued → sent → delivered → read / failed / deleted |
whatsapp_id |
string | ID da mensagem no WhatsApp (chave de correlação para status updates) |
source |
string | "api" (fila Catcher), "external" (WhatsApp Web/celular) |
media_id |
string | Referência a mídia no S3 |
Como remote_jid funciona por direcao:
| Cenario | Inbound remote_jid |
Outbound remote_jid |
Mesmo valor? |
|---|---|---|---|
| Chat 1:1 com 5541... | 554196332719@s.whatsapp.net |
554196332719@s.whatsapp.net |
Sim |
| Grupo 120363... | 120363012345678901@g.us |
120363012345678901@g.us |
Sim |
Não existe tabela
Chat. Conversas são derivadas agrupando mensagens porremote_jid. O endpointGET /v1/instances/{instanceId}/chatsfaz isso automaticamente.
Como sender_jid funciona#
| Cenario | sender_jid |
remote_jid |
|---|---|---|
| Inbound 1:1 | 554196332719@s.whatsapp.net (quem mandou) |
554196332719@s.whatsapp.net (a conversa) |
| Inbound grupo | 554196332719@s.whatsapp.net (quem mandou) |
120363012345678901@g.us (o grupo) |
| Outbound (API) | vazio (a instância e o remetente) | JID do destinatário |
| Outbound (externo) | vazio (a instância e o remetente) | JID do destinatário |
Para mensagens de grupo,
sender_jide essencial para saber quem disse cada coisa dentro do grupo.
Correlação: como agrupar eventos em conversas#
Chave primaria da conversa: instance_id + campo chat do evento (ou remote_jid no banco)
Chave secundaria (quando chat e um LID não resolvido): instance_id + campo chat_lid do evento
Todos os eventos de mensagem incluem o campo chat, que corresponde exatamente ao remote_jid no banco:
| Evento | Campo de conversa | Campo auxiliar LID | Campo de mensagem (UUID Catcher) |
|---|---|---|---|
message.received |
chat |
chat_lid |
message_ids (array) |
message.sent |
chat |
chat_lid |
message_ids (array) |
message.delivered |
chat |
chat_lid |
message_ids (array) |
message.read |
chat |
chat_lid |
message_ids (array) |
message.played |
chat |
chat_lid |
message_ids (array) |
message.deleted |
chat |
chat_lid |
message_ids (array) |
message.edited |
chat |
chat_lid |
message_ids (array) |
Padronizacao: todos os eventos de mensagem usam
message_ids(array). Para a maioria, o array tem exatamente 1 elemento; apenasmessage.delivered,message.reademessage.playedpodem trazer multiplos quando o WhatsApp agrega confirmacoes em batch. Consumers leemevent.data.message_ids[0]na maioria dos casos e iteram o array nos eventos de status.
Cenario LID (APIs externas): Quando outra API envia mensagens via LID e a Catcher ainda não conhece o telefone associado, os eventos message.sent e message.delivered terao phone vazio e chat com o LID. Use chat_lid como chave de agrupamento. Quando o contato responder, a Catcher aprendera o mapeamento, e a partir dai os eventos passarao a ter phone e chat com o phone JID. Você pode correlacionar retroativamente comparando o chat_lid dos novos eventos com os anteriores.
Correlação: como rastrear o lifecycle de uma mensagem#
O ciclo de vida de uma mensagem outbound e rastreado pelo message_ids[0] (UUID do Catcher):
message.sent (message_ids = ["550e8400-e29b-41d4-a716-..."])
↓
message.delivered (message_ids = ["550e8400-e29b-41d4-a716-..."])
↓
message.read (message_ids = ["550e8400-e29b-41d4-a716-..."])
↓ (se view-once)
message.played (message_ids = ["550e8400-e29b-41d4-a716-..."])
No banco, os timestamps são atualizados conforme os eventos chegam:
queued_at → sent_at → delivered_at → read_at → played_at (view-once)
↓
deleted_at (se revogada)
message_ids — UUIDs do Catcher#
O campo message_ids em todos os eventos de mensagem contem um array de UUIDs internos do Catcher (v4, 36 chars cada). Este identificador e:
- Garantido único — nunca reciclado, mesmo quando o WhatsApp reutiliza IDs após delecao
- Estável — o mesmo UUID persiste em todos os eventos do ciclo de vida da mensagem (received → delivered → read → played → deleted)
- Aceito nos endpoints da API — os endpoints de delete, edit, react, forward e mark-read aceitam tanto o UUID do Catcher quanto o ID do WhatsApp (hex)
Para a maioria dos eventos (message.received, message.sent, message.deleted, message.edited, message.starred, message.deleted_for_me, media.retry_result, label.message_association), o array tem exatamente 1 elemento — leia event.data.message_ids[0]. Apenas message.delivered, message.read e message.played podem trazer multiplos elementos quando o WhatsApp agrega receipts.
Nota:
message.undecryptablee o único evento ondemessage_ids[0]contem o ID do WhatsApp (não o UUID), pois a mensagem não pode ser persistida no banco.
Diferenciacao: 1:1 vs grupo#
O campo is_group está disponível nos seguintes eventos:
| Evento | is_group |
Como identificar se ausente |
|---|---|---|
message.received |
Sim | — |
message.sent |
Sim | — |
message.delivered |
Sim | — |
message.read |
Sim | — |
message.played |
Sim | — |
message.deleted |
Não | chat termina com @g.us |
message.edited |
Sim | — |
Quando
is_groupnão estiver presente, você pode inferir pelo sufixo do campochat:@g.us= grupo,@s.whatsapp.net= individual.
Endpoints de busca por identificador#
| Preciso de... | Endpoint | Parametro |
|---|---|---|
| Listar conversas | GET /v1/instances/{id}/chats |
— |
| Mensagens de uma conversa | GET /v1/instances/{id}/chats/{chatJID}/messages |
chatJID = remote_jid = chat dos eventos |
| Uma mensagem especifica | GET /v1/instances/{id}/message/{messageId} |
messageId = UUID do Catcher (elemento de message_ids do evento) ou ID do WhatsApp (hex) |
| Mídias de uma conversa | GET /v1/instances/{id}/media?remote_jid={chatJID} |
remote_jid = chat dos eventos |