Módulo 6: Canales reales: chat web, WhatsApp, Telegram y voz

3. WhatsApp Business API: el agente donde está el cliente

Descripción

Al terminar esta lección vas a poder conectar el sistema de agentes del Módulo 5 a WhatsApp: distinguir la API de la aplicación de escritorio que se le parece en el nombre, armar las piezas que Meta exige (cuenta de desarrollador, portafolio de negocio, app, cuenta de WhatsApp Business y número), crear las dos credenciales distintas que n8n necesita —una para recibir y otra para enviar—, configurar el WhatsApp Trigger y responder con el nodo WhatsApp Business Cloud. Y, sobre todo, vas a entender la regla que cambia el diseño de la conversación entera: la ventana de 24 horas, con su factura correspondiente.

Esto importa porque WhatsApp es el canal número uno de atención al cliente en LATAM, y no por poco. Un agente que atiende por WhatsApp llega a gente que nunca va a abrir el chat de tu sitio web, porque ya tiene la aplicación abierta todo el día. Es también el canal donde un agente mal diseñado hace más daño: es el mismo lugar donde la persona recibe mensajes de su familia, y una respuesta robótica ahí se siente peor que en cualquier otro lado. Y es, por lejos, el canal con más partes móviles fuera de tu control.

Conexión con el módulo: vienes de la lección 2, donde abriste un canal que n8n controla de punta a punta. Aquí todo lo estructural es igual —un trigger que recibe, un cerebro que razona, un nodo que responde— pero la capa de canal ahora es de otro, y ese otro es Meta. Vas a reencontrar las mismas decisiones (identidad de sesión, modo de respuesta, formato) resueltas de otra manera, y vas a encontrar dos reglas nuevas que no existían en el chat web: la ventana de servicio y las plantillas. La lección 4 usa Telegram como el laboratorio barato donde practicar estas ideas sin trámites; si tu verificación de negocio en Meta todavía está en proceso, puedes leer esta lección completa, saltar a la 4, y volver cuando el trámite avance.

El celular del dueño y la línea de la empresa

Piensa en un negocio pequeño que atiende por WhatsApp desde el celular del dueño. Funciona: los clientes escriben, alguien contesta, se resuelven cosas. Y tiene los límites obvios de esa solución: contesta una sola persona, desde un solo aparato, cuando lo tiene en la mano. Si el dueño se va de viaje, la atención se va con él. No hay forma de que un sistema conteste ahí, porque el teléfono es un teléfono.

Ahora piensa en la línea telefónica de una empresa grande. Nadie tiene ese aparato en el bolsillo. La línea llega a una central, la central la reparte, hay grabaciones, hay menús, hay registro de cada llamada, y varios sistemas pueden estar escuchando esa misma línea al mismo tiempo. Es más poderosa y también más burocrática: contratarla toma días, hay un contrato de por medio, y alguien tiene que verificar que la empresa existe.

WhatsApp tiene exactamente esas dos formas, y confundirlas es el error más caro de esta lección.

La aplicación WhatsApp Business es el celular del dueño. Se descarga gratis, se instala en un teléfono, tiene catálogo y respuestas rápidas, y no tiene ninguna forma de conectarse a n8n. Nada de lo que aprendas en esta lección funciona con ella.

WhatsApp Business Platform, con su Cloud API, es la línea de la empresa. No vive en ningún teléfono: vive en los servidores de Meta. Manda los mensajes entrantes a un webhook que tú indiques, y acepta mensajes salientes por una petición HTTP autenticada. Eso es lo que n8n usa, y es lo único que sirve para un agente.

La confusión ocurre porque los nombres se parecen, porque las dos aparecen si buscas "WhatsApp Business", y porque la aplicación es gratis y la API no. Si en algún momento de esta lección te encuentras instalando algo en un teléfono, detente: te fuiste por el camino equivocado.

Las piezas que Meta te va a pedir

Esta es la parte de la lección que más se parece a un trámite, y no hay forma de saltarla. Vale la pena verla como un mapa antes de empezar, porque los nombres de Meta cambian de posición en el panel con frecuencia y es fácil perderse buscando un botón.

Cuenta de desarrollador de Meta
   │   (tu identidad como quien construye; es gratis)
   │
   └── Portafolio de negocio  (Business Portfolio)
          │   (la representación de TuTienda como empresa;
          │    es lo que en algún momento hay que VERIFICAR)
          │
          ├── App de Meta
          │      │   (el "programa" al que le agregas el producto
          │      │    WhatsApp; de aquí salen el App ID y el App Secret)
          │      │
          │      └── Webhook  ──────────────► tu URL de n8n
          │             (un solo webhook por app — recuérdalo)
          │
          └── Cuenta de WhatsApp Business  (WABA)
                 │   (de aquí sale el Business Account ID)
                 │
                 └── Número de teléfono
                        ├── Número de PRUEBA que da Meta (gratis,
                        │   destinatarios limitados, para desarrollo)
                        └── Tu número REAL (requiere verificación)

