data_exchange: o cliente escolhe uma data e a tela seguinte mostra os horários que estão de fato livres, porque o seu backend decidiu quais são.
Você não implementa nada da criptografia da Meta. O endpoint que a Meta chama é o Pilot Status. Nós descriptografamos a requisição, fazemos um POST de JSON puro para uma URL sua, e criptografamos a sua resposta na volta.
Um Flow
NAVIGATE — aquele em que todas as telas estão fixas no Flow JSON — não precisa de nada disto. Tudo nesta página vale só para Flows cujas telas chamam o seu backend. Veja Flows para a diferença.O formato de uma troca
1
O cliente preenche uma tela
A Meta manda uma requisição criptografada — AES-GCM, com a chave envelopada em RSA-OAEP sob a chave pública registrada para aquele telefone — para o endpoint registrado no Flow, que somos nós.
2
Nós descriptografamos e encaminhamos
Um
POST de JSON puro para a sua URL, com um cabeçalho de assinatura HMAC. Nada de RSA, AES-GCM ou IV invertido do seu lado.3
Você responde com a próxima tela
200 com { "screen": "...", "data": { ... } }.4
Nós criptografamos a resposta
A Meta renderiza a tela que você nomeou.
O que fazemos POST para você
action nunca é null, e uma requisição sem ele nunca é encaminhada. Toda chamada que a Meta faz carrega INIT, BACK, data_exchange ou ping. Um payload descriptografado que não traga nenhum deles é descartado antes de chegar até você, porque encaminhá-lo colocaria a nossa assinatura em algo que não é uma troca de Flow — e o seu endpoint não teria como distingui-lo de um que assinamos de propósito.A assinatura
Quando o Flow tem um segredo de assinatura, o encaminhamento leva o cabeçalhox-pilot-status-signature: o HMAC-SHA256 em hexadecimal do corpo cru da requisição, com esse segredo como chave.
É o mesmo cabeçalho e o mesmo esquema dos webhooks de saída do Pilot Status — se você já valida aqueles, não precisa de um segundo caminho de código. Calcule o HMAC sobre os bytes como recebidos, antes de qualquer parse de JSON.
O que você tem de devolver
JSON puro,2xx, nomeando a próxima tela:
Para encerrar o Flow, devolva a tela reservada
SUCCESS. ⚠️ Este formato é convenção da Meta, não nossa: nós repassamos screen e data à Meta intactos, portanto extension_message_response não aparece em lado nenhum da Pilot Status — não o procure na nossa referência de API.
Responda rápido
A Meta segura a requisição aberta enquanto uma pessoa olha para um spinner, e não há retry — uma resposta lenta é uma tela falha, não uma tela atrasada. O nosso encaminhamento é abandonado depois de alguns segundos (8 s por padrão), deliberadamente mais apertado que o orçamento dos webhooks comuns: aqueles são notificações que ninguém está esperando. Faça o trabalho lento depois de responder.O que resolvemos sem chamar você
Quando a sua API falha
Seja qual for a causa — fora do ar, timeout, não-2xx, corpo impossível de parsear, sem screen — o cliente nunca vê a sua infraestrutura e nunca vê uma tela quebrada.
Uma falha do seu lado nunca é reportada à Meta como problema de chave. A resposta
421, que diz à Meta “baixe a minha chave pública de novo”, é devolvida por exatamente uma coisa: não conseguimos descriptografar. A Meta cacheia essa busca, então usá-la para uma indisponibilidade sua faria a mentira sobreviver à indisponibilidade.Ver o que aconteceu
A tela do Flow no painel lista as trocas recentes: a ação, a tela, o desfecho, o seu status HTTP e quanto tempo você levou. Os corpos são gravados só em caso de falha — uma troca bem-sucedida guarda tempo e formato e nada do que o cliente digitou — e o registro inteiro expira em 24 horas.Como configurar, na ordem
Três coisas precisam ser verdade antes de a Meta chamar a sua API, e elas se tornam verdade nesta ordem. Pule uma e você fica com um Flow que parece configurado, não levanta erro em lugar nenhum e nunca é chamado.1
1. A chave — do NÚMERO
Gere uma conosco, ou importe a que você já usa. A Meta guarda exatamente uma chave pública por telefone, então isso é uma propriedade do número e nunca de um Flow.
2
2. A URL de encaminhamento — do FLOW
Para onde damos
POST na troca já descriptografada. Um número serve vários formulários, e cada formulário costuma ser um serviço diferente do seu lado, então isso é por Flow.3
3. endpoint_uri — na Meta, no Flow
A Meta só chama um endpoint que ela tem registrado. Salvar a URL conosco não registra nada na Meta, de propósito: fazer isso como efeito colateral de um rename sequestraria o Flow de quem já roda um endpoint próprio. Leia o endpoint de volta e compare
endpointUri (o nosso) com metaEndpointUri (o da Meta) — drift: true quer dizer que a Meta está chamando outra pessoa.Todos esses endpoints exigem
flows:manage — inclusive as leituras. endpointUri e metaEndpointUri carregam o token de endpoint do número, e esse token é a única coisa que o endpoint público autentica, enquanto a chave pública correspondente é publicada pela própria Meta. Quem tiver os dois consegue forjar uma requisição que nós vamos descriptografar e encaminhar ao seu webhook sob a NOSSA assinatura. É também por isso que o valor está deliberadamente ausente do GET /v1/flows: uma credencial somente-leitura continua sendo uma credencial.Passo 1 — a chave: gerar, ou importar a sua
- Gerar (nós criamos o par)
- Importar (você já tem uma)
Criamos um par RSA-2048, guardamos a metade privada cifrada e registramos a metade pública na Meta para aquele número.
endpointUrl para antes do id do Flow: o segmento do token identifica o número, e o segmento seguinte identifica o Flow. O endereço completo que a Meta precisa chamar é {endpointUrl}/{metaFlowId} — que é exatamente o que endpointUri, no recurso do endpoint, já entrega pronto.Passo 2 — a URL de encaminhamento, no Flow
A URL precisa ser
https:// — recusada de outro jeito, e não existe flag para permitir http://. O corpo que encaminhamos são as respostas do formulário do seu usuário final, descriptografadas por nós um salto antes; em http:// isso é dado pessoal em claro, colocado ali pelo único participante que já tinha removido a criptografia.{"url": null} limpa o destino e mantém o segredo, então re-apontar o Flow depois não obriga você a redeployar um verificador por causa de um valor que nunca vazou.PUT e PATCH são a mesma operação aqui — o recurso tem um único campo gravável, então não há sobre o que “substituir” e “mesclar” discordarem. Dê GET no mesmo caminho para ler o estado sem escrever.O número não é parâmetro: ele vem da chave de API (uma chave por número nomeia o dela; uma chave de conta estreita com x-whatsapp-number-id). Nomeá-lo no corpo é recusado com FLOW_NUMBER_FROM_KEY, e uma chave vinculada a um número fora da WABA do Flow recebe 422 FLOW_NUMBER_WABA_MISMATCH em vez de uma resposta sobre um número que nunca poderia enviar esse Flow.Passo 3 — aponte a Meta para nós
RegistreendpointUri como o endpoint_uri do Flow no Flow Manager da Meta. Depois leia o endpoint de volta:
Trate a lista como aberta, não fechada: mantenha na tela qualquer código que você não reconheça. Um aviso que você não sabe soletrar continua sendo um aviso, e descartá-lo é como uma tela passa a reportar “está tudo bem” sobre um servidor que acabou de dizer o contrário.
Códigos de erro
Toda falha destes endpoints responde no mesmo envelope — um formato só, uma grafia só:/v1/numbers/{numberId}/flow-endpoint-key):
A URL de encaminhamento (
/v1/flows/{flowId}/endpoint):
Comuns aos dois:
FLOW_BODY_INVALID (400, corpo malformado — um corpo truncado nunca é tratado como vazio), FLOW_UNKNOWN_FIELDS (400), FLOW_NUMBER_FROM_KEY (400, o corpo nomeou o número), FLOW_REQUIRES_META_NUMBER (422), INTERNAL_ERROR (500).
Nunca assuma que o conjunto é fechado — trate os códigos que você conhece e caia no
code para o resto.Exemplo mínimo
Node + Express. Uma tela que responde com os horários de um dia escolhido.Nunca devolva
version. É a versão de protocolo da Meta, ecoada da requisição dela — uma versão errada derruba a troca inteira, não um campo só.Relacionados
- Flows — ciclo de vida, publicação, clonagem
- Receber as respostas de um Flow — as respostas enviadas, no webhook
- API de Flows