Neste artigo você vai aprender a criar um Flow dinâmico, configurar a Client Action que funciona como endpoint, propagar dados entre telas e mapear as variáveis na plataforma Botmaker.
Um Flow dinâmico é um WhatsApp Flow que se comunica com um servidor externo (o endpoint) enquanto o usuário navega pelas telas. Diferente de um Flow estático — que apenas coleta dados e os envia no final — um Flow dinâmico troca informações em tempo real, o que permite carregar listas atualizadas, validar dados no servidor e personalizar o conteúdo tela a tela.
Observação: Este artigo pressupõe que você já sabe criar um Flow estático básico. O foco está exclusivamente na parte dinâmica.
Você pode:
Pré-requisitos
Acesso à sua conta Botmaker com permissões para criar Client Actions e administrar WhatsApp Flows. Um WhatsApp Flow já criado (mesmo que com uma única tela) sobre o qual você vai trabalhar. Conhecimento básico da estrutura de um Flow JSON.
Conceitos-chave
Flow dinâmico: WhatsApp Flow que se comunica com um endpoint durante a navegação do usuário, em vez de enviar os dados apenas no final.
Endpoint: serviço que recebe os dados da tela atual, executa a lógica necessária e devolve a próxima tela junto com os dados que ela deve exibir. No Botmaker é implementado por meio de uma Client Action (CA) do tipo WA Flow Endpoint.
Client Action (CA): ação de código do Botmaker. Para Flows dinâmicos, ela deve ser do tipo WA Flow Endpoint — nenhum outro tipo funciona como backend de um Flow.
data_exchange: ação disparada quando o usuário clica no botão de uma tela configurada com ela. Envia os dados da tela atual ao endpoint.
Payload: objeto JSON trocado entre o Flow e o endpoint. O Botmaker o entrega já descriptografado.
Propagação de dados: técnica para reencaminhar manualmente, tela a tela, os dados coletados em telas anteriores para que cheguem ao final do fluxo.
Tipos de action que o endpoint recebe
INIT: o Flow foi aberto com flow_action: data_exchange (a primeira tela é carregada dinamicamente). Você deve devolver os dados iniciais da primeira tela. data_exchange: o usuário clicou no botão do footer com esta ação. Você deve processar os dados enviados e devolver a próxima tela.
ACK: o usuário voltou para uma tela com refresh_on_back: true. Você deve recarregar os dados da tela anterior.
ping: health check periódico da Meta. Você deve responder sempre com { status: 'active' }.
Passo 1: Crie a Client Action (CA)
Atenção: Apenas as CA do tipo WA Flow Endpoint são compatíveis com Flows dinâmicos. Os demais tipos (Usuário, Endpoint comum) não funcionam como backend de um Flow.
Passo 2: Copie a URL do serviço
Depois de publicar, abra a aba Geral da CA e copie a URL do serviço. Ela tem este formato:
https://functions.botmaker.com/whatsapp-flows/{BusinessID}/{WabaID}/{nomeDaCA}
Guarde esta URL: você vai usá-la como Endpoint URI na configuração do Flow.
Atenção: O Flow só funciona no WABA ID em que foi configurado. Certifique-se de usar a URL correspondente ao WABA correto; trocar de WABA fará com que o Flow pare de funcionar.
Passo 3: Vincule o endpoint ao Flow
A partir desse momento, toda tela do Flow configurada com a ação data_exchange chamará sua CA automaticamente.
Dica: Cada Flow pode ter apenas um endpoint. Se você tem vários fluxos com lógicas diferentes, crie CAs separadas — ou trate toda a lógica dentro de uma única CA identificando a screen recebida.
Passo 4: Entenda o que o endpoint recebe e o que ele deve devolver
Ao ser chamado pelo Flow, o endpoint recebe um payload JSON já descriptografado pelo Botmaker:
{
"version": "3.0",
"action": "data_exchange",
"flow_token": "<token>",
"screen": "NOME_DA_SCREEN_ATUAL",
"data": {
"campo_enviado": "valor informado pelo usuário"
}
}
O endpoint sempre deve devolver um JSON com a próxima tela e os dados que ela precisa para renderizar:
{
"screen": "PROXIMA_SCREEN",
"data": {
"variavel_da_proxima_tela": "valor"
}
}
Para listas dinâmicas usadas em componentes como RadioButtonsGroup, CheckboxGroup ou Dropdown, o array deve seguir este formato:
{
"screen": "SELECAO",
"data": {
"lista_opcoes": [
{ "id": "1", "title": "Opção A" },
{ "id": "2", "title": "Opção B" }
]
}
}
Observação: Apenas CheckboxGroup, RadioButtonsGroup e Dropdown suportam listas dinâmicas. O tipo de dado definido no Flow JSON deve corresponder exatamente ao que a CA devolve.
Passo 5: Escreva a lógica da Client Action
A CA recebe as variáveis globais screen e data. Use-as para identificar em qual tela o usuário está e o que ele enviou. Esta é a estrutura base:
// Tratar o ping (health check obrigatório)
if (!screen || data.action === 'ping') {
flow.data = { status: 'active' };
flow.send();
return;
}
// Primeira tela: devolver lista dinâmica
if (screen === 'SELECAO') {
flow.data = {
lista_produtos: [
{ id: 'p1', title: 'Produto A' },
{ id: 'p2', title: 'Produto B' },
],
};
flow.nextScreen = 'CONFIRMACAO';
flow.send();
// Segunda tela: processar seleção
} else if (screen === 'CONFIRMACAO') {
flow.data = {
resumo: `Você escolheu: ${data.produto_selecionado}`,
};
flow.nextScreen = 'RESULTADO';
flow.send();
}
Atenção: Chame sempre flow.send() no final de cada bloco. Se você esquecer, o Flow fica travado aguardando a resposta do endpoint.
Importante: O ping deve ser tratado obrigatoriamente. Se o endpoint não responder corretamente ao health check da Meta, o Flow pode ser marcado como indisponível e parar de funcionar para os usuários.
Quando uma tela tem a propriedade refresh_on_back: true no Flow JSON, ao voltar para ela o endpoint é chamado com action: BACK. Use isso para recarregar dados ou limpar seleções anteriores:
if (data.action === 'BACK' && screen === 'SELECAO') {
flow.data = {
lista_produtos: buscarProdutosAtualizados(),
};
flow.nextScreen = 'SELECAO';
flow.send();
}
Passo 6: Referencie os dados nas telas (Flow JSON)
Os dados devolvidos pelo endpoint ficam disponíveis nas telas com a sintaxe ${data.nome_do_campo}. Os dados preenchidos pelo usuário em um formulário são acessados com ${form.nome_do_campo}.
Para exibir um dado do endpoint:
{
"type": "TextSubheading",
"text": "${data.resumo}"
}
Para enviar um dado do formulário ao endpoint:
{
"on-click-action": {
"name": "data_exchange",
"payload": {
"produto_selecionado": "${form.produto_selecionado}"
}
}
}
Passo 7: Propague os dados entre as telas
A Meta envia ao Botmaker apenas as variáveis presentes no payload da última tela, e não as de todas as telas automaticamente. Para que os dados coletados em telas anteriores cheguem ao final, você precisa propagá-los manualmente: ao navegar de uma tela para outra, inclua no payload do on-click-action tanto os campos preenchidos na tela atual quanto os dados recebidos de telas anteriores via ${data.xxx}.
Por exemplo, em um Flow de cadastro com três telas, a Tela 1 coleta dados e navega para a Tela 2 passando-os:
"on-click-action": {
"name": "navigate",
"next": { "type": "screen", "name": "TELA_2" },
"payload": {
"nome": "${form.TextInput_nome}",
"razao_social": "${form.TextInput_razao}",
"cnpj": "${form.TextInput_cnpj}",
"inscricao_estadual": "${form.TextInput_ie}"
}
}
A Tela 2 recebe esses campos via ${data.xxx}, adiciona os novos e os reencaminha para a Tela 3. A tela final usa complete (não data_exchange) e acumula tudo para enviar ao Botmaker:
"on-click-action": {
"name": "complete",
"payload": {
"nome": "${data.nome}",
"razao_social": "${data.razao_social}",
"cnpj": "${data.cnpj}",
"inscricao_estadual": "${data.inscricao_estadual}",
"tel_celular": "${data.tel_celular}",
"tel_fixo": "${data.tel_fixo}",
"email": "${form.TextInput_email}",
"senha": "${form.TextInput_senha}"
}
}
Importante: Sem essa propagação explícita, apenas os campos da última tela chegarão ao payload; todos os dados anteriores serão perdidos.
Passo 8: Mapeie as variáveis na plataforma Botmaker
Quando o Flow é concluído, os dados do payload chegam ao Botmaker com nomes genéricos gerados automaticamente (por exemplo, screen_0_TextInput_3). Para usá-los com facilidade nas suas automações, mapeie cada campo para uma variável com nome amigável.
Por exemplo, o campo screen_0_TextInput_0 é mapeado para ${nomeEmpresa}, screen_0_TextInput_1 para ${razaoSocial}, e assim por diante.
Observação: Se você não configurar nenhuma variável, os dados serão salvos com os nomes genéricos do Flow — funcionais, mas menos legíveis para quem configura automações.
Antes de colocar seu Flow dinâmico em produção, verifique se:
Dica: Para testar o Flow JSON antes de publicar, acesse o Playground da Meta (developers.facebook.com/docs/whatsapp/flows/playground), substitua o JSON de exemplo pelo seu, clique em Run e selecione cada tela para validar a estrutura.
Este Flow tem duas telas: o usuário digita o nome na primeira, o endpoint o devolve em maiúsculas e a segunda exibe o resultado para confirmação.
Flow JSON:
{
"data_api_version": "3.0",
"data_channel_uri": "https://functions.botmaker.com/whatsapp-flows/{BusinessID}/{WabaID}/dinamic",
"routing_model": {
"SHARE": ["RESPONSE"],
"RESPONSE": []
},
"screens": [
{
"id": "SHARE",
"title": "Informe seu nome",
"terminal": false,
"data": { "comment_text": { "type": "string", "__example__": "Exemplo" } },
"layout": {
"type": "SingleColumnLayout",
"children": [{
"type": "Form", "name": "form",
"children": [
{ "type": "TextSubheading", "text": "Digite seu nome completo:" },
{ "type": "TextArea", "name": "comment_text", "required": true,
"helper-text": "Nome e sobrenome" },
{ "type": "Footer", "label": "Continuar",
"on-click-action": {
"name": "data_exchange",
"payload": { "comment_text": "${form.comment_text}" }
}}
]
}]
}
},
{
"id": "RESPONSE",
"title": "Confirmação",
"terminal": true,
"data": { "comment_text": { "type": "string", "__example__": "EXEMPLO" } },
"layout": {
"type": "SingleColumnLayout",
"children": [{
"type": "Form", "name": "form",
"children": [
{ "type": "TextCaption", "text": "Confirme seu nome:" },
{ "type": "TextSubheading", "text": "${data.comment_text}" },
{ "type": "Footer", "label": "Finalizar",
"on-click-action": {
"name": "complete",
"payload": { "comment_text": "${data.comment_text}" }
}}
]
}]
}
}
],
"version": "2.1"
}
CA do tipo WA Flow Endpoint — dinamic:
// Tratar ping
if (!screen || data.action === 'ping') {
flow.data = { status: 'active' };
flow.send();
return;
}
// Tela SHARE: devolver o nome em maiúsculas
if (screen === 'SHARE') {
flow.data = {
comment_text: data.comment_text.toLocaleUpperCase(),
};
flow.nextScreen = 'RESPONSE';
flow.send();
}
Para dar seus primeiros passos com WhatsApp Flows no Botmaker, veja o artigo "Passo a passo de criação do WhatsApp Flows no Botmaker". Para criar a ação de código, consulte "Criação de ação de código no Botmaker" e, para o mapeamento, "Criação de variáveis no Botmaker".
Lembre-se de visitar nossa Central de Ajuda para obter mais informações.