Cinco cosas que conviene tener claras sobre ese diagrama.

El número de prueba es tu mejor amigo al principio. Meta te regala un número de teléfono de desarrollo con el que puedes mandar y recibir mensajes sin pagar nada y sin verificar el negocio. Tiene un límite importante: solo puedes conversar con una lista corta de números que tú registres explícitamente (típicamente cinco). Para aprender, para probar el agente y para hacer el mini-proyecto de la lección 8, alcanza y sobra. Ese es el camino barato que esta guía recomienda.

La verificación de negocio es para producción, no para aprender. Meta pide documentos que acrediten que la empresa existe. Toma desde horas hasta varios días. No la necesitas para hacer este módulo. La necesitas el día que quieras atender a clientes de verdad con tu número real.

El token de acceso tiene fecha de caducidad. El que Meta te genera con un clic en el panel es temporal —típicamente 24 horas— y sirve perfecto para probar. Para algo que deba seguir funcionando mañana hace falta un token de larga duración, generado a partir de un usuario del sistema del portafolio de negocio. Es el paso que más gente olvida, y el síntoma es delicioso: todo funcionó ayer y hoy nada funciona, sin que nadie haya tocado nada.

Un número no puede estar en dos lados a la vez. Si un número ya está registrado en la aplicación de WhatsApp Business o en WhatsApp normal, hay que darlo de baja de ahí antes de usarlo en la API. No es reversible en caliente: mover un número tiene consecuencias para quien lo estuviera usando.

Un solo webhook por app. Esto la documentación de n8n lo dice explícitamente y merece un párrafo aparte más abajo, porque es la trampa práctica número uno del canal.

Lo que cuesta, dicho claro

Nada de esto es gratis en producción, y prefiero que lo sepas antes de invertir un fin de semana.

Desde julio de 2025 Meta cobra por mensaje entregado, no por conversación como hacía antes. Lo que se cobra son las plantillas (mensajes que tú inicias), y el precio depende de tres cosas: la categoría de la plantilla, el país del destinatario y tu volumen mensual.

CategoríaPara qué esOrden de magnitud
MarketingPromociones, novedades, recuperación de carritoLa más cara. Del orden de centavos de dólar por mensaje, y varía muchísimo entre países
UtilityConfirmaciones de pedido, avisos de envío, recordatoriosConsiderablemente más barata que marketing
AuthenticationCódigos de un solo usoBarata, con precios propios por país
ServiceTus respuestas dentro de la conversación que inició el clienteSin costo dentro de la ventana de 24 horas

Y dos ventanas gratuitas que conviene conocer porque cambian la economía del canal:

  • La ventana de servicio de 24 horas. Cuando un cliente te escribe, se abre una ventana de 24 horas durante la cual puedes responderle libremente, con texto normal, sin plantilla y sin costo por mensaje de servicio. Es la ventana en la que va a vivir el 95% de la actividad de tu agente de atención.
  • La ventana de 72 horas de los anuncios click-to-WhatsApp. Si el cliente llegó a tu chat haciendo clic en un anuncio de Meta, hay una ventana más larga y libre de cargo.

Los precios cambian con frecuencia y varían por país de forma que ningún blog resume bien. La fuente de verdad es la página de precios de Meta, y hay que mirarla para tu mercado, no para el mercado que aparezca de ejemplo. Lo que sí es estable y sí conviene memorizar es la forma de la regla, no el número: responder dentro de la conversación es gratis; iniciar una conversación cuesta y requiere una plantilla aprobada.

Traducido a tu agente: si tu caso de uso es atención al cliente —el cliente escribe, el agente responde—, el canal es sorprendentemente barato. Si tu caso de uso es que el agente inicie conversaciones —recordatorios, campañas, seguimientos—, ahí sí hay una factura y hay que hacer números antes.

La regla de las 24 horas, y por qué cambia el diseño

Esta es la sección más importante de la lección. Es la regla que separa a quien montó un bot de WhatsApp de quien entendió el canal.

WhatsApp no te deja mandarle a alguien lo que quieras cuando quieras. La lógica de Meta es simple y bastante razonable: el cliente decide cuándo se abre la puerta. Concretamente:

El cliente te escribe
   │
   ├──► se abre una ventana de 24 horas
   │      Dentro de ella: respondes con texto libre, cuantas veces
   │      quieras, sin plantilla, sin costo de mensaje de servicio.
   │      Cada mensaje nuevo del cliente REINICIA el contador.
   │
   └──► pasan 24 horas sin que el cliente escriba
          La ventana se cierra.
          Ya NO puedes mandarle texto libre.
          Solo puedes mandarle una PLANTILLA aprobada de antemano
          por Meta, y ese mensaje se cobra según su categoría.

