Build WhatsApp workflows with n8n
Connect OpenWA to n8n, an open-source workflow automation tool, using the official community nodes. By the end of this page you'll have the nodes installed, an OpenWA credential configured, and a working auto-reply workflow: an incoming WhatsApp message triggers a reply.
- npm package:
@rmyndharis/n8n-nodes-openwa(current version0.7.2) - Repository: rmyndharis/OpenWA-n8n
The package ships two nodes:
| Node | Type | What it does |
|---|---|---|
| OpenWA | Action | Calls OpenWA operations as a workflow step — send messages, check contacts, manage sessions and webhooks |
| OpenWA Trigger | Trigger | Starts a workflow when a WhatsApp event arrives — incoming messages, session and group events |
- A running OpenWA gateway that n8n can reach over the network. See Installation.
- A connected session that has finished pairing. See Your first session.
- An API key from the dashboard. See the Authentication guide.
- An n8n instance where you can install community nodes (self-hosted).
- An OpenWA server ≥ 0.4.0. The nodes are verified against v0.8.13.
Install the nodes
Install the community package on a self-hosted n8n instance.
From the n8n UI
- In n8n, open Settings → Community Nodes.
- Click Install.
- Enter
@rmyndharis/n8n-nodes-openwaand accept the community-node risk prompt. - Restart n8n.
Manual install
cd ~/.n8n/nodes
npm install @rmyndharis/n8n-nodes-openwa
Restart n8n after installing. Both nodes then appear in the node picker when you search for "OpenWA".
n8n Cloud only allows community nodes verified by n8n, and this package is not currently one of them. Use a self-hosted instance to run it.
Configure the OpenWA API credential
Both nodes share one credential. Create it once and reuse it across every OpenWA node in your instance.
| Field | Required | Default | Description |
|---|---|---|---|
| Server URL | Yes | http://localhost:2785 | Your OpenWA server URL, without a trailing slash or /api. Use HTTPS in production (for example https://wa.yourserver.com). |
| API Key | Yes | — | The API key from your OpenWA dashboard. The node sends it as the X-API-Key header on every request. |
When you click Test in the credential dialog, n8n makes an authenticated
GET /api/sessions request to your server. The test passes only if the key is valid, so a
wrong key or unreachable server fails immediately.
Create a dedicated API key for n8n rather than reusing an admin key, so you can revoke it without disrupting other clients. See the Authentication guide.
Send and webhook operations need an OPERATOR-role key (the default role). A read-only
VIEWER key passes the credential test but fails send and webhook calls with 403. The
VIEWER-safe operations are Session → Get Status / List All and Contact → Check Exists /
Get Info.
You can confirm the same credential by hand with curl before building a workflow. This hits
the same send endpoint the Send Text operation uses, so a success here confirms both the
credential and a connected session:
curl -X POST http://localhost:2785/api/sessions/default/messages/send-text \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chatId": "628123456789@c.us",
"text": "Hello from OpenWA!"
}'
On success the gateway returns 201 Created with the message id and timestamp:
{
"messageId": "true_628123456789@c.us_3EB0123456789",
"timestamp": 1706868000
}
A 404 means the session id doesn't exist; a 400 means the session isn't connected or the
body is invalid. Replace default with your session id and 628123456789@c.us with a real
recipient chat id.
The OpenWA node (actions)
The action node maps a Resource and Operation to one OpenWA call. It exposes four resources and the operations below. For field-level detail of every operation, see the n8n Node Reference.
| Resource | Operation | Description |
|---|---|---|
| Session | Create | Create a new session (returns its UUID) |
| Session | Start | Start a session and connect to WhatsApp |
| Session | Stop | Stop a session and disconnect |
| Session | Force Kill | Force-kill a stuck session's engine |
| Session | Delete | Delete a session |
| Session | Get QR | Get the QR code for scanning authentication |
| Session | Request Pairing Code | Get an 8-char phone linking code |
| Session | Get Status | Get the status of a session |
| Session | List All | List all sessions |
| Message | Send Text | Send a text message |
| Message | Send Image | Send an image (binary, URL, or Base64) |
| Message | Send Video | Send a video (binary, URL, or Base64) |
| Message | Send Audio | Send an audio file or a voice note (PTT) |
| Message | Send Document | Send a document or file |
| Message | Send Sticker | Send a sticker (WebP) |
| Message | Send Location | Send a location pin |
| Message | Send Contact | Send a contact card (vCard) |
| Message | Send Bulk | Send to many recipients as a tracked batch |
| Message | Get Batch Status | Read the progress of a bulk batch |
| Message | Cancel Batch | Cancel a bulk batch |
| Message | Reply | Reply to a message, quoting it |
| Message | React | Add or remove an emoji reaction |
| Message | Delete | Delete a message |
| Contact | Check Exists | Check whether a number is on WhatsApp |
| Contact | Get Info | Get contact information |
| Contact | Get Phone | Resolve a contact's phone number |
| Contact | Get Profile Picture | Get a contact's profile picture |
| Contact | Block | Block a contact |
| Contact | Unblock | Unblock a contact |
| Webhook | Create | Register a webhook (optional signing secret) |
| Webhook | Update | Update an existing webhook |
| Webhook | Delete | Remove a webhook |
| Webhook | Test | Send a test delivery to a webhook |
See the n8n Node Reference for the full field-level detail
of every operation. For any OpenWA endpoint not covered by the node — group management and
other endpoints outside its four resources — use n8n's generic HTTP Request node with the
same X-API-Key credential. The complete endpoint list is in the API reference.
When you send an image or document from a Base64 source, also set the MIME Type field
(for example image/png or application/pdf) — OpenWA requires it for base64 payloads. The
Binary source fills this in from the binary metadata, and the URL source needs
nothing extra.
The OpenWA Trigger node (events)
The trigger node starts a workflow when a WhatsApp event occurs. When you activate the workflow, the node registers a webhook in OpenWA pointing at n8n's webhook URL; when you deactivate it, that webhook is removed. You never manage the webhook by hand.
Select one or more events to subscribe to:
| Event | Description |
|---|---|
message.received | New incoming message |
message.sent | Message successfully sent |
message.ack | Message delivery or read acknowledgement |
message.failed | Message failed to send |
message.revoked | Message deleted for everyone |
message.reaction | Reaction added to or removed from a message (server ≥ 0.7.2) |
session.status | Session status changed |
session.qr | QR code generated for scanning |
session.authenticated | Session authenticated |
session.disconnected | Session lost connection |
Selecting the message.reaction event against an older server returns a 400 when the
webhook is created.
The group.join, group.leave, and group.update events are accepted when you subscribe but
are not yet emitted by OpenWA. Don't depend on them until a release notes them as live.
Signature verification
The trigger has an optional Webhook Secret. When set, the secret is registered with
OpenWA, and OpenWA signs every delivery with HMAC-SHA256 in the
X-OpenWA-Signature: sha256=<hex> header. The node verifies each delivery against the raw
request body and rejects any that fail with HTTP 401. Leave it empty to skip verification.
Changing or clearing the secret takes effect on the next activation. Deactivate and reactivate the workflow to re-register it.
Trigger payload
The trigger emits one item per event. The event is wrapped in an envelope; the actual event
data lives under data:
{
"event": "message.received",
"timestamp": "2024-01-15T10:30:00Z",
"sessionId": "default",
"idempotencyKey": "a1b2c3d4e5f6",
"deliveryId": "9f8e7d6c5b4a",
"data": {
"id": "3EB0F5A2B4C1",
"chatId": "628123456789@c.us",
"from": "628123456789@c.us",
"body": "Hello!",
"type": "text",
"timestamp": 1705312200
}
}
Reference fields in downstream nodes with n8n expressions — for example {{$json.data.body}}
for the message text and {{$json.data.chatId}} for the chat to reply to.
A few notes from the payload contract:
- Read message fields from
data(data.body,data.chatId), and the message identifier fromdata.id— incoming payloads useid, notmessageId. typeis engine-neutral: voice notes arevoice, shared contacts arecontact, and plain chats aretext.- Check Exists returns
whatsappId, the engine-canonical chat id, which may differ from the number you sent (for example an@lidid).
OpenWA retries failed deliveries with the same deliveryId. If your downstream actions aren't
idempotent, add a dedup step (a Remove Duplicates node or an IF check) keyed on
deliveryId so a retried delivery isn't processed twice.
Example: auto-reply to incoming messages
This is the smallest useful workflow — trigger on an incoming message, check the text, and reply.
- OpenWA Trigger — select your OpenWA API credential and subscribe to
message.received. - IF — condition:
{{$json.data.body}}containshello(case-insensitive). - OpenWA → Send Text — on the true branch, configure:
- Session ID:
default - Chat ID:
{{$json.data.chatId}} - Message:
Hi! Thanks for reaching out — how can we help?
- Session ID:
- Activate the workflow. The trigger registers its webhook with OpenWA automatically.
Send "hello" to your WhatsApp number, and you'll get the reply within seconds.
From here, swap the IF for a router to branch on keywords, append each new lead to Google
Sheets before replying, or post a Slack alert when session.disconnected fires. The trigger
gives you the inbound event; the action node sends the response.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Credential Test fails | Server unreachable, wrong key, or a trailing slash in Server URL | Confirm the server is running and reachable from n8n, the key is correct, and Server URL has no trailing / or /api. |
| Trigger never fires | OpenWA can't reach n8n's webhook URL | Confirm n8n's webhook URL is reachable from the gateway (check firewalls and proxies) and that the session is connected. |
Webhook creation fails with 400 | message.reaction selected against a server older than 0.7.2 | Upgrade OpenWA to ≥ 0.7.2, or remove that event from the subscription. |
Send Text returns 400 | Session not connected, or invalid chat id | Confirm the session status is ready and the chat id format is correct (628123456789@c.us). |
Send Text returns 404 | Session id doesn't exist | Set the node's Session ID to a real session. |
| Message sends but never arrives | Recipient isn't on WhatsApp | Use the Check Exists operation before sending to unverified numbers. |
Next steps
- n8n Node Reference — every operation and field in detail
- Webhooks — the event model behind the trigger node
- Sending messages — every send operation and its fields
- API reference — every endpoint the action node can call
- n8n Community Nodes documentation — installing and managing community nodes