n8n is the piece most WhatsApp integrations are missing. Not because the API is hard, but because the interesting part is rarely the message itself. It is the CRM lookup before it, the spreadsheet row after it, and the conditional in the middle that decides whether a human needs to get involved.
Writing that glue by hand takes a week. Dragging it onto a canvas takes an afternoon.
What you need first
An n8n instance, either cloud or self-hosted. A WhatsApp API account with an active session and an API key. That is genuinely it.
If you are self-hosting, the minimum viable Docker setup is:
yaml
Two things people learn the hard way. Set WEBHOOK_URL to your real public address or every webhook node will generate URLs pointing at nothing. And back up N8N_ENCRYPTION_KEY separately from the database, because if you move the volume without it, every stored credential becomes unrecoverable.
Put it behind a reverse proxy with TLS. Never expose port 5678 directly. 2 vCPU and 2GB RAM is the realistic production floor.
The two ways to connect to WhatsApp
n8n ships a native WhatsApp Business Cloud node. If you are on Meta's official platform with an approved WABA, use it. It handles authentication and gives you a trigger node out of the box.
For everything else, and that includes any session-based provider, you use two generic nodes: HTTP Request to send, Webhook to receive. That sounds like a downgrade. It is not. Generic nodes work against any API, never lag behind a vendor's feature releases, and are not subject to the template restrictions the official platform imposes. If Meta's onboarding is what pushed you toward automation tooling in the first place, the routes around it are worth understanding before you build.
Setting up the credential once
Do not paste your API key into individual nodes. Create a credential and reuse it.
Go to Credentials, then Add credential, and choose Header Auth. Set the name to Authorization and the value to Bearer wahttp_live_your_key_here. Save it as something like "WhatsApp API."
Every HTTP Request node can now select that credential. Rotating the key later means editing one record instead of hunting through fourteen workflows.
Scope the key while you are here. A workflow that only sends messages does not need an admin key, and a viewer or operator key limits the blast radius if the instance is ever compromised.
Workflow one: send a message from anything
The building block everything else sits on.
Add an HTTP Request node and configure it:
- Method:
POST - URL:
https://app.wahttp.com/api/sessions/{{ $json.sessionId }}/messages - Authentication: Predefined credential type, then your Header Auth credential
- Send Body: on, Body Content Type: JSON
json
The {{ }} syntax pulls data from whatever ran before. Put a Google Sheets node, a Postgres query, or a Typeform trigger upstream, and the fields flow straight through.
Now put a trigger in front of it, and you have an automation. A schedule trigger plus a database query gives you a daily digest. A Stripe webhook gives you payment confirmations. A form submission gives you instant lead follow-up.
Workflow two: react to incoming messages
This is where n8n earns its place.
Add a Webhook node. Set the method to POST. n8n generates two URLs, a test one and a production one. The test URL only listens while you have the canvas open with Listen for Test Event running. The production URL only works once the workflow is toggled Active. Roughly half of all "my webhook isn't firing" problems are one of those two things.
Register the production URL with your WhatsApp provider as the webhook endpoint, subscribed to message.received.
Add a Switch node to branch on message type, so images do not fall through logic written for text.
Add an IF node to filter out group messages. Check {{ $json.data.isGroup }} and route true to a No Operation node. An autoresponder that replies to every message in a group chat is the fastest way to get muted by 200 people at once.
Do the actual work. Look the sender up in your CRM. Send the body to an AI node for classification. Check a knowledge base.
Reply with the HTTP Request node from workflow one, using {{ $json.data.from }} as the recipient.
A practical detail: n8n's webhook node accepts a maximum 16MB payload by default, adjustable on self-hosted instances with N8N_PAYLOAD_SIZE_MAX. Media-heavy inbound traffic can hit this.
Another: enable authentication on the webhook node itself. Header auth is available in the node options, and without it your n8n endpoint accepts POSTs from anyone who finds the URL.
Workflow three: support triage with a human in the loop
The pattern that gets used long after the novelty wears off.
An incoming message arrives on the webhook. An AI node classifies it into a category and an urgency level. A Switch node routes on the result. Simple FAQ questions get an automatic reply from a template. Anything urgent posts to a Slack channel and creates a ticket. Everything else lands in a queue for a human to read.
The important structural choice is that automated replies only go out for the categories you explicitly whitelisted. Everything else routes to a person. Teams that invert this, auto-replying by default and escalating exceptions, generate significantly more angry customers.
Where automations go wrong
Sending faster than you should. An n8n loop over 500 spreadsheet rows fires 500 HTTP requests as fast as the instance can manage. That send pattern is exactly what WhatsApp's behavioural detection looks for, and it is the most common way a working automation kills a number. Use a Wait node between iterations, batch with the Loop Over Items node, and rely on your provider's queue rather than sending directly.
Building without idempotency. Webhook retries mean the same event can arrive twice. If your workflow creates an order or sends a confirmation, check whether you already handled that message ID before acting.
Ignoring error handling. Set an error workflow in the workflow settings. Without one, a failed execution is silent unless someone opens the executions list.
Treating message content as trusted. Anyone can message your number, and that text goes into your workflow. If it reaches an AI node with tool access, treat it as untrusted input rather than instructions.
Automating outreach nobody asked for. No workflow design saves a number sending cold messages at machine pace. Automate conversations people started, or ones they opted into.
Debugging a workflow that will not behave
n8n's executions list is the first place to look and the last place most people think of. Open it, find the failed run, and click into the node that errored. You get the exact input it received and the exact output it produced, which resolves most problems in under a minute.
A few patterns recur.
The expression returns nothing. {{ $json.phone }} evaluates to empty because the field is nested deeper than you think. Webhook payloads usually wrap everything in body, so the real path is often {{ $json.body.data.from }}. Click the input panel on the node and copy the path from the actual data rather than guessing.
The HTTP Request node returns 401. The credential is attached but the header name is wrong. It must be Authorization with a value of Bearer followed by a space and the key. A missing space is the single most common version of this.
The workflow runs but nothing sends. Check whether you are looking at a test execution. Test runs from the canvas use the test webhook URL and do not represent what happens when the workflow is live.
Everything works once, then stops. Look at whether the session is still connected on the WhatsApp side. n8n will happily keep firing requests at a disconnected session and log successful HTTP calls that never become messages.
Items multiply unexpectedly. n8n runs a node once per input item. If a node upstream returns 40 rows, the node after it executes 40 times. That is usually what you want for a broadcast and never what you want for a Slack alert, so add an Aggregate node when you need one output instead of many.
Cloud n8n or self-hosted
Self-hosting means no per-execution limits and message content that never leaves infrastructure you control, which matters for GDPR if you are processing customer conversations. The cost is that you own the uptime, the backups and the upgrades.
n8n Cloud removes all of that at a monthly fee with execution caps. For a support triage workflow firing on every inbound message, watch that cap, since conversational traffic produces far more executions than people estimate.
Either way, pairing n8n with a flat-rate WhatsApp API keeps the whole stack predictable. An automation's whole purpose is to run without supervision, and per-message billing on an unsupervised loop is an uncomfortable combination. The cost breakdown has the numbers if you want to compare properly.
If you would rather not build the plumbing at all, Make and Zapier connect the same way, and the integrations overview covers what is available for each.
Common Questions Asked by Users
Does n8n have a WhatsApp integration? Yes. There is a native WhatsApp Business Cloud node for Meta's official API, and any other WhatsApp API connects through the generic HTTP Request and Webhook nodes.
Can I send WhatsApp messages from n8n without the official API? Yes. A session-based API connects via the HTTP Request node with a Header Auth credential, and needs no Meta approval or business verification.
How do I trigger an n8n workflow from an incoming WhatsApp message? Add a Webhook node, activate the workflow to get the production URL, and register that URL with your WhatsApp provider subscribed to the incoming message event.
Why is my n8n webhook not receiving anything? Usually the workflow is not activated, so only the test URL is live, or WEBHOOK_URL is misconfigured on a self-hosted instance and the generated URL points somewhere unreachable.
Can I self-host the whole thing? Yes. n8n runs in Docker on a modest VPS, and some WhatsApp API providers offer self-hosted deployments too, which keeps message content entirely within your own infrastructure.
Will an n8n automation get my number banned? It can, if it sends fast or contacts people who did not opt in. Add Wait nodes, keep volume human-paced, and let your provider's queue handle throttling rather than firing requests in a tight loop.
Do I need to know how to code? No. Expressions like {{ $json.field }} are the closest it gets, and the JSON body in the HTTP Request node is fill-in-the-blank.