Una plantilla (message template) es un texto fijo que registras en el panel de Meta, con huecos para variables, y que Meta revisa y aprueba antes de que puedas usarlo. Algo así:

# Plantilla: order_shipped_notice  (categoría: utility)
# Enviada con el nodo WhatsApp → Message → Send Template

Hola {{1}}, tu pedido {{2}} ya salió de nuestro centro de
distribución y llega aproximadamente el {{3}}.
Si necesitas algo, respóndenos por aquí.

Las variables {{1}}, {{2}}, {{3}} se rellenan al enviar. El texto alrededor no se puede cambiar sin volver a pasar por aprobación. Esto significa algo importante y contraintuitivo: fuera de la ventana, tu agente no puede improvisar. Un modelo de lenguaje genera texto nuevo cada vez, y texto nuevo es exactamente lo que una plantilla no permite. Un agente de IA solo puede hablar libremente dentro de la ventana de 24 horas.

Piensa en las consecuencias de diseño, que son concretas:

Un agente de atención vive cómodo. El cliente escribe, el agente responde en segundos, la ventana está abierta de sobra. Todo el sistema del Módulo 5 funciona sin cambios.

Un agente que hace seguimiento necesita un plan. Supongamos que order_specialist determina que hay que investigar un caso y que la respuesta va a tardar dos días. No puedes simplemente escribirle al cliente pasado mañana con el resultado: la ventana ya cerró. Tienes que mandar una plantilla de tipo utility —aprobada de antemano, con texto fijo, que se cobra— y esa plantilla, al ser respondida por el cliente, reabre la ventana y ahí sí el agente puede conversar. El patrón se llama plantilla para reabrir, y es la solución estándar. Diséñalo desde el principio si tu caso lo va a necesitar.

Y una consecuencia que casi nadie anticipa: el reloj de la ventana no es el reloj de tu memoria. El nodo de memoria del Módulo 3 guarda el historial indefinidamente en Postgres. La ventana de WhatsApp caduca en 24 horas. Son dos relojes independientes. Un cliente que vuelve a escribir a los tres días abre una ventana nueva y el agente lo reconoce perfectamente, porque la memoria nunca caducó. Eso está bien y es lo deseable — pero implica que el agente puede referirse a algo que se conversó hace tres días con un cliente que quizás ya lo olvidó. Vale la pena que el prompt lo tenga en cuenta: retomar contexto viejo con una frase de anclaje ("volviendo a tu pedido #4521, que revisamos el lunes…") en vez de continuar como si no hubiera pasado el tiempo.

Las dos credenciales de n8n

Aquí hay un detalle que confunde y conviene decirlo directo: n8n necesita dos credenciales distintas de WhatsApp, y no son intercambiables. Una es para recibir y otra es para enviar.

# Credencial 1 — WhatsApp API  (la usa el nodo de ACCIÓN)
#   Nodo: WhatsApp Business Cloud
#   Sirve para: enviar mensajes, plantillas y medios
Access Token        ← Meta > tu app > WhatsApp > API Setup > Generate access token
Business Account ID ← la misma pantalla, es el ID de la WABA

# Credencial 2 — WhatsApp OAuth2  (la usa el nodo de DISPARO)
#   Nodo: WhatsApp Trigger
#   Sirve para: registrar y suscribir el webhook que recibe mensajes
Client ID     ← Meta > tu app > App settings > Basic > App ID
Client Secret ← la misma pantalla > App Secret

La razón de que sean dos es que hacen cosas distintas. Enviar un mensaje es una llamada autenticada a la API de WhatsApp con un token; suscribirse a los eventos de una app requiere identificarse como esa app, y para eso Meta usa el flujo de OAuth con el ID y el secreto de la aplicación. No es un capricho de n8n: son dos superficies de la plataforma de Meta.

El síntoma de equivocarse es característico: el agente envía perfecto pero nunca recibe nada (falta o está mal la credencial del trigger), o al revés, el trigger dispara con cada mensaje entrante pero el envío falla con un error de autorización (falta o caducó el token de la credencial de API).

El WhatsApp Trigger

El nodo WhatsApp Trigger es el que escucha. Su parámetro principal es la lista de eventos a los que se suscribe, y la documentación de n8n lista estos:

Account Review Update          Message Template Quality Update
Account Update                 Message Template Status Update
Business Capability Update     Messages                     ◄── el que te importa
Phone Number Name Update       Security
Phone Number Quality Update    Template Category Update

Para un agente conversacional, el único que necesitas es Messages. Los demás sirven para monitorear la salud de tu cuenta —que Meta bajó la calidad de tu número, que una plantilla fue rechazada, que la cuenta está bajo revisión—, y son valiosos en producción pero no tienen nada que ver con atender clientes. Suscribirte a todos "por si acaso" solo te va a llenar el registro de ejecuciones de ruido.

