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.