Flowise en WhatsApp por la API oficial, con ZapClaw

En resumen: ZapClaw entrega cada mensaje de WhatsApp a un pequeño script intermediario (el relay), que le pregunta a tu flujo de Flowise por la Prediction API, y la respuesta vuelve por ZapClaw. Los mensajes pasan por la Cloud API oficial de Meta, y el número sigue funcionando en la app de WhatsApp Business de tu celular. Funciona con chatflows y agentflows, y no necesitas una app de Meta propia.

Conecta tu número en minutos y dale a tu agente de Flowise el número de WhatsApp que tus clientes ya usan, en la nube o self-hosted.

Plan Business: US$ 29 al mes, con números ilimitados

Empieza gratis Ver el relay

Lo que necesitas para conectar

No necesitas una empresa registrada ni un negocio verificado para conectar. La lista completa.

Por qué ZapClaw para un agente de Flowise en WhatsApp

Por qué hay un relay en medio

Flowise ejecuta un flujo desde su Prediction API, con el mensaje en un campo question, y devuelve la respuesta en el cuerpo de la misma llamada HTTP. El webhook de ZapClaw trae su propio JSON y no lee el cuerpo de la respuesta, así que el relay hace de puente: convierte cada mensaje en una pregunta, y la respuesta en un envío por ZapClaw.

El relay de abajo tiene menos de 70 líneas de Node.js, sin nada que instalar. Si ya usas n8n, puede hacer de relay, como mostramos más abajo.

Configúralo en cuatro pasos

  1. En Flowise, guarda tu chatflow o agentflow y anota el ID del flujo. Si le asignaste una clave de API al flujo, anota esa clave también.
  2. En ZapClaw, conecta tu número, crea una clave de API y copia la Clave de firma en la página Webhook.
  3. Ejecuta el relay de abajo con esos valores en un servidor con una dirección HTTPS pública, y pega esa dirección en Webhook en ZapClaw. ZapClaw solo entrega en una dirección HTTPS pública.
  4. Haz clic en Enviar evento de prueba en ZapClaw: el relay responde 200 y no le pregunta nada a Flowise. Luego envía un mensaje de WhatsApp a tu número desde otro celular: el flujo responde.

El relay, listo para ejecutar

Guárdalo como relay.mjs e inícialo con node relay.mjs en Node.js 18 o posterior. Lee su configuración del entorno: ZAPCLAW_API_KEY, ZAPCLAW_SECRET (la clave de firma), FLOWISE_URL (la dirección de tu Flowise), FLOW_ID, FLOWISE_API_KEY cuando el flujo tenga una, y PORT, el puerto en el que escucha el relay (8787 por defecto), al que tu proxy HTTPS reenvía.

// relay.mjs: ZapClaw webhook in, Flowise Prediction API, the answer out through ZapClaw.
// Node.js 18 or newer, nothing to install. Start it with: node relay.mjs
import { createServer } from 'node:http';
import { createHmac, timingSafeEqual } from 'node:crypto';

const ZAPCLAW_API_KEY = process.env.ZAPCLAW_API_KEY; // zc_live_...
const ZAPCLAW_SECRET = process.env.ZAPCLAW_SECRET; // the webhook signing secret
const FLOWISE_URL = process.env.FLOWISE_URL || 'http://localhost:3000'; // your Flowise address
const FLOW_ID = process.env.FLOW_ID; // the ID of your chatflow or agentflow
const FLOWISE_API_KEY = process.env.FLOWISE_API_KEY; // only when the flow has an API key

const queues = new Map(); // one message at a time per customer, in order

const isSigned = (raw, header = '') => {
  const hmac = createHmac('sha256', ZAPCLAW_SECRET).update(raw).digest('hex');
  const expected = Buffer.from(`sha256=${hmac}`);
  const given = Buffer.from(String(header));
  return given.length === expected.length && timingSafeEqual(given, expected);
};

const answer = async ({ data, account }) => {
  // The customer is the session: Flowise keeps one conversation memory per sessionId.
  const res = await fetch(new URL(`api/v1/prediction/${FLOW_ID}`, FLOWISE_URL), {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...(FLOWISE_API_KEY && { Authorization: `Bearer ${FLOWISE_API_KEY}` }),
    },
    body: JSON.stringify({
      question: data.text.body,
      overrideConfig: { sessionId: data.user_id || data.from },
    }),
  });
  if (!res.ok) throw new Error(`Flowise answered ${res.status}`);
  const { text } = await res.json();
  if (!text) return;
  await fetch('https://api.zapclaw.app/api/v1/send/text', {
    method: 'POST',
    headers: { 'X-API-Key': ZAPCLAW_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      from: account.display_phone_number || account.phone_number_id,
      to: data.from || data.user_id,
      text: text.slice(0, 4096),
    }),
  });
};