La trampa del webhook único

La documentación de n8n lo dice sin rodeos: WhatsApp solo permite registrar un webhook por app. Vale la pena entender por qué eso duele en la práctica.

En n8n, un trigger tiene dos URLs: la de test —que solo vive mientras el editor está abierto— y la de producción —que vive mientras el workflow esté activo—. En casi todos los nodos puedes tener las dos funcionando y probar en el editor sin romper producción. En WhatsApp no: hay un solo lugar donde Meta manda los mensajes, así que cuando pruebas en el editor, el webhook de producción deja de recibir. Y viceversa.

Las salidas prácticas, en orden de sensatez:

  1. Dos apps de Meta separadas, una de desarrollo y otra de producción, cada una con su número de prueba o real. Es lo correcto y lo que hace todo el mundo cuando el proyecto es serio.
  2. Aceptar la interrupción mientras estás aprendiendo: cuando pruebas, producción no recibe; cuando terminas, vuelves a activar el workflow. Para el mini-proyecto de esta guía es perfectamente aceptable.
  3. Probar con datos fijos: pegar un payload real capturado antes en un nodo de datos y ejecutar el workflow desde ahí, sin depender de que Meta mande nada. Es la técnica que más tiempo ahorra durante el desarrollo del prompt, porque no dependes de escribir desde un teléfono cada vez.

La tercera es la que más conviene tener en el bolsillo, y para usarla necesitas conocer la forma del payload. Vamos a eso.

Anatomía del mensaje entrante

Cuando alguien le escribe a tu número, Meta manda a tu webhook un objeto anidado. Su forma general es esta —y aquí va la advertencia: la estructura exacta y la ruta hasta cada campo dependen de la versión de la API de Meta y de cómo tu versión de n8n la presente, así que confirma con una ejecución real antes de escribir una expresión:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "<ID de la cuenta de WhatsApp Business>",
      "changes": [
        {
          "field": "messages",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "5215500000000",
              "phone_number_id": "<ID del número que RECIBE>"
            },
            "contacts": [
              {
                "profile": { "name": "Ana" },
                "wa_id": "5215512345678"
              }
            ],
            "messages": [
              {
                "from": "5215512345678",
                "id": "wamid.HBgN...",
                "timestamp": "1753200000",
                "type": "text",
                "text": { "body": "Hola, ¿cómo va mi pedido #4521?" }
              }
            ]
          }
        }
      ]
    }
  ]
}

Cuatro campos hacen todo el trabajo:

  • from — el número del cliente. Es la identidad estable que la lección 1 prometía: el mismo hoy, mañana y en un año. Es tu sessionId ideal.
  • text.body — lo que escribió. Ojo: solo existe si type es "text". Si la persona mandó un audio, una imagen o un sticker, este campo no está y una expresión que lo asuma va a fallar.
  • type — qué clase de mensaje es (text, image, audio, document, interactive, button…). Es el campo que te dice si puedes seguir adelante o si tienes que manejar otro formato.
  • contacts[0].profile.name — el nombre que la persona tiene puesto en su perfil de WhatsApp. Es gratis y humaniza mucho la primera respuesta. No es un dato verificado —cualquiera pone lo que quiera en su perfil— así que sirve para saludar, no para identificar.

Y hay un quinto elemento que no aparece arriba y que causa un problema muy específico: los eventos de estado. Meta no solo te avisa cuando alguien escribe; también te avisa cuando tu mensaje fue entregado y cuando fue leído. Esos llegan con un campo statuses en vez de messages. Si tu workflow no los filtra, cada mensaje que envías dispara dos o tres ejecuciones extra, el agente recibe un payload sin texto, y en el mejor caso falla y en el peor responde algo sin sentido. Filtrarlos es la primera línea de defensa del adaptador de entrada.

Ejemplo trabajado: el sistema del Módulo 5 atendiendo por WhatsApp

Vamos a montarlo. El cerebro no se toca: es el mismo triage_agent con order_specialist y billing_specialist. Lo que construimos es la capa de adaptación alrededor.

WhatsApp Trigger (evento: Messages)
   │
   ├─► IF: ¿es un mensaje de texto de verdad?
   │      (filtra statuses, y también audios/imágenes por ahora)
   │
   ├─► Set: normalize_incoming   ← el adaptador de entrada
   │
   ├─► AI Agent: triage_agent    ← el cerebro, intacto
   │      ├─ Postgres Chat Memory (Session ID = el teléfono)
   │      ├─ AI Agent Tool: order_specialist
   │      └─ AI Agent Tool: billing_specialist
   │
   └─► WhatsApp Business Cloud → Message → Send   ← el adaptador de salida

Paso 1 — El filtro. Antes que nada, descartar lo que no es un mensaje de texto:

