n8n WhatsApp Business API integration: no-code automation through WACO
n8n, Make, and Zapier need just two things to talk to WhatsApp through WACO — and both come with every plan: a webhook that pushes every incoming message into your flow, and an API to reply or send templates. No custom node to install; the built-in Webhook and HTTP Request nodes are enough. This guide uses n8n as the example; the same pattern applies to Make and Zapier.
What you need
- A WACO account with a connected number and an API key (
waco_…) from the Developer page — see the API quickstart. - The webhook secret (
whsec_…) shown when you save a webhook URL on the same page — see the webhook guide. - n8n Cloud, or a self-hosted n8n reachable over HTTPS.
Step 1 — Import the example workflow
Copy the JSON below, then in n8n choose Workflows → Import from clipboard. It has three nodes: Webhook receives WACO events, Code verifies the signature and filters, HTTP Request replies through the WACO API. The example logic: when a customer mentions "price", send a link to the price list.
{
"name": "WACO → n8n: auto-reply",
"nodes": [
{ "id": "1", "name": "WACO Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [0, 0],
"parameters": { "httpMethod": "POST", "path": "waco", "responseMode": "onReceived", "options": { "rawBody": true } } },
{ "id": "2", "name": "Verify & filter", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [260, 0],
"parameters": { "jsCode": "// 1) Verify the WACO signature over the RAW body (not the parsed JSON)\nconst crypto = require('crypto');\nconst SECRET = 'whsec_REPLACE_WITH_YOUR_SECRET';\nconst raw = await this.helpers.getBinaryDataBuffer(0, 'data');\nconst received = String($input.first().json.headers['x-waco-signature'] || '');\nconst computed = 'sha256=' + crypto.createHmac('sha256', SECRET).update(raw).digest('hex');\nif (received.length !== computed.length || !crypto.timingSafeEqual(Buffer.from(received), Buffer.from(computed))) return [];\nconst ev = JSON.parse(raw.toString('utf8'));\n// 2) Incoming messages only (status & echo events are ignored in this example)\nif (ev.event !== 'message.received') return [];\n// 3) De-duplicate: a WACO webhook can be delivered twice -> remember processed ids\nconst st = $getWorkflowStaticData('global');\nst.seen = st.seen || {};\nconst now = Date.now();\nfor (const k of Object.keys(st.seen)) if (now - st.seen[k] > 86400000) delete st.seen[k];\nif (st.seen[ev.pesan.id]) return [];\nst.seen[ev.pesan.id] = now;\n// 4) Your logic: example auto-reply when a customer asks for prices\nconst text = String(ev.pesan.teks || '').toLowerCase();\nif (!/price|harga|how much/.test(text)) return [];\nreturn [{ json: { dari: ev.dari, nama: ev.nama, balasan: 'Hi ' + (ev.nama || '') + ', here is our price list: https://example.com/prices' } }];" } },
{ "id": "3", "name": "Reply via WACO", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [520, 0],
"parameters": { "method": "POST", "url": "https://waco.id/api/v1/balas",
"authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth",
"sendBody": true, "specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ nomor: $json.dari, teks: $json.balasan }) }}",
"options": {} } }
],
"connections": {
"WACO Webhook": { "main": [[{ "node": "Verify & filter", "type": "main", "index": 0 }]] },
"Verify & filter": { "main": [[{ "node": "Reply via WACO", "type": "main", "index": 0 }]] }
}
}
Step 2 — Fill in the secret & API key
- Open the Verify & filter node and replace
whsec_REPLACE_WITH_YOUR_SECRETwith your webhook secret. - Open the Reply via WACO node → Credential → create a new Header Auth:
Name
Authorization, ValueBearer waco_YOUR_KEY. - Activate the workflow, then copy the Production URL from the Webhook node (it ends in
/webhook/waco).
Step 3 — Register the URL with WACO
On the Developer page, paste the Production URL as your webhook URL and save. Send a chat to your WhatsApp number containing the word "price" — within a second or two the reply from n8n arrives, and the run shows up under Executions in n8n.
Three things that keep this flow safe to run forever
- Signature verification. Every WACO POST carries
X-WACO-Signature: sha256=…, an HMAC-SHA256 over the raw body. The Code node recomputes it from the raw body (the Raw Body option on the Webhook node) and drops anything that does not match — skip this and anyone who knows your URL can trigger the flow. - De-duplication. A WACO webhook can be delivered twice (dual delivery for reliability).
The Code node remembers processed
pesan.idvalues for 24 hours in workflow static data, so the bot never replies twice. - Fast acknowledgement. The Webhook node is set to Respond: Immediately, so WACO gets a 200 before your logic runs; redelivery only happens if n8n truly did not answer.
On self-hosted n8n, allow the Code node to use the crypto module by setting the environment
variable NODE_FUNCTION_ALLOW_BUILTIN=crypto. On n8n Cloud it is already available.
Common variations
- Log to Google Sheets / Notion / Airtable: replace the HTTP Request node with the
destination node; the fields are
ev.dari,ev.nama,ev.pesan.teks,ev.waktu. - Send a template from another system (new order, invoice due): no webhook needed — just an
HTTP Request node to
POST https://waco.id/api/v1/kirimwith body{"nomor":"628…","template":"template_name","isi":["…"]}. Templates are required for the first message outside the 24-hour window;/balasis only for replying to a still-open chat. - Track delivery: the
message.statusevent carries apesan_idequal to themessage_idreturned by/kirim— match them to know delivered/read/failed per message. - Incoming media: for images/documents, download the file via
GET /api/v1/media/{pesan.data.id}with the same API key.
Make and Zapier
Identical pattern: Webhooks → Custom webhook (Make) or Webhooks by Zapier → Catch Hook
receives the event; HTTP → Make a request or Webhooks by Zapier → POST calls the WACO API with
Authorization: Bearer waco_…. Signature verification uses each platform's code module (Make:
Custom JS, Zapier: Code by Zapier) with the same HMAC logic as above.
Frequently asked
Does this need a special plan? No. The API and webhooks are included in every WACO plan; message fees are paid to Meta as usual.
Can it run alongside the team inbox? Yes. Webhooks run side by side: your team keeps replying from the inbox while n8n receives a copy of the same events.
Is there an official WACO node in the n8n catalogue? Not yet — and it is not needed; HTTP Request covers the whole API. The full spec is in the OpenAPI reference.