createServer((req, res) => {
  const chunks = [];
  req.on('data', (chunk) => chunks.push(chunk));
  req.on('end', () => {
    const raw = Buffer.concat(chunks);
    if (!isSigned(raw, req.headers['x-zapclaw-signature'])) return res.writeHead(401).end();
    res.writeHead(200).end(); // answer ZapClaw now: it waits 10 seconds, a flow can take longer
    let event;
    try {
      event = JSON.parse(raw.toString('utf8'));
    } catch {
      return;
    }
    if (event.event !== 'message.received' || event.data?.type !== 'text') return;
    const key = event.data.user_id || event.data.from;
    const next = (queues.get(key) || Promise.resolve())
      .then(() => answer(event))
      .catch((err) => console.error(err));
    queues.set(key, next);
  });
}).listen(process.env.PORT || 8787);

Lo que hace: comprueba el encabezado X-ZapClaw-Signature, responde a ZapClaw de inmediato (ZapClaw espera 10 segundos, y un modelo puede tardar más) y le pregunta a Flowise un mensaje a la vez por cliente, para que las respuestas mantengan su orden. La respuesta del flujo vuelve en el campo text y sale como un mensaje de WhatsApp.

En un agentflow, deja el nodo Start en Chat Input: el relay envía el mensaje como question, y un inicio en Form Input espera un objeto form.

O usa n8n como relay

¿Ya usas n8n? Importa el flujo de nuestra página de n8n y agrega, entre el filtro y la respuesta, un nodo HTTP Request que envía a la Prediction API de tu flujo question igual a {{ $json.body.data.text.body }} y overrideConfig.sessionId igual a {{ $json.body.data.user_id || $json.body.data.from }}. Después de ese nodo, $json pasa a ser la respuesta de Flowise, así que en la respuesta usa {{ $json.text }} en text y haz que from y to lean el nodo del webhook: {{ $('ZapClaw webhook').item.json.body.account.display_phone_number || $('ZapClaw webhook').item.json.body.account.phone_number_id }} y {{ $('ZapClaw webhook').item.json.body.data.from || $('ZapClaw webhook').item.json.body.data.user_id }}.

Llamar a ZapClaw desde dentro de Flowise

Flowise también puede llamar a la API de ZapClaw por su cuenta: con el nodo HTTP de un agentflow, o con una Custom Tool que el agente decide usar, con un encabezado X-API-Key. Por ejemplo, una herramienta que avisa a un vendedor por WhatsApp cuando un cliente pide una cotización. Dentro de una Custom Tool, $flow.sessionId trae al cliente, porque el relay lo pasa como sesión, y una variable de Flowise leída con $vars puede guardar tu clave de ZapClaw. La llamada en sí, como comando curl:

curl -X POST https://api.zapclaw.app/api/v1/send/text \
  -H "X-API-Key: zc_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "from": "15551617409", "to": "15555550100", "text": "A customer asked for a quote" }'

from es tu número conectado, que el webhook trae en account.display_phone_number, y to es la persona a quien escribes. Un mensaje enviado responde 201. El texto libre funciona dentro de las 24 horas siguientes al último mensaje de esa persona a tu número; fuera de esa ventana, Meta solo acepta una plantilla aprobada, con POST /api/v1/send/template.

Lo que llega al relay

Cada mensaje llega como un evento message.received: el texto en data.text.body, el remitente en data.from (o data.user_id para un contacto que solo muestra su nombre de usuario), el nombre del contacto en data.contact_name y tu número en account.display_phone_number.

{
  "event": "message.received",
  "sequence": 1042,
  "timestamp": "2026-10-15T14:00:00.000Z",
  "data": {
    "from": "15555550100",
    "user_id": "US.1A2B3C4D5E6F7G8H9I0J",
    "contact_name": "Maria Silva",
    "message_id": "wamid.HBg...",
    "type": "text",
    "timestamp": "1792072800",
    "text": { "body": "Do you deliver on Saturdays?" }
  },
  "account": {
    "phone_number_id": "964283400112599",
    "display_name": "My Business",
    "display_phone_number": "+1 555 161-7409"
  }
}

El relay solo pasa los mensajes de texto entrantes: el evento de prueba del panel y cualquier otro evento reciben un 200 y nada más. Un audio o una imagen trae una media_url que descargas con tu clave de API, si quieres pasársela a Flowise más adelante. Todos los eventos y campos están en la documentación (en inglés).

Cuánto cuesta

Meta te cobra directamente las tarifas de mensajes de WhatsApp, sin margen de ZapClaw. Todos los planes y precios.

Para quién es

Equipos que construyeron en Flowise un agente de IA, un asistente sobre sus propios documentos o un flujo de clasificación de consultas de soporte y quieren llevarlo al número de WhatsApp que sus clientes ya usan. Las agencias conectan los números de sus clientes en el plan Agency, cada cliente aislado de los demás. No sirve para envíos masivos.

Para ir más allá

Fuentes

Documentación de Flowise, en inglés, consultada el 15 de octubre de 2026. Las funciones cambian, así que revisa cada fuente antes de construir.

Pon tu agente de Flowise en WhatsApp hoy

Empieza en el plan gratuito: un número, sin tarjeta. Pasa al plan Business cuando necesites más números o más mensajes.

Empieza gratis Ver la documentación del webhook (en inglés)