# Nodo: IF — Name: is_text_message
# Solo deja pasar los eventos que traen un mensaje de texto real.
# Sin esto, los avisos de "entregado" y "leído" disparan el agente.

Condición 1:  {{ $json.entry[0].changes[0].value.messages }}   → existe
Condición 2:  {{ $json.entry[0].changes[0].value.messages[0].type }}  → igual a  "text"
Combinar:     AND

Las rutas de arriba son las del payload crudo de Meta. Confirma la ruta exacta en tu versión ejecutando una vez y mirando la salida del trigger: algunas versiones de n8n desanidan parte del objeto y la expresión se acorta bastante.

Paso 2 — El adaptador de entrada. Un nodo Set que convierte el objeto de Meta en tres campos limpios. Esto parece trivial y es la pieza que hace posible la arquitectura de la lección 7:

# Nodo: Set — Name: normalize_incoming
# Traduce el payload de Meta al formato que el núcleo espera.
# Los nombres de estos campos son TUYOS: elígelos una vez y
# úsalos igual en todos los canales.

channel          = "whatsapp"
channel_user_id  = {{ $json.entry[0].changes[0].value.messages[0].from }}
customer_name    = {{ $json.entry[0].changes[0].value.contacts[0].profile.name }}
text             = {{ $json.entry[0].changes[0].value.messages[0].text.body }}

Paso 3 — La memoria. Aquí es donde WhatsApp brilla, y vale la pena detenerse. En el chat web tuviste que inventarte un mecanismo (metadata) para conseguir una identidad estable del cliente. En WhatsApp la identidad viene incluida: el número de teléfono es único, es real, y es el mismo para siempre.

# Nodo: Postgres Chat Memory (conectado al triage_agent)

Session ID:  Define below
Key:         {{ $('normalize_incoming').item.json.channel_user_id }}

Esa expresión es literalmente la del Módulo 3, lección 4 — la credencial de empleado. Con ella, el cliente que escribió el lunes y vuelve el jueves reanuda su conversación sin repetir nada.

Paso 4 — El agente. Sin cambios, con una sola precaución: el AI Agent tiene que saber de dónde leer el texto. Como el trigger ya no es un Chat Trigger, hay que decírselo:

# Nodo: AI Agent — Name: triage_agent

Source for Prompt (User Message):  Define below
Prompt (User Message):             {{ $json.text }}

Ese es exactamente el error que el Módulo 3 anticipaba con el mensaje No session ID found: cuando el trigger no es un Chat Trigger, ni el prompt ni la sesión se resuelven solos.

Paso 5 — El adaptador de salida. El nodo WhatsApp Business Cloud, operación Send:

# Nodo: WhatsApp Business Cloud — Name: send_whatsapp_reply
# Resource: Message   ·   Operation: Send

Phone Number ID:  <el ID de TU número, el que RECIBE>
Recipient Phone Number:  {{ $('normalize_incoming').item.json.channel_user_id }}
Message Type:     Text
Text Body:        {{ $json.output }}

Dos campos que se confunden con frecuencia: Phone Number ID es el identificador de tu número de negocio, un número largo que te da Meta y que no es un teléfono; Recipient Phone Number es el teléfono de la persona, en formato internacional sin + ni espacios. Poner uno en el lugar del otro produce un error de la API que no dice claramente cuál de los dos está mal.

Y {{ $json.output }} es el campo donde el nodo AI Agent entrega su respuesta. Verifica el nombre en tu versión mirando la salida del nodo: es de las cosas que cambian entre versiones.

Qué esperar. Guarda, activa el workflow, y escríbele desde uno de los teléfonos que registraste como destinatario de prueba: "Hola, ¿cómo va mi pedido #4521?". Después de unos segundos —y van a ser varios, porque el triage_agent delega— llega la respuesta a tu WhatsApp. En la pestaña de ejecuciones de n8n vas a ver la corrida completa, con su traza de delegaciones, exactamente igual que en el Módulo 5. Ese es el punto entero de la arquitectura: cambió la puerta, no el cerebro.

Perfecto. Si llegaste hasta aquí con un mensaje real llegando a tu teléfono, ya tienes el canal más difícil del módulo funcionando.

Las otras operaciones del nodo

El nodo WhatsApp Business Cloud hace más que enviar texto. Vale la pena conocer el catálogo para saber qué es posible.

Message → Send. Lo que acabas de usar. Manda un mensaje dentro de la ventana de 24 horas.

Message → Send Template. Manda una plantilla aprobada, rellenando sus variables. Es la única forma de escribirle a alguien fuera de la ventana. Necesitas el nombre de la plantilla, el idioma y los valores de las variables en orden.

