Skip to main content
O cliente abre o seu Flow, preenche, toca em Enviar — e o webhook que chega até você parece vazio. A mensagem está lá, mas o texto dela é uma palavra só: Enviado. Nada se perdeu. As respostas viajam em outro evento, e esse evento precisa ser assinado explicitamente.

O que a Meta entrega de verdade

Um Flow enviado não chega como mensagem de texto. Chega como uma resposta interativa do tipo nfm_reply, com três campos:

Por que o texto da mensagem diz Enviado

Porque é a única coisa do payload que é texto de mensagem. A bolha do chat, chat_messages.text, o content dos eventos message.* e o GET /v1/messages carregam todos o mesmo valor, e esse valor é o body da Meta (com o nome do Flow como fallback quando o body vem em branco).
As respostas ficam de fora do content de propósito. Isso é um contrato público: quem lê content recebeu a promessa de texto de mensagem. Colocar um blob JSON ali quebraria todo consumidor que renderiza ou casa em cima dele, e derramaria nomes, telefones e documentos num campo de texto puro sem schema — de forma irreversível, assim que um cliente começasse a fazer o parse.As respostas ganham uma superfície própria, onde são estruturadas, correlacionáveis pelo flow_token e podadas por uma janela de retenção.

As respostas chegam em flow.response_received

É preciso assinar o evento. Um webhook cuja lista de events contém só messages nunca o recebe — e nada reporta erro, que é exatamente a cara de “o meu webhook chega vazio” visto de fora.Flows rodam em números Meta (Cloud API), cujos webhooks são assinados pelos nomes de campo da própria Meta (messages, flows, …). O flow.response_received é um evento Pilot Status entregue ao lado deles, no formato canônico { event, data } — como os eventos normalizados call.*. Acrescente-o à lista.
Abra Webhooks (/webhooks), edite o webhook ligado ao número do Flow e marque flow.response_received no seletor de eventos. O events é substituído inteiro ao salvar, então mantenha os eventos que você já tinha.

O payload

response e responseRaw são duas metades de um campo só, e a metade que falha é a que vale tratar. A Meta manda as respostas como string JSON; quando essa string parseia, você recebe response e responseRaw vem null. Quando não parseia, você recebe responseRaw com os bytes exatamente como chegaram e response vem null.A submissão nunca é descartada por ser impossível de parsear — perder o que o cliente digitou é pior do que te entregar algo que você precisa olhar. Então leia os dois, e não presuma que response é objeto sem conferir.

O Chatwoot mostra content: null — isso é do Chatwoot

O Chatwoot não tem leitor para nfm_reply. Uma submissão de Flow que chega ao Chatwoot pelo canal nativo de WhatsApp Cloud dele cai como uma mensagem com content: null — sem texto e sem respostas. É uma limitação do parser de WhatsApp do Chatwoot, não do número nem do Flow, e nenhuma configuração do nosso lado muda o que o parser dele entende. Nesse canal o Pilot Status não está no caminho, então não há nada que a gente consiga acrescentar ao tópico: este evento é a forma de ler essas respostas.
No canal espelhado por API, nós acrescentamos. Quando a conversa é espelhada pelo Pilot Status, uma submissão é publicada duas vezes: a bolha pública é substituída por uma linha fixa curta (📋 Formulário respondido) no lugar do rótulo da Meta, e as respostas vão para uma nota privada na mesma conversa — uma linha campo: valor por resposta, só para atendentes, nunca visível para o cliente.A nota é uma conveniência para humanos e tem limite por valor; o evento é a cópia legível por máquina e nunca é truncado. Veja Chatwoot.

Ler as respostas depois

O evento é o canal ao vivo. A cópia armazenada está em GET /v1/flows/{id}/responses, unida ao contato que respondeu, e guardada por 30 dias.
A janela de retenção é aplicada na leitura, então uma submissão vencida nunca é servida — puxe para a sua própria base o que você precisa guardar, em vez de tratar este endpoint como arquivo.

Exemplo mínimo

Node + Express. Valida a assinatura sobre o corpo cru e lê as respostas.

Ainda vazio? Confira nesta ordem

1

O flow.response_received está no events do webhook?

Faça GET /v1/webhooks e leia a lista de volta. Um webhook com ["messages"] recebe mensagens e mais nada.
2

O webhook está no número certo?

Webhooks têm escopo por número, e um Flow é respondido no número que o enviou.
3

O webhook está ativo, e a entrega está sendo tentada?

GET /v1/webhooks/{id}/logs mostra as tentativas recentes. Um webhook pausado (active: false) não entrega nada.
4

Você está lendo content em vez de data.response?

content é o rótulo da Meta e sempre será. As respostas estão em data.response.
5

Você está lendo o LOG da entrega em vez da entrega?

Num número configurado para não guardar conteúdo do cliente, as respostas continuam sendo entregues ao seu endpoint por inteiro — o que é apagado é a cópia guardada do payload (from, response e responseRaw viram null). Um registro que parece vazio ao lado de um 200 é essa ocultação, não uma entrega falhada.

Relacionados