En este artículo aprenderás a crear un Flow dinámico, configurar la Client Action que funciona como endpoint, propagar datos entre pantallas y mapear las variables en la plataforma Botmaker.
Un Flow dinámico es un WhatsApp Flow que se comunica con un servidor externo (el endpoint) mientras el usuario navega por las pantallas. A diferencia de un Flow estático —que solo recopila datos y los envía al final— un Flow dinámico intercambia información en tiempo real, lo que te permite cargar listas actualizadas, validar datos en el servidor y personalizar el contenido pantalla por pantalla.
Nota: Este artículo asume que ya sabes crear un Flow estático básico. El foco está exclusivamente en la parte dinámica.
Puedes:
Requisitos previos
Acceso a tu cuenta de Botmaker con permisos para crear Client Actions y administrar WhatsApp Flows. Un WhatsApp Flow ya creado (aunque sea con una sola pantalla) sobre el que vas a trabajar. Conocimiento básico de la estructura de un Flow JSON.
Conceptos clave
Flow dinámico: WhatsApp Flow que se comunica con un endpoint durante la navegación del usuario, en lugar de enviar los datos solo al final.
Endpoint: servicio que recibe los datos de la pantalla actual, ejecuta la lógica necesaria y devuelve la siguiente pantalla junto con los datos que debe mostrar. En Botmaker se implementa mediante una Client Action (CA) del tipo WA Flow Endpoint.
Client Action (CA): acción de código de Botmaker. Para Flows dinámicos debe ser del tipo WA Flow Endpoint — ningún otro tipo funciona como backend de un Flow.
data_exchange: acción que se dispara cuando el usuario hace clic en el botón de una pantalla configurada con ella. Envía los datos de la pantalla actual al endpoint.
Payload: objeto JSON que se intercambia entre el Flow y el endpoint. Botmaker lo entrega ya descifrado.
Propagación de datos: técnica para reenviar manualmente, pantalla a pantalla, los datos recopilados en pantallas anteriores para que lleguen al final del flujo.
Tipos de action que recibe el endpoint
INIT: el Flow se abrió con flow_action: data_exchange (la primera pantalla se carga dinámicamente). Debes devolver los datos iniciales de la primera pantalla. data_exchange: el usuario hizo clic en el botón del footer con esta acción. Debes procesar los datos enviados y devolver la siguiente pantalla.
BACK: el usuario volvió a una pantalla con refresh_on_back: true. Debes recargar los datos de la pantalla anterior.
ping: health check periódico de Meta. Debes responder siempre con { status: 'active' }.
Paso 1: Crea la Client Action (CA)
Atención: Solo las CA del tipo WA Flow Endpoint son compatibles con Flows dinámicos. Los demás tipos (Usuario, Endpoint común) no funcionan como backend de un Flow.
Paso 2: Copia la URL del servicio
Después de publicar, abre la pestaña General de la CA y copia la URL del servicio. Tiene este formato:
https://functions.botmaker.com/whatsapp-flows/{BusinessID}/{WabaID}/{nombreDeLaCA}
Guarda esta URL: la vas a usar como Endpoint URI en la configuración del Flow.
Atención: El Flow solo funciona en el WABA ID en el que fue configurado. Asegúrate de usar la URL correspondiente al WABA correcto; cambiar de WABA hará que el Flow deje de funcionar.
Paso 3: Vincula el endpoint al Flow
A partir de ese momento, toda pantalla del Flow configurada con la acción data_exchange llamará a tu CA automáticamente.
Consejo: Cada Flow puede tener un solo endpoint. Si tienes varios flujos con lógicas distintas, crea CAs separadas —o maneja toda la lógica dentro de una sola CA identificando la screen recibida.
Paso 4: Entiende qué recibe y qué debe devolver el endpoint
Al ser llamado por el Flow, el endpoint recibe un payload JSON ya descifrado por Botmaker:
{
"version": "3.0",
"action": "data_exchange",
"flow_token": "<token>",
"screen": "NOMBRE_DE_LA_SCREEN_ACTUAL",
"data": {
"campo_enviado": "valor ingresado por el usuario"
}
}
El endpoint siempre debe devolver un JSON con la siguiente pantalla y los datos que necesita para renderizar:
{
"screen": "PROXIMA_SCREEN",
"data": {
"variable_de_la_siguiente_pantalla": "valor"
}
}
Para listas dinámicas usadas en componentes como RadioButtonsGroup, CheckboxGroup o Dropdown, el array debe seguir este formato:
{
"screen": "SELECCION",
"data": {
"lista_opciones": [
{ "id": "1", "title": "Opción A" },
{ "id": "2", "title": "Opción B" }
]
}
}
Nota: Solo CheckboxGroup, RadioButtonsGroup y Dropdown soportan listas dinámicas. El tipo de dato definido en el Flow JSON debe coincidir exactamente con lo que devuelve la CA.
Paso 5: Escribe la lógica de la Client Action
La CA recibe las variables globales screen y data. Úsalas para identificar en qué pantalla está el usuario y qué envió. Esta es la estructura base:
// Manejar el ping (health check obligatorio)
if (!screen || data.action === 'ping') {
flow.data = { status: 'active' };
flow.send();
return;
}
// Primera pantalla: devolver lista dinámica
if (screen === 'SELECCION') {
flow.data = {
lista_productos: [
{ id: 'p1', title: 'Producto A' },
{ id: 'p2', title: 'Producto B' },
],
};
flow.nextScreen = 'CONFIRMACION';
flow.send();
// Segunda pantalla: procesar selección
} else if (screen === 'CONFIRMACION') {
flow.data = {
resumen: `Elegiste: ${data.producto_seleccionado}`,
};
flow.nextScreen = 'RESULTADO';
flow.send();
}
Atención: Llama siempre a flow.send() al final de cada bloque. Si lo olvidas, el Flow queda bloqueado esperando la respuesta del endpoint.
Importante: El ping debe manejarse obligatoriamente. Si el endpoint no responde correctamente al health check de Meta, el Flow puede marcarse como no disponible y dejar de funcionar para los usuarios.
Cuando una pantalla tiene la propiedad refresh_on_back: true en el Flow JSON, al volver hacia ella el endpoint se llama con action: BACK. Úsalo para recargar datos o limpiar selecciones anteriores:
if (data.action === 'BACK' && screen === 'SELECCION') {
flow.data = {
lista_productos: buscarProductosActualizados(),
};
flow.nextScreen = 'SELECCION';
flow.send();
}
Paso 6: Referencia los datos en las pantallas (Flow JSON)
Los datos devueltos por el endpoint quedan disponibles en las pantallas con la sintaxis ${data.nombre_del_campo}. Los datos completados por el usuario en un formulario se acceden con ${form.nombre_del_campo}.
Para mostrar un dato del endpoint:
{
"type": "TextSubheading",
"text": "${data.resumen}"
}
Para enviar un dato del formulario al endpoint:
{
"on-click-action": {
"name": "data_exchange",
"payload": {
"producto_seleccionado": "${form.producto_seleccionado}"
}
}
}
Paso 7: Propaga los datos entre pantallas
Meta envía a Botmaker solo las variables presentes en el payload de la última pantalla, no las de todas las pantallas automáticamente. Para que los datos recopilados en pantallas anteriores lleguen al final, tienes que propagarlos manualmente: al navegar de una pantalla a otra, incluye en el payload del on-click-action tanto los campos completados en la pantalla actual como los datos recibidos de pantallas anteriores vía ${data.xxx}.
Por ejemplo, en un Flow de registro con tres pantallas, la Pantalla 1 recopila datos y navega a la Pantalla 2 pasándolos:
"on-click-action": {
"name": "navigate",
"next": { "type": "screen", "name": "PANTALLA_2" },
"payload": {
"nombre": "${form.TextInput_nombre}",
"razon_social": "${form.TextInput_razon}",
"cuit": "${form.TextInput_cuit}",
"inscripcion_estadual": "${form.TextInput_ie}"
}
}
La Pantalla 2 recibe esos campos vía ${data.xxx}, agrega los nuevos y los reenvía a la Pantalla 3. La Pantalla final usa complete (no data_exchange) y acumula todo para enviarlo a Botmaker:
"on-click-action": {
"name": "complete",
"payload": {
"nombre": "${data.nombre}",
"razon_social": "${data.razon_social}",
"cuit": "${data.cuit}",
"inscripcion_estadual": "${data.inscripcion_estadual}",
"tel_celular": "${data.tel_celular}",
"tel_fijo": "${data.tel_fijo}",
"email": "${form.TextInput_email}",
"clave": "${form.TextInput_clave}"
}
}
Importante: Sin esta propagación explícita, solo los campos de la última pantalla llegarán al payload; todos los datos anteriores se perderán.
Paso 8: Mapea las variables en la plataforma Botmaker
Cuando el Flow se completa, los datos del payload llegan a Botmaker con nombres genéricos generados automáticamente (por ejemplo, screen_0_TextInput_3). Para usarlos con facilidad en tus automatizaciones, mapea cada campo a una variable con nombre amigable.
Por ejemplo, el campo screen_0_TextInput_0 se mapea a ${nombreEmpresa}, screen_0_TextInput_1 a ${razonSocial}, y así sucesivamente.
Nota: Si no configuras ninguna variable, los datos se guardarán con los nombres genéricos del Flow —funcionales, pero menos legibles para quienes configuran automatizaciones.
Antes de poner tu Flow dinámico en producción, verifica que:
Consejo: Para probar el Flow JSON antes de publicar, accede al Playground de Meta (developers.facebook.com/docs/whatsapp/flows/playground), reemplaza el JSON de ejemplo por el tuyo, haz clic en Run y selecciona cada pantalla para validar la estructura.
Este Flow tiene dos pantallas: el usuario escribe su nombre en la primera, el endpoint lo devuelve en mayúsculas y la segunda muestra el resultado para confirmación.
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": "Ingresá tu nombre",
"terminal": false,
"data": { "comment_text": { "type": "string", "__example__": "Ejemplo" } },
"layout": {
"type": "SingleColumnLayout",
"children": [{
"type": "Form", "name": "form",
"children": [
{ "type": "TextSubheading", "text": "Escribí tu nombre completo:" },
{ "type": "TextArea", "name": "comment_text", "required": true,
"helper-text": "Nombre y apellido" },
{ "type": "Footer", "label": "Continuar",
"on-click-action": {
"name": "data_exchange",
"payload": { "comment_text": "${form.comment_text}" }
}}
]
}]
}
},
{
"id": "RESPONSE",
"title": "Confirmación",
"terminal": true,
"data": { "comment_text": { "type": "string", "__example__": "EJEMPLO" } },
"layout": {
"type": "SingleColumnLayout",
"children": [{
"type": "Form", "name": "form",
"children": [
{ "type": "TextCaption", "text": "Confirmá tu nombre:" },
{ "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 de tipo WA Flow Endpoint — dinamic:
// Manejar ping
if (!screen || data.action === 'ping') {
flow.data = { status: 'active' };
flow.send();
return;
}
// Pantalla SHARE: devolver el nombre en mayúsculas
if (screen === 'SHARE') {
flow.data = {
comment_text: data.comment_text.toLocaleUpperCase(),
};
flow.nextScreen = 'RESPONSE';
flow.send();
}
Para dar tus primeros pasos con WhatsApp Flows en Botmaker, te compartimos el artículo "Paso a paso de creación de WhatsApp Flows en Botmaker". Para crear la acción de código, consulta "Creación de acción de código en Botmaker", y para el mapeo, "Creación de variables en Botmaker".
Recuerda visitar nuestro Centro de Ayuda para mayor información