Sincronização de histórico
Evento: history · Transporte: POST para o seu receptor
Receba lotes de dados processados durante sincronizações e recuperações de histórico.
Variações do payload
EventType permanece history. O campo event identifica o conteúdo do lote: por exemplo messages, chats, calls, labels ou chat_labels. Leia o array correspondente; não suponha que todos os arrays existam no mesmo evento.
Sincronizações de etiquetas podem acrescentar history_type, full_sync, summary e chunk. Esses metadados não são universais para todo histórico.
Identificação da origem
request_id identifica de onde o lote veio. No histórico enviado após ler o QR code ou o código de pareamento, todos os lotes (inclusive o status de conclusão) trazem o mesmo request_id, gerado a cada pareamento e devolvido em POST /instance/connect antes da leitura do código e também informado em GET /instance/history-sync/status. Em POST /labels/refresh, os lotes labels e chat_labels trazem o request_id devolvido na resposta da requisição. Nas respostas de POST /message/history-sync, o request_id do pedido vem em cada mensagem e no topo dos lotes messages e chats quando todo o lote pertence ao mesmo pedido; lotes mistos podem omiti-lo no topo.
Resultado de POST /message/history-sync
Cada pedido termina com um único lote event: "status" com o request_id do pedido e os campos status, has_more, history_access, received_messages e next_request. Quando o celular indica mais mensagens, mas não entrega uma página que avance, status vem blocked, com success: false e o motivo em error, sem next_request: não ofereça "carregar mais" com o mesmo pedido. Reenvie next_request para pedir as mensagens anteriores; null indica que não há uma próxima requisição utilizável; isso só comprova o início da conversa quando has_more é false. has_more: false indica o início da conversa; null indica que não foi confirmado. Mensagens que chegarem depois de um timeout, até cerca de 5 minutos após o pedido, vêm com o mesmo request_id, sem novo status; depois disso chegam sem request_id.
Conversas individuais e LID
Em conversas individuais, chatid vem pelo número da conversa (@s.whatsapp.net), mesmo quando o celular devolve o histórico pelo LID; o LID fica em chatlid. Assim as mensagens recuperadas aparecem em POST /message/find pela mesma conversa das mensagens ao vivo.
Como processar
Faça upsert pelos IDs, aceite vários lotes e tolere sobreposição com eventos ao vivo. O recebimento de um lote não comprova que todo o histórico do WhatsApp foi sincronizado. Quando chunk.has_more existir, ele descreve aquela sequência de chunks.
Sequências e conclusão
Cada origem de lotes recebe um batchChunkOrder: o histórico inicial, cada parte que o WhatsApp envia depois dele e cada resposta de POST /message/history-sync. Chats, mensagens e ligações da mesma origem compartilham o número. Identifique uma sequência por batchChunkOrder + event e acompanhe seus lotes com batchNumber e batchTotal. Lotes de sequências diferentes podem chegar intercalados.
Lotes com dados chegam com batchHistoryStatus: "loading". O fim é informado por um lote sem dados, com event: "status" e batchHistoryStatus: "complete"; seu batchChunkOrder é o da última sequência enviada. No histórico do pareamento, ele sai quando o WhatsApp indica o fim da sincronização completa ou após cerca de 2 minutos sem novas partes do histórico. Quando o pareamento pede só o histórico normal (history_days ausente, fora de 0–365 ou de 1 a 90 em POST /instance/connect), o WhatsApp não envia a sincronização completa, e o complete sai por esse prazo. Se partes atrasadas chegarem depois, um novo complete é enviado: considere o de maior batchChunkOrder. A numeração recomeça em 1 a cada pareamento.
Um novo pareamento pode reenviar mensagens já recebidas. Deduplique por messageid e faça upsert pelos IDs: lotes também podem se sobrepor a eventos recebidos ao vivo.
Nos pedidos manuais, o status final tem uma sequência própria e batchHistoryStatus: "complete", inclusive quando status: "timeout". Esse marcador encerra o pedido; só has_more: false confirma o início da conversa. completed aguarda o processamento dos chunks em andamento do chat. Um timeout pode ser parcial, e mensagens atrasadas ainda podem chegar. O status manual é um lote único, com batchNumber: 1 e batchTotal: 1. Com fallbackMode: "try_alternates", o celular pode responder igual ao pedido pelo número e ao pedido pelo LID; a resposta repetida é descartada e não reenvia chats nem mensagens. Uma resposta com mensagens novas ainda pode chegar depois do status, com o mesmo request_id.
Habilitar este evento
Adicione history à lista events do webhook da instância. Preserve os outros eventos de que sua integração precisa.
{
"enabled": true,
"url": "https://seu-sistema.example/hooks/whatsapp",
"events": [
"history"
]
}
Envie essa configuração para POST /webhook, usando o header token. O JSON acima configura a assinatura; os exemplos de entrega abaixo são o que seu servidor recebe.
Campos do payload
O envelope comum vem na raiz. Campos condicionais podem estar ausentes ou nulos conforme o evento; não use a tabela como obrigação de presença de todos os campos.
| Campo | Tipo | Significado |
|---|---|---|
EventType | string | Obrigatório. Tipo de evento, por exemplo connection ou messages. |
owner | string | Obrigatório. Consulte o objeto ou exemplo correspondente. |
token | string | Obrigatório. Token da instância; dado sensível. |
BaseUrl | string | Obrigatório. Consulte o objeto ou exemplo correspondente. |
instanceName | string | Consulte o objeto ou exemplo correspondente. |
event | string | Conteúdo do lote: messages, chats, calls, labels, chat_labels ou status (conclusão do histórico). |
request_id | string | Origem do lote: pareamento, recarga de etiquetas ou pedido manual. Em lotes messages e chats de pedidos manuais, só aparece no topo quando todo o lote pertence ao mesmo pedido; consulte também messages[].request_id. |
request_chat | string | Em status de POST /message/history-sync: chat do pedido. |
status | string | Resultado do pedido manual: completed quando o WhatsApp confirma sua conclusão; timeout após 2 minutos sem confirmação; blocked quando o celular indica mais mensagens, mas não entregou uma página que avance (o motivo vem em error). Não comprova que toda a conversa foi recuperada. |
success | boolean | Em status de POST /message/history-sync: só aparece, com false, junto de error. Sempre presente com status: "blocked"; num timeout, aparece quando o próximo pedido não pôde ser montado. |
error | string | Em status de POST /message/history-sync: por que não há next_request. pagination_no_progress: a partir da mesma âncora, o celular não entregou uma página que avance nem no maior count (a cada página sem avanço, o next_request dobra o count, até 100): veio vazia, sem mensagem que sirva de âncora ou repetida. É o fim do que o celular entrega a partir dessa âncora, mas o WhatsApp não confirma que é o início da conversa; repetir o pedido dá o mesmo resultado; anchor_unavailable: a mensagem de referência não está mais disponível, peça com outra; history_access_unavailable: o restante não está acessível; cursor_lookup_failed: falha ao montar o próximo pedido, tente de novo. |
has_more | boolean / null | Em status de POST /message/history-sync: o que o celular declarou. true há mais mensagens no celular, false chegou ao início da conversa, null não foi confirmado. Alguns aparelhos declaram true em toda resposta sob demanda, inclusive na vazia: com eles, a paginação termina em blocked com pagination_no_progress, nunca em has_more: false. |
history_access | string | Em status de POST /message/history-sync: unavailable quando há mais mensagens, mas sem acesso a elas. |
received_messages | integer | Em status de POST /message/history-sync: mensagens recebidas para o pedido. |
next_request | object / null | Corpo pronto para pedir mensagens anteriores. null indica que não há próxima requisição utilizável; só has_more: false comprova o início da conversa. |
next_request.number | string | Obrigatório. Consulte o objeto ou exemplo correspondente. |
next_request.count | integer | Obrigatório. Consulte o objeto ou exemplo correspondente. |
next_request.messageid | string | Obrigatório. Consulte o objeto ou exemplo correspondente. |
next_request.timestamp | integer | Obrigatório. Timestamp da âncora em milissegundos Unix. |
next_request.fromMe | boolean | Obrigatório. Consulte o objeto ou exemplo correspondente. |
messages | array / null | Lote de mensagens. |
messages[].id | string | Identificador retornado pelo sistema; preserve como string. |
messages[].messageid | string | ID da mensagem no WhatsApp. |
messages[].chatid | string | JID do contato, grupo ou canal. |
messages[].sender | string | JID do remetente. |
messages[].senderName | string | Nome disponível do remetente. |
messages[].fromMe | boolean | Mensagem enviada pela conta conectada. |
messages[].wasSentByApi | boolean | Origem na API quando esse campo estiver presente na mensagem. |
messages[].isGroup | boolean | Identifica conversa de grupo. |
messages[].messageType | string | Tipo de mensagem normalizado. |
messages[].text | string | Texto ou legenda disponível. |
messages[].messageTimestamp | integer | Timestamp da mensagem em milissegundos Unix. |
messages[].content | variável | Conteúdo específico do tipo de mensagem; não possui um formato único. |
messages[].status | string | Estado disponível da mensagem; pode estar vazio. |
messages[].request_id | string | Pedido manual que recuperou esta mensagem, quando correlacionado. |
chats | array / null | Lote de chats. |
chats[].id | string | ID local do chat. |
chats[].wa_chatid | string | JID da conversa. |
chats[].name | string | Nome disponível. |
chats[].wa_isGroup | boolean | Conversa de grupo. |
chats[].wa_isBlocked | boolean | Estado de bloqueio no snapshot. |
chats[].wa_archived | boolean | Estado de arquivamento. |
chats[].wa_unreadCount | integer | Quantidade de mensagens não lidas disponível. |
chats[].wa_label | variável | Etiquetas associadas, conforme a projeção do chat. Pode ser texto JSON; normalize antes de usar. |
labels | array / null | Lote de etiquetas. |
chat_labels | array / null | Associações atualizadas pela sincronização de etiquetas. |
history_type | string | Origem adicional, como labels_refresh. |
full_sync | boolean | Se a sincronização de etiquetas foi completa. |
chunk | object | Metadados opcionais de fragmentação. |
chunk.index | integer | Índice do chunk. |
chunk.total | integer | Total daquela sequência. |
chunk.size | integer | Itens neste chunk. |
chunk.has_more | boolean | Existem mais chunks naquela sequência. |
batchNumber | integer | Número deste lote, começando em 1. |
batchTotal | integer | Total de lotes desta sequência. |
batchChunkOrder | integer | Sequência da origem deste lote, atribuída pela API. Não é a ordem do chunk no WhatsApp e recomeça em 1 a cada pareamento. |
batchHistoryStatus | string | loading em lotes com dados; complete no lote status que encerra o histórico. |
calls | array / null | Registros de chamadas do histórico quando event=calls. |
Exemplos de entrega
Exemplos ilustrativos com identificadores fictícios. O conteúdo específico e os campos opcionais variam.
Lote de mensagens
{
"EventType": "history",
"owner": "5511999999999",
"token": "INSTANCE_TOKEN",
"BaseUrl": "https://seu-servidor.example",
"instanceName": "Atendimento",
"event": "messages",
"request_id": "3f1c9b52-8d4e-4a7b-9c61-2f0e5d7a1b84",
"messages": [
{
"id": "5511999999999:MSG_HISTORICO",
"messageid": "MSG_HISTORICO",
"chatid": "5511888888888@s.whatsapp.net",
"text": "Mensagem do histórico",
"messageTimestamp": 1788868800000
}
],
"batchNumber": 1,
"batchTotal": 1,
"batchChunkOrder": 1,
"batchHistoryStatus": "loading"
}
Lote de chats
{
"EventType": "history",
"owner": "5511999999999",
"token": "INSTANCE_TOKEN",
"BaseUrl": "https://seu-servidor.example",
"instanceName": "Atendimento",
"event": "chats",
"request_id": "3f1c9b52-8d4e-4a7b-9c61-2f0e5d7a1b84",
"chats": [
{
"id": "r0123456789abcd",
"wa_chatid": "5511888888888@s.whatsapp.net",
"name": "Contato de exemplo"
}
],
"batchNumber": 1,
"batchTotal": 1,
"batchChunkOrder": 1,
"batchHistoryStatus": "loading"
}
Conclusão do histórico
{
"EventType": "history",
"owner": "5511999999999",
"token": "INSTANCE_TOKEN",
"BaseUrl": "https://seu-servidor.example",
"instanceName": "Atendimento",
"event": "status",
"request_id": "3f1c9b52-8d4e-4a7b-9c61-2f0e5d7a1b84",
"batchNumber": 1,
"batchTotal": 1,
"batchChunkOrder": 3,
"batchHistoryStatus": "complete"
}
Resultado de POST /message/history-sync
{
"EventType": "history",
"owner": "5511999999999",
"token": "INSTANCE_TOKEN",
"BaseUrl": "https://seu-servidor.example",
"instanceName": "Atendimento",
"event": "status",
"request_id": "5f0c2a8e-6d1b-4c3a-9e7f-1a2b3c4d5e6f",
"request_chat": "5511888888888@s.whatsapp.net",
"status": "completed",
"has_more": true,
"history_access": "available",
"received_messages": 50,
"next_request": {
"number": "5511888888888@s.whatsapp.net",
"count": 50,
"messageid": "3EB0MAIS_ANTIGA_RECEBIDA",
"timestamp": 1706350400000,
"fromMe": false
},
"batchChunkOrder": 4,
"batchHistoryStatus": "complete",
"batchNumber": 1,
"batchTotal": 1
}
Prazo do resultado vencido; histórico ainda inconclusivo
{
"EventType": "history",
"owner": "5511999999999",
"token": "INSTANCE_TOKEN",
"BaseUrl": "https://seu-servidor.example",
"instanceName": "Atendimento",
"event": "status",
"request_id": "5f0c2a8e-6d1b-4c3a-9e7f-1a2b3c4d5e6f",
"request_chat": "5511888888888@s.whatsapp.net",
"status": "timeout",
"has_more": null,
"history_access": "unknown",
"received_messages": 0,
"next_request": {
"number": "5511888888888@s.whatsapp.net",
"count": 50,
"messageid": "3EB0MAIS_ANTIGA_RECEBIDA",
"timestamp": 1706350400000,
"fromMe": false
},
"batchChunkOrder": 4,
"batchHistoryStatus": "complete",
"batchNumber": 1,
"batchTotal": 1
}
Responder ao webhook
Seu receptor deve aceitar o POST JSON e devolver uma resposta 2xx rapidamente, após validar e registrar o recebimento. O corpo da resposta não é um comando para a API. Processe trabalho demorado separadamente.
O worker não repete automaticamente uma entrega HTTP malsucedida. Consulte diagnóstico de webhooks e implemente a reconciliação necessária. Eventos repetidos ou fora de ordem ainda precisam ser tolerados pelo receptor.