Message → Send and Wait for Response. El equivalente en WhatsApp del patrón de human-in-the-loop que viste en la lección 2 con el nodo Chat. Manda un mensaje y pausa la ejecución hasta que la persona conteste. Los tipos de respuesta son los mismos tres: Approval (botones de aprobar y rechazar), Free Text (un formulario donde escribe libremente) y Custom Form (un formulario que armas tú). Es la vía más simple para conseguir una confirmación inequívoca antes de una acción sensible sin tener que interpretar un "sí" ambiguo.

Media → Upload / Download / Delete. Para mandar y recibir archivos. Download es el que más va a servirte: cuando un cliente manda una foto de un producto dañado o un comprobante de pago, el mensaje entrante no trae el archivo, trae un ID de medio; hay que descargarlo con ese ID. Es un flujo de dos pasos que sorprende la primera vez.

Sobre botones y respuestas rápidas hay una nota honesta que hacer. WhatsApp soporta mensajes interactivos con botones y con listas, y son una herramienta de UX enorme —la lección 6 los trata a fondo—. El nivel de soporte nativo para construirlos desde el nodo varía entre versiones de n8n; en algunas hay que armar el cuerpo interactivo con un nodo HTTP Request contra la API de Meta directamente. Abre el nodo en tu instalación y revisa qué tipos de mensaje ofrece el selector Message Type antes de diseñar una conversación que dependa de botones. Si no están, la salida por HTTP Request funciona igual de bien; solo hay que escribir el JSON a mano.

Errores comunes

Instalar la aplicación WhatsApp Business y esperar que se conecte (conceptual). Qué pasa: alguien descarga la app en su teléfono, configura el perfil del negocio, y después busca durante media hora dónde está la opción de conectarla con n8n. No existe. Por qué pasa: los nombres son casi idénticos y la app es lo primero que aparece al buscar. Cómo detectarlo: si estás en un teléfono, es esto. Cómo corregirlo: todo el flujo de la API empieza en el panel de desarrolladores de Meta, en un navegador, y nunca requiere instalar nada. Si además el número que querías usar ya está en la app, hay que darlo de baja antes de registrarlo en la API.

El token temporal que caduca de un día para otro (práctico). Qué pasa: montas todo, funciona precioso, lo dejas activo, y al día siguiente cada envío falla con un error de autorización mientras el trigger sigue recibiendo mensajes con normalidad. Nadie tocó nada. Por qué pasa: el token que Meta genera con un clic en la pantalla de configuración de la API es de corta duración, típicamente 24 horas. Está pensado para probar. Cómo detectarlo: el patrón es inconfundible — recibe bien, envía mal, y empezó de golpe sin cambios. Cómo corregirlo: genera un token de larga duración a partir de un usuario del sistema en la configuración de tu portafolio de negocio, y guárdalo en la credencial de WhatsApp API. Y anota en algún lado cuándo caduca, porque los de larga duración también caducan.

No filtrar los eventos de estado y provocar ejecuciones fantasma (práctico). Qué pasa: por cada mensaje que el agente envía aparecen dos o tres ejecuciones más en el registro, algunas fallidas y otras con respuestas absurdas. En casos malos, el agente responde a sus propios acuses de recibo y se genera un ida y vuelta que consume tokens sin que nadie lo esté usando. Por qué pasa: el evento Messages incluye tanto mensajes entrantes como cambios de estado (sent, delivered, read), y esos últimos llegan sin campo de texto. Cómo detectarlo: abre una de las ejecuciones raras y busca la palabra statuses en el payload del trigger; si está, es esto. Cómo corregirlo: el nodo IF del paso 1 del ejemplo trabajado, que exige que exista messages y que type sea "text". Es una condición de dos líneas que evita el problema entero.

Asumir que todos los mensajes son texto (práctico). Qué pasa: el agente funciona bien en las pruebas y falla el primer día real, cuando un cliente manda un audio de voz —cosa completamente normal en WhatsApp en LATAM— y la expresión que lee text.body devuelve vacío. El agente recibe un mensaje en blanco y responde algo sin sentido, o el workflow falla. Por qué pasa: en las pruebas uno escribe, y los clientes reales mandan audios, fotos y stickers. Cómo detectarlo: revisa el campo type en las ejecuciones fallidas. Cómo corregirlo: a corto plazo, el filtro por type = "text" con una rama alternativa que responda algo honesto como "Por ahora solo puedo leer mensajes de texto, ¿me lo escribes?". A mediano plazo, un nodo de transcripción de audio delante del agente convierte el audio en texto y el problema desaparece — y eso, en LATAM, suele ser una de las mejoras que más se notan.

