Flowise on WhatsApp through the official API, with ZapClaw
In short: ZapClaw delivers each WhatsApp message to a small relay, the relay asks your Flowise flow through its Prediction API, and the answer goes back through ZapClaw. Messages travel on Meta's official Cloud API, and the number keeps working in the WhatsApp Business app on your phone. Chatflows and agentflows both work, and you need no Meta app of your own.
Connect your number in minutes and give your Flowise agent the WhatsApp number your customers already use, in the cloud or self-hosted.
Business plan: US$ 29 per month, with unlimited numbers
Start for free See the relayWhat you need to connect
- The WhatsApp Business app on the number, version 2.24.17 or newer, in regular use.
- Two-factor authentication on the personal Facebook account that authorizes the connection.
- The number not connected to another provider. If it is, disconnect it there first.
- A computer to run the connection, with your phone at hand to confirm it in the app.
You do not need a company tax ID or a verified business to connect. The full checklist.
Why ZapClaw for a Flowise agent on WhatsApp
- The number stays in the WhatsApp Business app. Through Coexistence your team keeps answering in the app while Flowise works the same number.
- No Meta app of your own. You connect the number in Meta's Embedded Signup window, from the ZapClaw dashboard, and ZapClaw runs the Cloud API side.
- One memory per customer. The relay passes the customer as the
sessionId, and Flowise keeps a separate conversation for each session, so the agent remembers what that person said before. - No unofficial library behind your agent. Integrations that imitate WhatsApp Web go against WhatsApp's terms and put the number at risk. ZapClaw uses Meta's Cloud API, and Meta's policies apply as they do to any business on it.
- Deliveries you can check. Each event is signed with HMAC-SHA256 and gets up to 3 delivery attempts when your relay does not answer, and a failed event can be replayed from the dashboard.
Why a relay sits in between
Flowise runs a flow from its Prediction API, with the message in a question field, and returns the answer in the same HTTP response. ZapClaw's webhook carries its own JSON and does not read an answer from the response, so a small relay sits in between: it turns each message into a question, and the answer into a send through ZapClaw.
The relay below is under 70 lines of Node.js, with nothing to install. If you already run n8n, it can be the relay instead, as shown further down.
Set it up in four steps
- In Flowise, save your chatflow or agentflow and note its flow ID. If you assigned an API key to the flow, note that key too.
- In ZapClaw, connect your number, create an API key and copy the Signing secret from the Webhook page.
- Run the relay below with those values on a server with a public HTTPS address, and paste that address under Webhook in ZapClaw. ZapClaw delivers only to a public HTTPS address.
- Press Send test event in ZapClaw: the relay answers
200and asks Flowise nothing. Then send a WhatsApp message to your number from another phone: the flow answers.
The relay, ready to run
Save it as relay.mjs and start it with node relay.mjs on Node.js 18 or newer. It reads its settings from the environment: ZAPCLAW_API_KEY, ZAPCLAW_SECRET (the signing secret), FLOWISE_URL (your Flowise address), FLOW_ID, FLOWISE_API_KEY when the flow has one, and PORT, the port the relay listens on (8787 by default), which your HTTPS proxy forwards to.
// 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);
What it does: it checks the X-ZapClaw-Signature header, answers ZapClaw at once (ZapClaw waits 10 seconds, and a model can take longer) and asks Flowise one message at a time per customer, so the answers keep their order. The flow's answer comes back in the text field and goes out as a WhatsApp message.
In an agentflow, keep the Start node on Chat Input: the relay sends the message as question, and a Form Input start expects a form object instead.
Or use n8n as the relay
Already run n8n? Import the flow from our n8n page and add an HTTP Request node between the filter and the reply that posts to your flow's Prediction API, with question set to {{ $json.body.data.text.body }} and overrideConfig.sessionId to {{ $json.body.data.user_id || $json.body.data.from }}. After that node, $json holds Flowise's answer, so in the reply set text to {{ $json.text }} and make from and to read the webhook node: {{ $('ZapClaw webhook').item.json.body.account.display_phone_number || $('ZapClaw webhook').item.json.body.account.phone_number_id }} and {{ $('ZapClaw webhook').item.json.body.data.from || $('ZapClaw webhook').item.json.body.data.user_id }}.
Calling ZapClaw from inside Flowise
Flowise can call ZapClaw's API on its own too: the HTTP node of an agentflow, or a Custom Tool the agent chooses to use, with an X-API-Key header. For example, a tool that alerts a salesperson on WhatsApp when a customer asks for a quote. Inside a Custom Tool, $flow.sessionId holds the customer, because the relay passes it as the session, and a Flowise variable read through $vars can hold your ZapClaw key. The call itself, as a curl command:
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 is your connected number, which the webhook brings in account.display_phone_number, and to is the person you write to. A sent message answers 201. Free text works within 24 hours of that person's last message to your number; outside that window Meta accepts only an approved template, through POST /api/v1/send/template.
What reaches the relay
Each message comes as a message.received event: the text in data.text.body, the sender in data.from (or data.user_id for a contact who shows only a username), the contact's name in data.contact_name and your number in 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"
}
}
The relay passes on only incoming text messages: the dashboard's test event and every other event get a 200 and nothing more. A voice note or an image carries a media_url you download with your API key, if you want to hand it to Flowise later. Every event and field is in the docs.
What it costs
- Free: 500 messages a month and 1 number, with no card and no end date. At the limit, sending pauses and new messages are held until you subscribe.
- Business: US$ 29 per month, with 20,000 messages included and unlimited numbers.
- Agency: US$ 49 per month for agencies, with 3 clients and 60,000 messages included and unlimited numbers.
Meta bills its WhatsApp message fees to you directly, with no ZapClaw markup. Every plan and price.
Who it is for
Teams that built an AI agent, an assistant over their own documents or a support triage flow in Flowise and want it on the WhatsApp number their customers already use. Agencies connect their clients' numbers on the Agency plan, each client isolated from the others. It does not fit bulk broadcasting.
Go further
- Typebot on WhatsApp, when a scripted flow with buttons fits better than an AI agent.
- WhatsApp in n8n, with a flow you import instead of a script.
- A webhook for your own AI, when people keep replying from the app.
- Dify on WhatsApp, if you build your agents in Dify.
- The webhook reference, with every event and field.
Sources
Flowise's documentation checked on 15 October 2026. Features change, so check each source before you build.
- Flowise, Prediction: the endpoint, the
questionfield and one memory persessionId. - Flowise API reference, Prediction: the request fields and the
textof the response. - Flowise, access control for flows: the API key sent as a Bearer token.
- Flowise, Agentflow V2: the Start node inputs and the HTTP node.
- Flowise, Custom Tool:
$flow.sessionIdand$vars. - Flowise source on GitHub: how the
sessionIdof a prediction is read. - ZapClaw: webhooks and signature verification in the docs, and what you need to connect.
Put your Flowise agent on WhatsApp today
Start on the free plan: one number, no card. Move to the Business plan when you need more numbers or more messages.
Start for free Read the webhook docs