Skip to main content
Sim — um Flow pode consultar a sua API enquanto o cliente preenche o formulário. É isso que é um Flow 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çalho x-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.
Sem segredo configurado, não há cabeçalho. O encaminhamento acontece assim mesmo, sem assinatura, e aí qualquer um que alcance a sua URL pode postar um corpo plausível nela. Configure o segredo.

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.
Um 200 que não nomeia screen é recusado de propósito. É o único modo de falha que parece sucesso do seu lado e é invisível do lado do cliente: a Meta renderiza um payload sem tela como nada, então a pessoa fica diante de um formulário que nunca avança e nunca dá erro.Em vez disso, tratamos exatamente como uma chamada falha — o cliente recebe um erro repetível sobre a tela em que já está, e a troca fica registrada como falha que você consegue encontrar.

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ê

O ping da Meta nunca chega ao seu endpoint. É a checagem de saúde da Meta, e nós mesmos respondemos. Uma checagem de saúde que depende de um terceiro estar acordado reporta a coisa errada para a parte errada — o seu servidor fora do ar num deploy faria a Meta marcar o endpoint como não saudável para todos os Flows daquele número.Portanto: não implemente ping, e não espere vê-lo nos seus logs.

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.
A chave é deste NÚMERO, mesmo aparecendo ao lado de um Flow. Trocá-la muda a descriptografia de todos os Flows data_exchange daquele telefone, não só do que você estava olhando.
Um destino salvo num número sem chave é um Flow que nunca será chamado. A Meta não tem com o que cifrar, então não chega até nós, então o destino nunca é usado — e nada, de nenhum dos lados, reporta isso. É para isso que existem numberHasKey e a lista warnings; FLOW_ENDPOINT_NUMBER_HAS_NO_KEY é o que importa.
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

Criamos um par RSA-2048, guardamos a metade privada cifrada e registramos a metade pública na Meta para aquele número.
Gerar SUBSTITUI a chave que a Meta tem para aquele telefone. A Meta guarda uma chave pública por número — registrar a nossa sobrescreve o que estiver lá.Se você já roda um endpoint data_exchange próprio nesse número, ele para de descriptografar no instante em que registramos. É por isso que substituir uma chave viva exige {"confirm": true} e, sem isso, é recusado com FLOW_ENDPOINT_KEY_REQUIRES_CONFIRMATION.A configuração inicial não pergunta, e repetir a chamada para um par que a Meta nunca aceitou (uploadedAt: null) também não — uma repetição reenvia a mesma metade pública já guardada em vez de criar outra, então não há nada a destruir em nenhum dos dois casos.
Leia o estado quando quiser — o que temos, quando a Meta confirmou pela última vez, e se a cópia dela ainda concorda com a nossa:
UNKNOWN não é NOT_SET. Uma chamada ao Graph que falhou não diz nada sobre o que a Meta tem. Ler isso como “sem chave” leva a rotacionar — e rotacionar substitui uma chave que provavelmente estava boa.
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

secret volta em exatamente uma resposta na vida de um segredo: a requisição que o criou. Ele é guardado cifrado e não há caminho de leitura de volta. Copie agora — secret: null numa gravação posterior quer dizer “já existia um e foi mantido”, não “não existe nenhum”. Quem responde isso é hasSecret.Perdeu? {"url": "...", "rotateSecret": true} cria um novo, que é também a única saída para um segredo que vazou.
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

Registre endpointUri 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ó:
A chave (/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