Veio do botão FLOW de template?
Não existe objeto de botão para montar. É isto que tropeça quem chega do outro lado: no template, o botão FLOW é um componente que você declara e a Meta aprova, então o reflexo é procurar a mesma coisa aqui. Aqui o botão é octa. O texto que você puser nele é o rótulo que o cliente toca. Sem components, sem array de buttons, sem revisão.
Duas coisas atravessam do mundo dos templates, e as duas são recusas em vez de surpresas:
- O Flow e o número remetente têm de estar na mesma conta do WhatsApp Business. Se você tem vários números em várias WABAs, um Flow criado sob uma delas não sai por outra — você recebe
FLOW_NOT_SENDABLE. - O Flow precisa estar publicado (ou mande
mode: "draft", de propósito). Um Flow depreciado para de enviar no instante em que a Meta o marca assim.
text é obrigatório — o Flow é um botão, não a mensagem inteira. O bloco flow não pode ser combinado com templateId, list, carousel, buttons, header nem com envio direto de mídia.
A janela de 24 horas não é opcional
Esta é a parte que você não consegue ver, e a razão de recusarmos o envio em vez de tentar. Medimos em 9 de setembro de 2026 contra três versões da Graph API — v22.0, v25.0 e v26.0 — com números e aparelhos reais. Fora da janela de 24 horas, a Meta respondeHTTP 200 com um wamid e descarta a mensagem em silêncio. Sem erro. Sem status de falha. Sem nada em log nenhum. Foram oito envios, quatro entregues, 200 nos oito.
Ou seja: se deixássemos passar, a sua mensagem sumiria e nem você nem nós teríamos como saber. Em vez disso, você recebe:
Erros
O
FLOW_NOT_SENDABLE devolve uma única mensagem para os três motivos, de propósito. Dizer “existe, mas é de outra conta” confirmaria que um id que não é seu é real.
data_exchange não leva tela nem dados
Um Flow data_exchange é respondido pelo seu endpoint, então não há o que semear no envio — e a Meta cobra isso. Mande a tela de entrada junto e a mensagem inteira é recusada:
data_exchange chega pela requisição INIT que a Meta faz ao seu endpoint — a costura é ali, não no envio.
Por isso screen e data são recusados na porta, em vez de descartados em silêncio:
Recusamos em vez de descartar, e isso é deliberado. Jogar fora o
data caladamente deixaria você acreditar que valores chegaram ao Flow sem nunca terem saído do nosso processo. Remova o campo, ou use action: "navigate" — que é exatamente para isso que esses dois campos existem.Como as respostas voltam — são DOIS destinos
Qual deles você recebe depende da ação, e trocar um pelo outro é a surpresa mais comum aqui.
Quando alguém envia o Flow preenchido, as respostas chegam no evento de webhook
flow.response_received e em GET /v1/flows/{id}/responses, correlacionadas com o envio que as originou.
Você não precisa fazer nada para essa correlação funcionar. O token que liga os dois é gerado por mensagem e guardado no momento do envio — que é também por que flow_token no corpo é recusado. Um token escolhido por quem chama deixaria uma conta reclamar as respostas de outra.
Assinar o evento
flow.response_received é um passo à parte. Veja Respostas de Flow.Duas coisas que vale saber antes de testar
Número Cloud API não recebe Flow. Enviar para outro número Meta — mesmo com a janela aberta — não entrega, e a Meta responde200 do mesmo jeito. Teste com um telefone comum.
mode: "draft" funciona. Você pode experimentar um Flow antes de publicá-lo. Lembre-se de que a mensagem chega a uma pessoa real.