Flowise no WhatsApp pela API oficial, com o ZapClaw

Em resumo: o ZapClaw entrega cada mensagem do WhatsApp a um pequeno script intermediário (o relay), que pergunta ao seu fluxo do Flowise pela Prediction API, e a resposta volta pelo ZapClaw. As mensagens passam pela API Cloud oficial da Meta, e o número continua funcionando no app WhatsApp Business do celular. Funciona com chatflows e agentflows, e você não precisa de app próprio na Meta.

Conecte o seu número em minutos e dê ao seu agente do Flowise o número de WhatsApp que os seus clientes já usam, na nuvem ou self-hosted.

Plano Business: R$ 99 por mês, com números ilimitados

Comece grátis Ver o relay

O que você precisa para conectar

Não precisa de CNPJ nem de empresa verificada para conectar. A lista completa.

Por que o ZapClaw para um agente do Flowise no WhatsApp

Por que existe um relay no meio

O Flowise roda um fluxo pela Prediction API, com a mensagem num campo question, e devolve a resposta no corpo da mesma chamada HTTP. O webhook do ZapClaw traz o próprio JSON e não lê o corpo da resposta, então o relay faz a ponte: transforma cada mensagem numa pergunta, e a resposta num envio pelo ZapClaw.

O relay abaixo tem menos de 70 linhas de Node.js, sem nada para instalar. Se você já usa o n8n, ele pode fazer o papel do relay, como mostramos mais abaixo.

Configure em quatro passos

  1. No Flowise, salve o seu chatflow ou agentflow e anote o ID do fluxo. Se você atribuiu uma chave de API ao fluxo, anote essa chave também.
  2. No ZapClaw, conecte o seu número, crie uma chave de API e copie a Chave de assinatura na página Webhook.
  3. Rode o relay abaixo com esses valores num servidor com endereço HTTPS público e cole esse endereço em Webhook no ZapClaw. O ZapClaw só entrega em endereço HTTPS público.
  4. Clique em Enviar evento de teste no ZapClaw: o relay responde 200 e não pergunta nada ao Flowise. Depois mande uma mensagem de WhatsApp para o seu número de outro celular: o fluxo responde.

O relay, pronto para rodar

Salve como relay.mjs e inicie com node relay.mjs no Node.js 18 ou mais recente. Ele lê as configurações do ambiente: ZAPCLAW_API_KEY, ZAPCLAW_SECRET (a chave de assinatura), FLOWISE_URL (o endereço do seu Flowise), FLOW_ID, FLOWISE_API_KEY quando o fluxo tiver uma, e PORT, a porta em que o relay escuta (8787 por padrão), para a qual o seu proxy HTTPS encaminha.

// 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);

O que ele faz: confere o cabeçalho X-ZapClaw-Signature, responde ao ZapClaw na hora (o ZapClaw espera 10 segundos, e um modelo pode demorar mais) e pergunta ao Flowise uma mensagem de cada vez por cliente, para as respostas manterem a ordem. A resposta do fluxo volta no campo text e sai como uma mensagem de WhatsApp.

Num agentflow, deixe o nó Start em Chat Input: o relay envia a mensagem como question, e um início em Form Input espera um objeto form.

Ou use o n8n como relay

Já usa o n8n? Importe o fluxo da nossa página do n8n e coloque, entre o filtro e a resposta, um nó HTTP Request que envia para a Prediction API do seu fluxo question igual a {{ $json.body.data.text.body }} e overrideConfig.sessionId igual a {{ $json.body.data.user_id || $json.body.data.from }}. Depois desse nó, $json passa a ser a resposta do Flowise, então, na resposta, use {{ $json.text }} em text e faça from e to lerem o nó do webhook: {{ $('ZapClaw webhook').item.json.body.account.display_phone_number || $('ZapClaw webhook').item.json.body.account.phone_number_id }} e {{ $('ZapClaw webhook').item.json.body.data.from || $('ZapClaw webhook').item.json.body.data.user_id }}.

Chamando o ZapClaw de dentro do Flowise

O Flowise também chama a API do ZapClaw por conta própria: pelo nó HTTP de um agentflow, ou por uma Custom Tool que o agente decide usar, com um cabeçalho X-API-Key. Por exemplo, uma ferramenta que avisa um vendedor no WhatsApp quando um cliente pede um orçamento. Dentro de uma Custom Tool, $flow.sessionId traz o cliente, porque o relay passa o cliente como sessão, e uma variável do Flowise lida por $vars pode guardar a sua chave do ZapClaw. A chamada em si, 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 é o seu número conectado, que o webhook traz em account.display_phone_number, e to é a pessoa para quem você escreve. Uma mensagem enviada responde 201. Texto livre funciona dentro de 24 horas desde a última mensagem dessa pessoa para o seu número; fora dessa janela, a Meta só aceita um template aprovado, pelo POST /api/v1/send/template.

O que chega no relay

Cada mensagem chega como um evento message.received: o texto em data.text.body, o remetente em data.from (ou data.user_id para um contato que só mostra o nome de usuário), o nome do contato em data.contact_name e o seu número em 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"
  }
}

O relay só repassa mensagens de texto recebidas: o evento de teste do painel e qualquer outro evento recebem um 200 e nada mais. Um áudio ou uma imagem traz uma media_url que você baixa com a sua chave de API, se quiser entregar ao Flowise depois. Todos os eventos e campos estão na documentação (em inglês).

Quanto custa

A Meta cobra as tarifas de mensagem do WhatsApp direto de você, sem margem do ZapClaw. Todos os planos e preços.

Para quem é

Equipes que montaram no Flowise um agente de IA, um assistente sobre os próprios documentos ou um fluxo de triagem de atendimento e querem levar isso para o número de WhatsApp que os clientes já usam. Agências conectam os números dos clientes no plano Agency, cada cliente isolado dos outros. Não serve para disparo em massa.

Para ir além

Fontes

Documentação do Flowise, em inglês, conferida em 15 de outubro de 2026. Recursos mudam, então confira cada fonte antes de construir.

Coloque o seu agente do Flowise no WhatsApp hoje

Comece no plano grátis: um número, sem cartão. Passe para o plano Business quando precisar de mais números ou de mais mensagens.

Comece grátis Ver a documentação do webhook (em inglês)