Diseñar un agente que necesita escribir primero, sin plantillas (conceptual). Qué pasa: alguien construye un flujo donde el agente hace seguimiento a las 48 horas para preguntar si el problema se resolvió. En pruebas funciona, porque en pruebas siempre hay una conversación abierta. En producción, el mensaje nunca llega, y el error de Meta habla de una ventana cerrada. Por qué pasa: la ventana de 24 horas es invisible mientras uno prueba conversando de ida y vuelta. Cómo detectarlo: cualquier mensaje que tu sistema envíe sin que el cliente haya escrito en las últimas 24 horas está en riesgo. Cómo corregirlo: registra una plantilla de categoría utility para ese seguimiento, apruébala con Meta, y envíala con Send Template. El texto va a ser fijo y eso está bien: su único trabajo es reabrir la ventana. Cuando el cliente responda a la plantilla, ahí sí tu agente puede conversar libremente.

Ejercicios

Ejercicio 1 — Decide plantilla o texto libre. Para cada uno de estos cinco mensajes de TuTienda, di si se puede enviar como texto libre o si requiere una plantilla aprobada, y en el segundo caso qué categoría le pondrías.

  1. Respuesta a un cliente que preguntó por su pedido hace treinta segundos.
  2. Aviso de que el pedido salió del centro de distribución, dos días después de la última conversación.
  3. Segunda respuesta en la misma conversación, tres minutos después de la primera.
  4. Promoción de fin de temporada a todos los clientes que compraron el año pasado.
  5. Resultado de una disputa de cobro que tardó cuatro días en resolverse.
Ver solución
  1. Texto libre. La ventana está abierta de sobra. Mensaje de servicio, sin costo.
  2. Plantilla, categoría utility. Pasaron dos días, la ventana cerró. Es información transaccional sobre un pedido que el cliente ya hizo, así que utility es la categoría correcta y la más barata de las de pago.
  3. Texto libre. Sigue dentro de la ventana, y además cada mensaje del cliente la reinicia.
  4. Plantilla, categoría marketing. No hay conversación abierta y el contenido es promocional. Es la categoría más cara, y también la que más riesgo tiene: si mucha gente la marca como no deseada, Meta baja la calidad de tu número y eso afecta a todo lo demás que envíes.
  5. Plantilla, categoría utility. Aunque el contenido sea la resolución de un caso, pasaron cuatro días. Fíjate en el patrón de diseño que esto obliga: la plantilla no puede contener el resultado detallado de la disputa —el texto es fijo— así que lo razonable es una plantilla que diga "tenemos novedades sobre tu caso {{1}}, respóndenos para conocerlas", y en cuanto el cliente responda, la ventana se abre y el agente explica con todo el detalle que quiera.

Ese último caso es el más instructivo del ejercicio: la plantilla no transmite la información, transmite la invitación a reabrir la conversación. Entender eso cambia cómo se diseña cualquier flujo asíncrono en WhatsApp.

Por qué funciona: los cinco casos se resuelven con una sola pregunta —¿escribió el cliente en las últimas 24 horas?— y el ejercicio la vuelve automática.

Ejercicio 2 — Diagnostica el bucle. Un compañero activa su agente de WhatsApp y a los pocos minutos ve treinta ejecuciones en el registro, sin que nadie haya escrito. Algunas fallan; otras terminan con el agente respondiendo cosas sin sentido. Explica qué está pasando, cómo lo confirmarías, y escribe la condición exacta que lo corrige.

Ver solución

Lo que pasa es el problema de los eventos de estado. El trigger está suscrito a Messages, y ese evento no trae solo los mensajes que escriben las personas: trae también los cambios de estado de los mensajes que tú envías —enviado, entregado, leído—. Cada respuesta del agente genera dos o tres eventos de estado, cada uno dispara el workflow, y el agente se encuentra con un payload sin campo de texto.

En el peor caso esto se realimenta: si el flujo no falla del todo y el agente logra mandar algo, ese algo genera nuevos estados, que disparan de nuevo. No es un bucle infinito estricto —los estados de un mensaje son finitos— pero sí multiplica las ejecuciones y el consumo de tokens de forma alarmante.

Cómo confirmarlo: abre una de las ejecuciones raras y mira el JSON del trigger. Si dentro de value hay una clave statuses en lugar de messages, ya está confirmado.

La corrección, en un IF inmediatamente después del trigger:

# Nodo: IF — Name: is_text_message

Condición 1:  {{ $json.entry[0].changes[0].value.messages }}  →  existe / no vacío
Condición 2:  {{ $json.entry[0].changes[0].value.messages[0].type }}  →  igual a "text"
Combinar:     AND

La primera condición descarta los eventos de estado; la segunda descarta audios, imágenes y stickers, que también hay que manejar aparte. Y confirma la ruta contra una ejecución real de tu versión: si tu n8n desanida el payload, la expresión se acorta.

Un detalle de higiene que vale la pena agregar: por la rama falsa del IF no pongas nada, o pon un nodo No Operation. No respondas nada por esa rama — responder a un acuse de recibo es exactamente lo que estamos evitando.

Por qué funciona: el ejercicio enseña a leer el payload en vez de adivinar, que es la habilidad que resuelve el 80% de los problemas de cualquier canal.

