Trabalhando com um agente de IA? Baixe a documentação completa como arquivo Markdown para usar como contexto.
Baixar .md completo"Minha mensagem foi entregue? Foi lida?" parece uma única pergunta com uma única resposta. Construa diretamente sobre WhatsApp, Instagram e Facebook Messenger e você descobre que são três perguntas com três respostas diferentes — e as diferenças não estão só no JSON. O comportamento diverge: os canais discordam sobre quais estados do ciclo de vida existem, sobre o que "delivered" realmente significa, sobre como um recibo de "read" é endereçado, e sobre se uma falha alguma vez chega até você de forma assíncrona.
Este é um passeio por onde as três APIs de mensagens da Meta realmente divergem no relato de status, e pelo trabalho necessário para colapsá-las em um único contrato de webhook. Se você já integrou um desses canais, os outros dois vão te surpreender exatamente das formas abaixo.
Um ciclo de vida de entrega parece igual no papel em todo lugar — sent → delivered → read, mais failed. Veja o que cada canal de fato reporta na própria API da Meta — esta tabela é o comportamento bruto da plataforma, antes que qualquer camada unificadora (nossa ou de quem quer que seja) toque nela:
| API da Meta reporta | Messenger | ||
|---|---|---|---|
| sent (aceito pela Meta) | ✅ statuses[].status=sent |
❌ nunca | ❌ nunca |
| delivered (no dispositivo) | ✅ statuses[].status=delivered |
✅ message_deliveries |
❌ sem evento de entrega |
| read | ✅ por mensagem, sujeito à privacidade | ✅ message_reads, watermark |
✅ messaging_seen, por mensagem |
| failed (assíncrono) | ✅ statuses[].status=failed |
❌ nenhum | ❌ nenhum |
| endereça uma mensagem por | id (Meta mid) |
mids[] / timestamp watermark |
echo mid / read mid |
Quatro colunas de assimetria, direto da Meta. Cada uma é uma armadilha comportamental, não um detalhe de formatação — e o resto desta página é sobre o que é preciso para escondê-las atrás de um único contrato.
O WhatsApp oferece o ciclo de vida completo: um sent explícito no momento em que a Meta
aceita a mensagem, um delivered quando ela chega ao dispositivo, um read, e um failed
assíncrono.
Messenger e Instagram oferecem dois estados, não quatro. Não há sent — o mais próximo
disso é a resposta HTTP síncrona da Send API. E, crucialmente, não há evento failed
assíncrono (mais sobre isso abaixo). Então uma integração ingênua que espera por um read
ou failed terminal no Instagram vai esperar para sempre: esses sinais estão estruturalmente
ausentes. O primeiro status que você consegue observar no IG/Messenger é delivered.
No WhatsApp e no Messenger, delivered é um recibo genuíno de nível de dispositivo: a Meta
está te dizendo que a mensagem chegou ao aparelho do destinatário.
O Instagram não tem recibo de entrega algum. Seu webhook de mensagens expõe
messaging_seen (read) e ecos de mensagem — mas nada que diga "delivered". Então de onde vem
um evento delivered? Nós o sintetizamos. Quando você envia um DM no Instagram, a Meta ecoa
sua própria mensagem de volta para o seu webhook (message_echoes, is_echo: true) cerca de
1–3 segundos depois, assim que a mensagem foi aceita na thread da conversa. Esse eco é o
primeiro e melhor sinal de "está no sistema" que o Instagram oferece, então o tratamos como
delivered.
Seja honesto sobre o que isso significa: o delivered do Instagram é "aceito na thread",
não "no dispositivo do destinatário". É o sinal mais forte que a plataforma dá, mas não é
semanticamente idêntico ao recibo do WhatsApp/Messenger. Uma API unificada deve expor um
único evento — e documentar o asterisco em vez de fingir que os canais são iguais.
Há um segundo perigo escondido no truque do eco. Uma única conta do Instagram pode ter vários
apps conectados (sua integração, uma sessão do Meta Business Suite, o app do IG, outro
fornecedor). A Meta ecoa toda mensagem enviada nessa conta para todos os apps
inscritos. Então você recebe ecos de mensagens que nunca enviou. Tratá-los como seus próprios
eventos delivered emitiria status fantasmas para mensagens que não existem no seu sistema. A
solução é resolver o mid de cada eco contra os seus próprios registros de envio e descartar
os ecos estrangeiros — só ecos que correspondem a uma mensagem que você realmente enviou
viram um evento delivered.
WhatsApp e Instagram reportam leituras por mensagem: o recibo carrega o id da mensagem, e você marca aquela mensagem como lida.
O Messenger não envia ids de mensagem nas leituras. Ele envia um watermark — um timestamp
que significa "tudo nesta conversa até este momento foi lido". Um único evento de read pode,
portanto, representar uma dúzia de mensagens. Para mapeá-lo em status por mensagem, você tem
que expandir o watermark: buscar toda mensagem que você enviou para aquele usuário no
timestamp do watermark ou antes dele, que ainda não esteja lida ou falha, e emitir um read
para cada uma. Um evento de entrada da Meta se desdobra em muitos eventos de status de saída —
o que chamamos de read cascading.
E as leituras não são garantidas em todos os canais. Os recibos de read do WhatsApp dependem
da configuração de privacidade do destinatário: se ele desativou os recibos de leitura, o
status read nunca chega, não importa que ele tenha lido a mensagem. Qualquer lógica que
bloqueie em read como estado terminal vai travar nesses usuários — delivered é o único
sinal de sucesso terminal seguro para se projetar em cima.
Essa é a diferença que mais dói em produção. O WhatsApp reporta falhas de forma
assíncrona: uma mensagem pode ser aceita no envio, depois falhar mais tarde na entrega e
chegar como um status failed com um código de erro da Meta. Em cenários multidispositivo, o
WhatsApp pode até reportar delivered e failed para a mesma mensagem — entregue em um
dispositivo, falha em outro. Seu handler precisa tolerar ciclos de vida não lineares.
Messenger e Instagram não têm canal de falha assíncrono. Se um envio falha, você fica
sabendo exatamente uma vez: na resposta HTTP síncrona à sua chamada da Send API. Depois que a
Meta aceita a mensagem, silêncio significa sucesso — não há evento posterior que a retrate.
Então a mesma pergunta lógica, "essa mensagem falhou?", é respondida por um webhook em um canal
e apenas por um código de retorno da API nos outros dois. Uma camada unificada tem que fazer a
ponte: expor o failed assíncrono do WhatsApp como evento, e tratar o erro de envio síncrono
como o sinal de falha em todo o resto.
Os status de entrega do WhatsApp referenciam o mid da Meta. As entregas do Messenger
referenciam mids[]. As leituras do Messenger não referenciam id algum — só o timestamp do
watermark. O Instagram referencia o mid do eco e o mid da leitura. Nenhum desses é o id que
você recebeu de volta ao enviar a mensagem numa API unificada — e eles são inconsistentes
entre si.
Então o movimento unificador é cunhar nosso próprio UUID no momento do envio, retorná-lo na
chamada de envio, e reconciliar todo status de entrada da Meta de volta a ele: um mid da Meta
é buscado primeiro num cache em memória (zero acessos ao banco no caminho quente) e no banco
como fallback; um watermark do Messenger é resolvido por (channel, recipient, time-range). Do
lado de quem chama, a mensagem que você enviou e todo status que a segue carregam o mesmo
id, independentemente de qual dos três esquemas de identidade a Meta usou por baixo.
Depois de tudo isso, o cliente vê uma única forma. Todo status — em qualquer canal — chega ao
seu webhook_url como o mesmo envelope:
{
"event": "message.delivered",
"channel_id": 42,
"channel_type": "instagram",
"timestamp": "2026-06-25T10:00:05Z",
"data": {
"message_id": "a1b2c3d4-...",
"status": "delivered",
"recipient": "..."
}
}
message_id é sempre o UUID da sua resposta de envio. event é um de message.sent,
message.delivered, message.read, message.failed. A matriz completa de eventos por canal e
os campos do payload estão em Recebendo Mensagens — este
artigo é o porquê por trás desse contrato.
Algumas propriedades não óbvias surgem ao unificar canais reais em vez de um idealizado:
(message, status) é deduplicada
para que uma retransmissão nunca duplique um evento.message.sent e message.failed só
disparam no WhatsApp. message.delivered e message.read disparam nos três — mas o
delivered do Instagram é o sinal do eco, e read pode nunca chegar no WhatsApp se os
recibos estiverem desligados. Expomos uma única API e documentamos as bordas, em vez de
forjar estados que a plataforma não emite."API de mensagens unificada" geralmente vende a metade fácil — um único endpoint para enviar. A metade difícil é a parte que você só encontra depois que a mensagem sai: três plataformas que discordam sobre quais estados de entrega existem, o que "delivered" significa, como uma leitura é endereçada, e se a falha alguma vez é reportada de forma assíncrona. Colapsar isso em um único webhook com um id estável, sendo honesto sobre as costuras, é a maior parte da engenharia real.
Pronto para construir em cima disso? Enviando Mensagens cobre o lado do envio, Recebendo Mensagens é o contrato completo de status e webhooks, e você pode começar de graça.
Eles diferem. O WhatsApp reporta o ciclo de vida completo — sent, delivered, read e um failed assíncrono. Messenger e Instagram reportam apenas delivered e read: não há evento 'sent' nem evento de falha assíncrono nesses dois canais.
Não. O webhook de mensagens do Instagram expõe um recibo de leitura (messaging_seen) e ecos de mensagem, mas nenhum evento de entrega. Um sinal de 'delivered' precisa ser sintetizado a partir do eco que a Meta devolve cerca de 1–3 segundos depois que a mensagem é aceita na thread da conversa — então significa 'aceita na thread', não 'no dispositivo'.
Os recibos de leitura do WhatsApp dependem da configuração de privacidade do destinatário. Se ele desativou os recibos de leitura, o status read nunca chega, mesmo que ele tenha lido a mensagem. Trate delivered como o estado terminal de sucesso; não bloqueie esperando por read.
O Messenger reporta leituras com um watermark — um timestamp que significa 'tudo até aqui foi lido' — em vez de IDs por mensagem. Um único evento de read cobre, portanto, toda mensagem enviada naquele timestamp ou antes dele, então ele precisa ser expandido em um status de read por mensagem.
A Fiwano mapeia todos os canais em um único contrato de webhook: message.sent, message.delivered, message.read e message.failed, cada um referenciando o mesmo UUID que você recebeu da chamada de envio. Ela sintetiza o delivered do Instagram a partir dos ecos (descartando ecos de outros apps na conta), expande o watermark de read do Messenger por mensagem e expõe as falhas assíncronas do WhatsApp — documentando quais eventos disparam em cada canal.
Documentação da API Fiwano