Ejercicio 3 — Escribe el flujo de seguimiento. billing_specialist abre una disputa por un cobro no reconocido y el equipo de facturación tarda entre dos y cuatro días en resolverla. Diseña el flujo completo para notificar al cliente cuando se resuelva. Escribe: (a) el texto de la plantilla con sus variables y su categoría; (b) qué pasa cuando el cliente responde a esa plantilla; (c) qué tiene que saber el agente en ese momento para no sonar perdido.

Ver solución

(a) La plantilla. Categoría utility, porque es información transaccional sobre un caso que el cliente abrió:

# Plantilla: dispute_resolved_notice  (utility)

Hola {{1}}, ya tenemos una resolución para la disputa {{2}} que
abriste el {{3}}. Respóndenos por aquí y te compartimos el detalle.

Fíjate en lo que no dice: no dice si la disputa se resolvió a favor o en contra. Hay dos razones y las dos importan. La primera es que el texto de una plantilla es fijo, y una resolución tiene matices que no caben en variables. La segunda es de producto: una mala noticia no se da en un mensaje que no espera respuesta. La plantilla abre la puerta; el agente conversa.

(b) Cuando el cliente responde. Su respuesta llega por el WhatsApp Trigger como cualquier otro mensaje, abre la ventana de 24 horas, y entra al triage_agent normalmente. A partir de ahí es una conversación común y corriente.

(c) Lo que el agente tiene que saber. Aquí está la parte interesante, y es donde el ejercicio se pone a prueba. Si el cliente responde solo "sí, cuéntame", el agente recibe un mensaje sin ninguna referencia a la disputa. Tres cosas lo salvan, y conviene tener las tres:

  1. La memoria persistente. Como el sessionId es el teléfono, el historial de cuando se abrió la disputa sigue ahí. El agente puede leer que hace cuatro días se abrió la disputa D-8842.
  2. Un registro del caso consultable por tool. Mejor todavía: una tool lookup_dispute que dado el teléfono o el ID devuelva el estado actual. La memoria dice qué se conversó; la tool dice qué pasó realmente después, que no es lo mismo.
  3. Una instrucción de anclaje en el prompt. Algo como: "si el cliente responde a una notificación de seguimiento, retoma explícitamente el caso al que se refiere antes de dar el detalle, porque pueden haber pasado días desde la última conversación." Sin eso, el agente puede responder correctamente pero sin contexto, y al cliente le cae encima una resolución sin recordar de qué caso se trata.

La versión superior del diseño —vale la pena mencionarla— es registrar en tu propia base de datos que a ese teléfono se le envió la plantilla dispute_resolved_notice para el caso D-8842. Así, cuando llega cualquier mensaje de ese número en las siguientes horas, el adaptador de entrada puede inyectar ese contexto directamente. Es más trabajo y es lo que separa un flujo que funciona de uno que se siente bien.

Por qué funciona: el ejercicio junta las tres cosas nuevas de esta lección —la ventana, la plantilla y la memoria que no caduca con ella— en un flujo que aparece en cualquier sistema de atención real.

Resumen y siguiente paso

Ya tienes el canal más importante de LATAM funcionando con el cerebro del Módulo 5 detrás. Distinguiste la API de la aplicación que se le parece en el nombre, armaste las piezas de Meta y sabes cuál de ellas es un trámite de producción y cuál es un atajo de desarrollo, creaste las dos credenciales que n8n necesita —OAuth2 para recibir, token de API para enviar— y sabes reconocer el síntoma de tener una mal. Filtraste los eventos de estado que de otro modo disparan ejecuciones fantasma, normalizaste el payload en tres campos limpios, y usaste el teléfono del cliente como clave de memoria persistente, que es la mejor identidad que ningún canal te va a regalar.

Y sobre todo, entendiste la regla que gobierna el diseño: dentro de la ventana de 24 horas tu agente conversa libremente y gratis; fuera de ella solo puede enviar una plantilla aprobada y pagada, cuyo trabajo real no es informar sino reabrir la puerta.

Antes de avanzar deberías poder: explicar en una frase por qué n8n necesita dos credenciales de WhatsApp y qué falla si tienes solo una; decir qué pasa con la URL de test cuando activas el workflow de producción, y por qué; y escribir de memoria la condición que descarta los eventos de estado.

La lección 4 baja el nivel de dificultad a propósito. Telegram hace casi todo lo que hace WhatsApp —trigger, mensajes, botones— sin cobrar nada, sin verificación de negocio, sin ventana de 24 horas, y con un bot creado en dos minutos hablando con otro bot. Es el laboratorio donde vas a practicar los botones interactivos y el patrón de callback que después se traslada a WhatsApp, y es la alternativa completa si tu verificación en Meta sigue en trámite.

Recursos