n8n Node Reference
Exact field-level reference for the two nodes in the @rmyndharis/n8n-nodes-openwa package (v0.9.1): OpenWA (an action node) and OpenWA Trigger (a webhook trigger node). Use it to look up every resource, operation, field, and event, plus the HMAC signature the trigger verifies.
For installation and a first workflow, see the n8n integration guide. For the underlying HTTP API each operation calls, see the API Reference.
Package overview
| Node | n8n type | Direction | Purpose |
|---|---|---|---|
| OpenWA | openWa | Action | Send messages and manage sessions, chats, contacts, groups, labels, templates, status, channels, keys, and webhooks |
| OpenWA Trigger | openWaTrigger | Trigger | Start a workflow when a subscribed event arrives |
Both nodes use the openWaApi credential and call your OpenWA server's /api endpoints.
Credential: OpenWA API
Both nodes require an OpenWA API credential with two fields.
| Field | Required | Description |
|---|---|---|
| Server URL | Yes | Base URL with no trailing slash and no /api suffix, for example http://localhost:2785 or https://wa.example.com. The node appends /api/... itself. |
| API Key | Yes | Sent as the X-API-Key header on every request. Get it from your OpenWA dashboard. |
The credential test issues an authenticated GET /api/sessions, so an invalid key fails at save time. To create the key, see Authentication.
OpenWA (action node)
Package 0.9.0 extended the action node from four resources to the fifteen below. Select a
Resource, then an Operation; the visible fields change with each operation.
Most operations take a Session Name or ID. It is a dropdown: the node calls GET /api/sessions
with your credential and lists each session as name (id), storing the session's UUID. The stored
value is a plain string, so an expression can supply an id instead of picking one. The same pattern
backs the Chat, Contact, Group, Label, Template, Channel, and Webhook ID
fields, each loading from its own listing endpoint once a session is chosen, and the API Key
field, which is not session-scoped. The session, chat, contact, and group loaders fetch one page of
up to 1000 entries — beyond that, set the field from an expression.
The Observability and API Key resources have no Session ID at all; on System it appears only for Get Session Stats, and on Webhook it is hidden for List All and Get Delivery Failures.
| Resource | Operation | Method + path |
|---|---|---|
| Session | Create | POST /api/sessions |
| Session | Start | POST /api/sessions/{sessionId}/start |
| Session | Stop | POST /api/sessions/{sessionId}/stop |
| Session | Force Kill | POST /api/sessions/{sessionId}/force-kill |
| Session | Delete | DELETE /api/sessions/{sessionId} |
| Session | Get QR | GET /api/sessions/{sessionId}/qr |
| Session | Request Pairing Code | POST /api/sessions/{sessionId}/pairing-code |
| Session | Get Status | GET /api/sessions/{sessionId} |
| Session | List All | GET /api/sessions |
| Session | Get Stats Overview | GET /api/sessions/stats/overview |
| Message | Send Text | POST /api/sessions/{sessionId}/messages/send-text |
| Message | Send Image | POST /api/sessions/{sessionId}/messages/send-image |
| Message | Send Video | POST /api/sessions/{sessionId}/messages/send-video |
| Message | Send Audio | POST /api/sessions/{sessionId}/messages/send-audio |
| Message | Send Document | POST /api/sessions/{sessionId}/messages/send-document |
| Message | Send Sticker | POST /api/sessions/{sessionId}/messages/send-sticker |
| Message | Send Location | POST /api/sessions/{sessionId}/messages/send-location |
| Message | Send Contact | POST /api/sessions/{sessionId}/messages/send-contact |
| Message | Send Poll | POST /api/sessions/{sessionId}/messages/send-poll |
| Message | Send Template | POST /api/sessions/{sessionId}/messages/send-template |
| Message | Send Bulk | POST /api/sessions/{sessionId}/messages/send-bulk |
| Message | Get Batch Status | GET /api/sessions/{sessionId}/messages/batch/{batchId} |
| Message | Cancel Batch | POST /api/sessions/{sessionId}/messages/batch/{batchId}/cancel |
| Message | Reply | POST /api/sessions/{sessionId}/messages/reply |
| Message | React | POST /api/sessions/{sessionId}/messages/react |
| Message | Edit | POST /api/sessions/{sessionId}/messages/edit |
| Message | Delete | POST /api/sessions/{sessionId}/messages/delete |
| Message | Forward | POST /api/sessions/{sessionId}/messages/forward |
| Message | List | GET /api/sessions/{sessionId}/messages |
| Message | Get History | GET /api/sessions/{sessionId}/messages/{chatId}/history |
| Message | Get Reactions | GET /api/sessions/{sessionId}/messages/{chatId}/{messageId}/reactions |
| Contact | Check Exists | GET /api/sessions/{sessionId}/contacts/check/{phoneNumber} |
| Contact | Get Info | GET /api/sessions/{sessionId}/contacts/{contactId} |
| Contact | Get Phone | GET /api/sessions/{sessionId}/contacts/{contactId}/phone |
| Contact | Get Profile Picture | GET /api/sessions/{sessionId}/contacts/{contactId}/profile-picture |
| Contact | Get Profile Pictures | GET /api/sessions/{sessionId}/contacts/profile-pictures?ids= |
| Contact | List | GET /api/sessions/{sessionId}/contacts |
| Contact | Block | POST /api/sessions/{sessionId}/contacts/{contactId}/block |
| Contact | Unblock | DELETE /api/sessions/{sessionId}/contacts/{contactId}/block |
| Chat | List | GET /api/sessions/{sessionId}/chats |
| Chat | Mark Read | POST /api/sessions/{sessionId}/chats/read |
| Chat | Mark Unread | POST /api/sessions/{sessionId}/chats/unread |
| Chat | Delete | POST /api/sessions/{sessionId}/chats/delete |
| Chat | Set State | POST /api/sessions/{sessionId}/chats/typing |
| Group | List | GET /api/sessions/{sessionId}/groups |
| Group | Create | POST /api/sessions/{sessionId}/groups |
| Group | Join | POST /api/sessions/{sessionId}/groups/join |
| Group | Get | GET /api/sessions/{sessionId}/groups/{groupId} |
| Group | Leave | POST /api/sessions/{sessionId}/groups/{groupId}/leave |
| Group | Add Participants | POST /api/sessions/{sessionId}/groups/{groupId}/participants |
| Group | Remove Participants | DELETE /api/sessions/{sessionId}/groups/{groupId}/participants |
| Group | Promote Participants | POST /api/sessions/{sessionId}/groups/{groupId}/participants/promote |
| Group | Demote Participants | POST /api/sessions/{sessionId}/groups/{groupId}/participants/demote |
| Group | Update Subject | PUT /api/sessions/{sessionId}/groups/{groupId}/subject |
| Group | Update Description | PUT /api/sessions/{sessionId}/groups/{groupId}/description |
| Group | Get Settings | GET /api/sessions/{sessionId}/groups/{groupId}/settings |
| Group | Update Settings | PUT /api/sessions/{sessionId}/groups/{groupId}/settings |
| Group | Get Invite Code | GET /api/sessions/{sessionId}/groups/{groupId}/invite-code |
| Group | Revoke Invite Code | POST /api/sessions/{sessionId}/groups/{groupId}/invite-code/revoke |
| Profile | Set Name | PUT /api/sessions/{sessionId}/profile/name |
| Profile | Set Status | PUT /api/sessions/{sessionId}/profile/status |
| Profile | Set Picture | PUT /api/sessions/{sessionId}/profile/picture |
| Label | List | GET /api/sessions/{sessionId}/labels |
| Label | Get | GET /api/sessions/{sessionId}/labels/{labelId} |
| Label | Get for Chat | GET /api/sessions/{sessionId}/labels/chat/{chatId} |
| Label | Add to Chat | POST /api/sessions/{sessionId}/labels/chat/{chatId} |
| Label | Remove From Chat | DELETE /api/sessions/{sessionId}/labels/chat/{chatId}/{labelId} |
| Status | List | GET /api/sessions/{sessionId}/status |
| Status | Get by Contact | GET /api/sessions/{sessionId}/status/{contactId} |
| Status | Get Media | GET /api/sessions/{sessionId}/status/{statusId}/media |
| Status | Delete | DELETE /api/sessions/{sessionId}/status/{statusId} |
| Status | Send Text | POST /api/sessions/{sessionId}/status/send-text |
| Status | Send Image | POST /api/sessions/{sessionId}/status/send-image |
| Status | Send Video | POST /api/sessions/{sessionId}/status/send-video |
| Template | List | GET /api/sessions/{sessionId}/templates |
| Template | Create | POST /api/sessions/{sessionId}/templates |
| Template | Get | GET /api/sessions/{sessionId}/templates/{templateId} |
| Template | Update | PUT /api/sessions/{sessionId}/templates/{templateId} |
| Template | Delete | DELETE /api/sessions/{sessionId}/templates/{templateId} |
| Channel | List | GET /api/sessions/{sessionId}/channels |
| Channel | Get | GET /api/sessions/{sessionId}/channels/{channelId} |
| Channel | Get Messages | GET /api/sessions/{sessionId}/channels/{channelId}/messages |
| Channel | Subscribe | POST /api/sessions/{sessionId}/channels/subscribe |
| Channel | Unsubscribe | DELETE /api/sessions/{sessionId}/channels/{channelId} |
| Call | Reject | POST /api/sessions/{sessionId}/calls/{callId}/reject |
| Observability | Check | GET /api/health |
| Observability | Check Liveness | GET /api/health/live |
| Observability | Check Readiness | GET /api/health/ready |
| System | Get Settings | GET /api/settings |
| System | Get Stats Overview | GET /api/stats/overview |
| System | Get Message Stats | GET /api/stats/messages |
| System | Get Session Stats | GET /api/stats/sessions/{sessionId} |
| System | Get Audit Log | GET /api/audit |
| System | Search | GET /api/search |
| API Key | List | GET /api/auth/api-keys |
| API Key | Create | POST /api/auth/api-keys |
| API Key | Get | GET /api/auth/api-keys/{keyId} |
| API Key | Update | PUT /api/auth/api-keys/{keyId} |
| API Key | Revoke | POST /api/auth/api-keys/{keyId}/revoke |
| API Key | Delete | DELETE /api/auth/api-keys/{keyId} |
| API Key | Validate | POST /api/auth/validate |
| Webhook | Create | POST /api/sessions/{sessionId}/webhooks |
| Webhook | Get | GET /api/sessions/{sessionId}/webhooks/{webhookId} |
| Webhook | List | GET /api/sessions/{sessionId}/webhooks |
| Webhook | Update | PUT /api/sessions/{sessionId}/webhooks/{webhookId} |
| Webhook | Delete | DELETE /api/sessions/{sessionId}/webhooks/{webhookId} |
| Webhook | Test | POST /api/sessions/{sessionId}/webhooks/{webhookId}/test |
| Webhook | List All | GET /api/webhooks |
| Webhook | Get Delivery Failures | GET /api/webhooks/delivery-failures |
Values that land in a URL path — Session ID, Batch ID, Webhook ID, Label ID, Status ID, Template ID,
Call ID, API key ID — are sanitized before use: they cannot be empty and cannot contain .., /, or
\. A value that violates this fails the item with a clear error rather than building a malformed
URL. WhatsApp JIDs (chat, contact, group, channel) legitimately contain @ and ., so they are
checked for emptiness and URL-encoded instead.
Send Catalog and PUT /api/settings were removed from the server in v0.19.0 — both had answered 501 since they shipped. Catalog reads and Send Product are Baileys-only on the server and have no operations here either — call them with n8n's HTTP Request node against a Baileys session if you need them. Settings are environment-derived and read-only at runtime, so System exposes only a read; and /api/metrics
authenticates with its own bearer token rather than the X-API-Key this credential carries.
Presence subscription (POST /api/sessions/{sessionId}/presence/subscribe) also has no operation —
call it with n8n's HTTP Request node if you want presence.update events.
Media source model
Every operation that carries media — Send Image, Send Video, Send Audio, Send Document, Send
Sticker, Profile → Set Picture, and Status → Send Image / Send Video — shares one source model. A
Source field offers Binary Data, URL, and Base64 (default URL), and the remaining fields
follow from it:
| Source | Extra fields | Request fields sent |
|---|---|---|
| Binary Data | Binary Property (default data) | base64 (the buffer encoded) and mimetype, read from the binary metadata |
| URL | (the media URL field) | url |
| Base64 | Base64 Data, MIME Type | base64 and mimetype (the MIME Type field) |
When a binary item carries no MIME type of its own, the node falls back to a per-kind default:
application/octet-stream for images, video, and documents, audio/ogg; codecs=opus for audio,
image/webp for stickers, image/jpeg for profile and status images, and video/mp4 for status
video.
OpenWA rejects base64 media without a mimetype. The Binary Data source fills it in from the
binary metadata and the URL source needs nothing extra, but the Base64 source requires you to
set the MIME Type field.
List fields
Several fields take a list: Mentions, Participants, Recipients, Contact IDs, poll Options, Allowed IPs, and Allowed Sessions. Each is a plain string field rather than a fixed set of rows, so it accepts three shapes: a comma- or newline-separated list typed by hand, a pasted JSON array, or an expression resolving to an array. Blank entries are dropped.
Session resource
Session operations address a session by its UUID. Create, List All, and Get Stats Overview take no Session ID.
| Operation | Fields | Notes |
|---|---|---|
| Create | Session Name, Session Config (JSON) | Session Name is required: 3–50 characters, letters, numbers, and hyphens only. Session Config is an optional JSON object, for example {"autoReconnect":true} — a non-object value fails the item. Returns the new session's UUID. |
| Start | Session Name or ID | Starts the session and connects to WhatsApp. |
| Stop | Session Name or ID | Stops the session and disconnects. |
| Force Kill | Session Name or ID | Force-kills a stuck session's engine. |
| Delete | Session Name or ID | Deletes the session. |
| Get QR | Session Name or ID | Returns the QR code for scanning authentication. |
| Request Pairing Code | Session Name or ID, Phone Number | Phone Number is 6–15 digits in international format (for example 628123456789); the node strips +, spaces, -, and () before validating. Returns an 8-character phone-linking code. |
| Get Status | Session Name or ID | Returns the status of one session. |
| List All | Options: Limit, Offset | Returns every session, paginated. |
| Get Stats Overview | (none) | Overview statistics across all sessions. |
Message resource
The twenty-one message operations share a required Session Name or ID. All of them except Send Bulk, Get Batch Status, Cancel Batch, Forward, and List also require a Chat Name or ID — the batch routes are not addressed to one chat, Forward names a source and a target chat of its own, and List takes an optional chat filter in its options collection.
| Field | Type | Required | Description |
|---|---|---|---|
| Session Name or ID | options | Yes | The session to act through. |
| Chat Name or ID | options | Yes (all except Send Bulk, Get Batch Status, Cancel Batch, Forward, List) | Recipient, for example 628123456789@c.us for a person or ...@g.us for a group. Empty values fail the item. |
The operation-specific fields follow.
Send Text — request body { chatId, text }.
| Field | Type | Required | Maps to |
|---|---|---|---|
| Message | string | Yes | text |
Send Image — the media source model, plus an optional caption. Request
body { chatId } plus the source fields, and caption when set.
| Field | Type | Required | Notes |
|---|---|---|---|
| Image Source | options: Binary Data, URL, Base64 | Yes | Default URL. |
| Binary Property | string | Yes (binary) | Default data. |
| Image URL | string | Yes (url) | Public URL of the image. |
| Base64 Data | string | Yes (base64) | Base64-encoded image bytes. |
| MIME Type | string | Yes (base64) | For example image/png. Default image/jpeg. |
| Caption | string | No | Sent as caption. |
Send Video — same shape as Send Image, with the Video Source field and a video/mp4 default
MIME type.
Send Audio — same source model, plus a voice-note toggle. Request body { chatId } plus the
source fields, and ptt: true when the toggle is on.
| Field | Type | Required | Notes |
|---|---|---|---|
| Audio Source | options: Binary Data, URL, Base64 | Yes | Default URL. |
| Binary Property | string | Yes (binary) | Default data. |
| Audio URL | string | Yes (url) | Public URL of the audio. |
| Base64 Data | string | Yes (base64) | Base64-encoded audio bytes. |
| MIME Type | string | Yes (base64) | Default audio/ogg; codecs=opus. For a plain audio file set its real type (for example audio/mpeg). |
| Send as Voice Note | boolean | No | Default off. When on, the clip is delivered as a true WhatsApp voice note (PTT — the microphone bubble with a waveform) instead of a plain audio file. Requires OGG/Opus audio (audio/ogg; codecs=opus). |
Send Document — same source model, with a filename. Request body { chatId, filename } plus the
source fields, and caption when set.
| Field | Type | Required | Notes |
|---|---|---|---|
| Document Source | options: Binary Data, URL, Base64 | Yes | Default URL. |
| Binary Property | string | Yes (binary) | Default data. |
| Document URL | string | Yes (url) | Public URL of the document. |
| Base64 Data | string | Yes (base64) | Base64-encoded document bytes. |
| MIME Type | string | Yes (base64) | For example application/pdf. Default application/pdf. |
| Filename | string | No | Sent as filename. Default document.pdf. |
| Caption | string | No | Sent as caption when set. |
Send Sticker — same source model. WhatsApp expects a WebP sticker, ideally 512×512.
| Field | Type | Required | Notes |
|---|---|---|---|
| Sticker Source | options: Binary Data, URL, Base64 | Yes | Default URL. |
| Binary Property | string | Yes (binary) | Default data. |
| Sticker URL | string | Yes (url) | Public URL of the sticker (WhatsApp expects a WebP image). |
| Base64 Data | string | Yes (base64) | Base64-encoded sticker bytes. |
| MIME Type | string | Yes (base64) | Default image/webp; WhatsApp requires WebP. |
Send Text, Send Image, Send Video, and Send Document accept an optional Mentions field — a list
of WhatsApp ids to @mention (for example 628123456789@c.us), in any of the shapes described under
List fields. The message text or caption must also contain the matching
@628123456789 token for the mention to render. The field is guarded by operation, so a mentions
value can never ride along on an operation whose DTO would reject it.
Send Location — request body { chatId, latitude, longitude }.
| Field | Type | Required | Maps to |
|---|---|---|---|
| Latitude | number | Yes | latitude |
| Longitude | number | Yes | longitude |
| Location Name | string | No | Sent as description (OpenWA's field for the location label) when set. |
Send Contact — request body { chatId, contactName, contactNumber }.
| Field | Type | Required | Maps to |
|---|---|---|---|
| Contact Name | string | Yes | contactName — display name for the shared contact card. |
| Contact Number | string | Yes | contactNumber — phone number including the country code (it is not auto-prefixed), for example +628123456789. |
Send Poll — request body { chatId, name, options }, plus allowMultipleAnswers when on.
| Field | Type | Required | Notes |
|---|---|---|---|
| Question | string | Yes | Sent as name. Maximum 255 characters. |
| Options | string list | Yes | The answers to vote on. Between 2 and 12 — anything outside that range fails the item. |
| Allow Multiple Answers | boolean | No | Default off. When on, voters may pick several options instead of exactly one. |
Send Template — renders a stored template and sends the result. Request
body { chatId } plus either templateId or templateName, and vars when set.
| Field | Type | Required | Notes |
|---|---|---|---|
| Template Name or ID | options | Yes (or Template Name) | Id of the template to render. When both this and Template Name are set, the id wins. |
| Template Name | string | Yes (or Template Name or ID) | Used only when the id is empty. Providing neither fails the item. |
| Variables (JSON) | json | No | Values substituted into the template's {{placeholder}} tokens, as a JSON object such as {"name":"Alice"}. A non-object value fails the item. |
Send Bulk — sends up to 100 messages as a tracked batch. Request body { messages }, plus
batchId and options when set. No Chat ID — each item carries its own chatId.
| Field | Type | Required | Notes |
|---|---|---|---|
| Messages (JSON) | json | Yes | Array of 1–100 items — an empty array or more than 100 items fails the item. A text item is { "chatId": "628123456789@c.us", "type": "text", "content": { "text": "Hello" } }. A media item nests the media object under the type key (image/video/audio/document) and puts caption alongside it on content: { "chatId": "628123456789@c.us", "type": "image", "content": { "image": { "url": "https://example.com/a.jpg" }, "caption": "Hi" } }. Media uses url or base64 (add mimetype for base64) — there is no binary source in bulk. |
| Batch ID | string | No | Custom batch id; must be unique per session. Leave empty to let the server generate one. |
| Options | collection | No | Left empty, the server applies its own defaults (delay 3000 ms, randomize on, stop-on-error off). |
The Options collection offers:
| Option | Type | Default | Notes |
|---|---|---|---|
| Delay Between Messages (Ms) | number | 3000 | Milliseconds to wait between sends, 1000–60000. |
| Randomize Delay | boolean | on | Adds a random 0–2000 ms on top of the delay. |
| Stop on Error | boolean | off | Aborts the batch on the first failed send. |
Send Bulk returns a batchId immediately and sends in the background. Poll Get Batch Status
until the status is completed, cancelled, or failed, or stop the batch early with Cancel
Batch.
Get Batch Status / Cancel Batch — read a batch's progress or cancel it. Each takes one field:
| Field | Type | Required | Notes |
|---|---|---|---|
| Batch ID | string | Yes | The batch id returned by Send Bulk. |
Reply — request body { chatId, quotedMessageId, text }.
| Field | Type | Required | Notes |
|---|---|---|---|
| Quoted Message ID | string | Yes | Full serialized id of the message to quote (for example true_628123456789@c.us_3EB0…), as returned by send operations or delivered by the Trigger. |
| Message | string | Yes | The reply text, sent as text. |
React — request body { chatId, messageId, emoji }.
| Field | Type | Required | Notes |
|---|---|---|---|
| Message ID | string | Yes | Full serialized id of the target message. |
| Emoji | string | No | The emoji to react with. Leave empty to remove your existing reaction — the empty value is sent deliberately. |
Edit — request body { chatId, messageId, body }.
| Field | Type | Required | Notes |
|---|---|---|---|
| Message ID | string | Yes | Full serialized id of the message to edit. |
| Message | string | Yes | The replacement body, maximum 4096 characters. |
Delete — request body { chatId, messageId, forEveryone }.
| Field | Type | Required | Notes |
|---|---|---|---|
| Message ID | string | Yes | Full serialized id of the message to delete. |
| Delete for Everyone | boolean | No | Default on — revokes the message for everyone. Turn off to remove only your own local copy. |
Forward — request body { fromChatId, toChatId, messageId }. Takes no shared Chat ID.
| Field | Type | Required | Notes |
|---|---|---|---|
| From Chat Name or ID | options | Yes | The chat the message currently lives in. |
| To Chat Name or ID | options | Yes | The chat to forward it to. |
| Message ID | string | Yes | Full serialized id of the message to forward. |
List — reads stored messages. Takes no shared Chat ID; every filter lives in its Options collection and is sent as a query parameter.
| Option | Type | Default | Notes |
|---|---|---|---|
| Chat Name or ID | options | — | Only return messages from this chat. |
| From | string | — | Only return messages from this sender. |
| Limit | number | 50 | Max number of results to return. |
| Offset | number | 0 | Records to skip before collecting the result set. |
Get History — reads a chat's history. Requires a Chat ID; the Options collection offers:
| Option | Type | Default | Notes |
|---|---|---|---|
| Deep | boolean | off | Pull older messages from the device instead of only what the server has stored. |
| Include Media | boolean | off | Include media payloads in the returned messages. |
| Limit | number | 50 | Max number of results to return. |
Get Reactions — reads the reactions on one message.
| Field | Type | Required | Notes |
|---|---|---|---|
| Chat Name or ID | options | Yes | The chat the message lives in. |
| Message ID | string | Yes | Full serialized id of the message. |
Contact resource
Check Exists takes a Phone Number, Get Profile Pictures takes a list of ids, List takes only
pagination, and every other contact operation takes a Contact Name or ID (a WhatsApp JID such as
628123456789@c.us).
| Operation | Field | Type | Required | Notes |
|---|---|---|---|---|
| Check Exists | Phone Number | string | Yes | Digits only, for example 628123456789. The node strips +, spaces, -, and (); a value with any non-digit left over fails the item. |
| Get Info | Contact Name or ID | options | Yes | For example 628123456789@c.us. Empty values fail the item. |
| Get Phone | Contact Name or ID | options | Yes | Resolves the contact's phone number. |
| Get Profile Picture | Contact Name or ID | options | Yes | Returns the contact's profile-photo URL. |
| Get Profile Pictures | Contact IDs | string list | Yes | Pictures for many contacts at once, sent as ?ids=. At most 50 — a longer list fails the item rather than being silently truncated by the server. |
| List | Options: Limit, Offset | collection | No | Returns the session's contacts, paginated. |
| Block | Contact Name or ID | options | Yes | Blocks the contact. |
| Unblock | Contact Name or ID | options | Yes | Unblocks the contact (DELETE on the block endpoint). |
Check Exists returns whatsappId, the engine-canonical chat id. It can differ from the number
you sent (for example an @lid id), so read the recipient id from the response rather than
reconstructing it.
Chat resource
Chat operations act on a conversation rather than the session. Every operation except List posts the target chat in the request body.
| Operation | Fields | Notes |
|---|---|---|
| List | Options: Limit (default 50), Offset (default 0) | Returns the session's chats, paginated. |
| Mark Read | Chat Name or ID | Body { chatId }. |
| Mark Unread | Chat Name or ID | Body { chatId }. |
| Delete | Chat Name or ID | Body { chatId }. A POST, not a DELETE — the server takes the chat id in the body here. |
| Set State | Chat Name or ID, State | Body { chatId, state }. State is Typing, Recording, or Paused (default Typing); Typing and Recording show the indicator in the chat, Paused clears it. |
Group resource
List, Create, and Join are session-level; every other operation takes a Group Name or ID (a JID
such as 120363021234567890@g.us).
| Operation | Fields | Notes |
|---|---|---|
| List | Options: Limit (1–1000), Offset | Left empty, the server applies its own defaults (limit 1000, offset 0). |
| Create | Group Name, Participants | Name is required and capped at 100 characters; Participants is required and capped at 256. Baileys engine only since server v0.16.0 — whatsapp-web.js, the server default, answers 501 Operation not supported by the active engine: createGroup. See Groups. |
| Join | Invite Code | The part after https://chat.whatsapp.com/. A full invite link is accepted and reduced to the code. Maximum 128 characters. |
| Get | Group Name or ID | Group info including participants. |
| Leave | Group Name or ID | Leaves the group. |
| Add / Remove / Promote / Demote Participants | Group Name or ID, Participants | Body { participants }, capped at 256. Remove Participants is a DELETE that carries a JSON body — the API takes the list there rather than in the query string. |
| Update Subject | Group Name or ID, Subject | Required, maximum 100 characters. |
| Update Description | Group Name or ID, Description | Maximum 1024 characters. An empty value is sent as-is and clears the description. |
| Get Settings | Group Name or ID | Reads announce, locked, and the disappearing-message timer. |
| Update Settings | Group Name or ID, Settings | Partial — settings you leave out stay untouched, and at least one is required. |
| Get Invite Code | Group Name or ID | The invite code and link. |
| Revoke Invite Code | Group Name or ID | Revokes the code and generates a new one. |
The Settings collection offers:
| Option | Type | Default | Notes |
|---|---|---|---|
| Announce | boolean | off | Only admins can send messages to the group. |
| Locked | boolean | off | Only admins can edit the group info. |
| Disappearing Messages (Seconds) | number | 604800 | Disappearing-message timer; 0 disables it. Baileys engine only — whatsapp-web.js returns 501. |
Add, Remove, Promote, and Demote report a per-participant outcome in results[], and a partial
refusal does not fail the batch — check results[].success rather than the top-level success.
Profile resource
Changes the session's own WhatsApp profile.
| Operation | Fields | Notes |
|---|---|---|
| Set Name | Name | Required, maximum 25 characters. |
| Set Status | Status | Maximum 139 characters. An empty value is sent as-is and clears the about text. |
| Set Picture | Picture Source, and the matching Binary Property / Picture URL / Base64 Data + MIME Type | The media source model; base64 defaults to image/jpeg. The resolved media fields form the whole request body. |
Label resource
WhatsApp Business labels — the catalogue on the account, and the labels attached to one chat.
| Operation | Fields | Notes |
|---|---|---|
| List | (none) | Every label on the account. |
| Get | Label Name or ID | One label. |
| Get for Chat | Chat Name or ID | The labels attached to a chat. |
| Add to Chat | Chat Name or ID, Label Name or ID | Body { labelId }. |
| Remove From Chat | Chat Name or ID, Label Name or ID | Both ids go in the path. |
Status resource
Reads the Status (Stories) feed and posts new updates.
| Operation | Fields | Notes |
|---|---|---|
| List | (none) | The status feed. |
| Get by Contact | Contact Name or ID | One contact's status updates. |
| Get Media | Status ID, Put Output in Field | Streams the stored image or video bytes. The response is attached as a binary property named by Put Output in Field (default data), not as JSON. |
| Delete | Status ID | Deletes one of your own status updates. |
| Send Text | Text, Background Color, Font, Recipients | Body { text } plus backgroundColor, font, and recipients when set. Text is required, maximum 4096 characters. |
| Send Image | Image Source (+ source fields), Caption, Recipients | The media object nests under image rather than sitting flat on the body. |
| Send Video | Video Source (+ source fields), Caption, Recipients | The media object nests under video. |
| Field | Type | Notes |
|---|---|---|
| Background Color | color | Sent as backgroundColor. Leave empty for the server default. |
| Font | options | Font index from the WhatsApp status font set: Default (0), Font 1, Font 2, Bold (6), Font 7, Font 8, Font 9, Font 10, and Server Default (the node's default), which omits the field entirely. |
| Caption | string | Maximum 1024 characters. |
| Recipients | string list | Who may see this status: at most 256 @c.us or @lid ids, never a group. Required on the Baileys engine; leave empty on whatsapp-web.js to post to all contacts. |
Template resource
Reusable message bodies with {{variable}} placeholders, stored per session and rendered by
Message → Send Template.
| Operation | Fields | Notes |
|---|---|---|
| List | (none) | Every template in the session. |
| Create | Name, Body, Header, Footer | Name (max 100) and Body (max 4096) are required; Header and Footer are optional, max 1024 each. |
| Get | Template Name or ID | One template. |
| Update | Template Name or ID, Update Fields | Partial: the collection offers Body, Footer, Header, and Name, with the same limits. At least one is required. |
| Delete | Template Name or ID | Deletes the template. |
Channel resource
WhatsApp Channels (newsletters) the session follows.
| Operation | Fields | Notes |
|---|---|---|
| List | (none) | Followed channels. |
| Get | Channel Name or ID | One channel. |
| Get Messages | Channel Name or ID, Options: Limit | A channel's messages. |
| Subscribe | Invite Code | The part after https://whatsapp.com/channel/. A full link is accepted and reduced to the code. |
| Unsubscribe | Channel Name or ID | A DELETE on the channel — it unfollows rather than deletes. |
Call resource
| Operation | Fields | Notes |
|---|---|---|
| Reject | Session Name or ID, Call ID | The call id as delivered by the Trigger's call events. Rejection is the only call action the API exposes — pair it with call.received to auto-decline. |
Observability resource
Server health, for alerting from inside a workflow. None of these are scoped to a session, so the resource has no Session ID and no other fields.
| Operation | Notes |
|---|---|
| Check | GET /api/health — the server's health JSON as-is. |
| Check Liveness | The liveness probe. |
| Check Readiness | The readiness probe. This is the one that also probes the database connections, so it reports a server that is running but not yet able to serve. |
System resource
Server-wide reporting. Settings are read-only here on purpose: the server derives them from its
environment; the PUT /api/settings route was removed in v0.19.0 after always answering 501.
| Operation | Fields | Notes |
|---|---|---|
| Get Settings | (none) | The server settings document. ADMIN key. |
| Get Stats Overview | (none) | Overview statistics. |
| Get Message Stats | (none) | Message statistics. |
| Get Session Stats | Session Name or ID | Statistics for one session. |
| Get Audit Log | Filters | The audit log. ADMIN key. |
| Search | Query, Filters | Cross-session message search; q is the only required parameter. |
The Search filters:
| Filter | Type | Notes |
|---|---|---|
| Chat ID | string | Only search within this chat. Deliberately free text, not a dropdown — Search spans every session, so there is no single session whose chats could be listed. |
| Date From / Date To | dateTime | Bounds on the message time. The UI supplies ISO-8601 and the node converts each to the epoch-milliseconds number the API binds; an unparseable value fails the item. |
| Direction | options | Incoming or Outgoing. |
| From | string | Only return messages from this sender. |
| Limit / Offset | number | Pagination, defaults 50 and 0. |
| Session Name or ID | options | Only search within this session. |
| Type | string | Only return messages of this type, for example text or image. |
The Get Audit Log filters:
| Filter | Type | Notes |
|---|---|---|
| Action | string | Only entries for this action. |
| API Key Name or ID | options | Only entries recorded for this key. Sent to the API as apiKeyId. |
| Limit / Offset | number | Pagination, defaults 50 and 0. |
| Session Name or ID | options | Only entries for this session. |
| Severity | string | Only entries of this severity. |
API Key resource
API-key administration. Every operation except Validate needs the credential itself to carry the ADMIN role. Create returns the new key's plaintext exactly once — capture it in the same execution, because it cannot be read back afterwards.
| Operation | Fields | Notes |
|---|---|---|
| List | (none) | Every key. |
| Create | Name, Fields | Name is required; the Fields collection carries the optional restrictions below. |
| Get | API Key Name or ID | One key. The id, not the key itself. |
| Update | API Key Name or ID, Fields | Partial — only the fields you set are changed, and an empty list never clears an existing whitelist. At least one field is required. |
| Revoke | API Key Name or ID | Deactivates the key. |
| Delete | API Key Name or ID | Removes the key. |
| Validate | (none) | Validates the credential this node is already authenticating with. Works with any valid key. |
The Fields collection offers:
| Option | Type | Default | Notes |
|---|---|---|---|
| Name | string | — | A friendly name for the key. |
| Role | options | Viewer | Admin, Operator, or Viewer. |
| Expires At | dateTime | — | When the key stops working. |
| Allowed IPs | string list | — | Restrict the key to these IP addresses. |
| Allowed Sessions | string list | — | Restrict the key to these session ids. |
Webhook resource
Use these to register, update, or inspect a webhook from a workflow. For an event-driven workflow, prefer the Trigger node, which registers and removes its own webhook automatically.
Create — request body { url, events }, plus secret when set.
| Field | Type | Required | Notes |
|---|---|---|---|
| Webhook URL | string | Yes | Destination that receives event deliveries. |
| Events | multiOptions | Yes | One or more events. At least one must be selected. |
| Webhook Secret | string (password) | No | If set, OpenWA signs each delivery with X-OpenWA-Signature (HMAC-SHA256); 16+ characters required since v0.20.0. Sent as secret. |
Update — partial update (PUT): only the fields you set in Update Fields are changed;
everything else keeps its current value.
| Field | Type | Required | Notes |
|---|---|---|---|
| Webhook Name or ID | options | Yes | The webhook to update. The dropdown lists a session's webhooks by delivery URL. |
| Update Fields | collection | No | The changes to apply — see the options below. |
The Update Fields collection offers:
| Option | Type | Notes |
|---|---|---|
| URL | string | New delivery URL. |
| Events | multiOptions | Replaces the full set of subscribed events (not merged). When set, at least one event must be selected. |
| Active | boolean | Whether the webhook is enabled. |
| Retry Count | number | Maximum delivery attempts, 0–5. |
| Secret | string (password) | A non-empty value rotates the HMAC-SHA256 signing secret; an empty value is ignored. To disable signing, recreate the webhook without a secret. |
| Headers (JSON) | json | Custom delivery headers as a flat JSON object of string values, for example {"X-Team":"ops"}. Headers are non-nullable server-side — clear them by sending {}. |
| Filters (JSON) | json | Advanced delivery filters as a JSON object, for example {"conditions":[...]}. Enter null to clear existing filters. |
Get / List / Delete / Test — read, remove, or probe a webhook.
| Operation | Fields | Notes |
|---|---|---|
| Get | Session Name or ID, Webhook Name or ID | One webhook. |
| List | Session Name or ID | The session's webhooks. |
| Delete | Session Name or ID, Webhook Name or ID | Removes it. |
| Test | Session Name or ID, Webhook Name or ID | Sends a test delivery. |
List All and Get Delivery Failures span every session, so neither shows a Session ID field.
| Operation | Options | Notes |
|---|---|---|
| List All | Limit, Offset | Webhooks across all sessions. GET /api/webhooks binds only limit and offset, so no session filter is offered — one there would be accepted by the UI and then ignored by the server. |
| Get Delivery Failures | Limit, Offset, Session Name or ID | Failed deliveries; this route is the one that does accept a session filter. ADMIN key. |
Output and error handling
On success, each input item produces one output item containing the OpenWA JSON response. A DELETE
that answers 204 No Content surfaces as { "success": true } so downstream nodes receive a
readable item instead of an empty one. Status → Get Media is the exception: it returns raw bytes,
which the node attaches as a binary property rather than putting on json.
The node fails the workflow on the first error unless Continue On Fail is enabled, in which case
the failing item's output is { "error": "<message>" } and processing continues. Validation problems
(empty chat id, non-digit phone number, no event selected, malformed session id, a poll outside 2–12
options, an oversized participant list) surface as node errors carrying the offending item's index;
HTTP failures from OpenWA surface as API errors carrying the server's status and message.
OpenWA Trigger (node)
The trigger node registers a webhook with OpenWA when the workflow activates and starts the workflow each time a subscribed event arrives. It has no input; its single output emits one item per delivery.
Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| Session Name or ID | options | Yes | Session to receive events from, chosen from the same dropdown the action node uses. Sanitized like the action node (no empty, .., /, or \). |
| Events | multiOptions | Yes | Events to subscribe to. Default ['message.received']. At least one is required. |
| Webhook Secret | string (password) | No | Shared secret for signature verification. See Signature verification. |
| Deduplicate Deliveries | boolean | No | Default off. Drops a repeated delivery of the same deliveryId, remembering the 500 most recent ids in workflow static data. Best-effort: two deliveries arriving at the same moment can both pass, and a retry whose first run failed is also dropped — enable it only when downstream actions are not idempotent and failed runs are rare. |
The delivery path is scoped to the session (…/webhook/openwa-<sessionId>), so several active
workflows can each run a Trigger on one n8n instance without colliding on a shared path.
Webhook lifecycle
The node manages its own OpenWA webhook across activation and deactivation. It stores the returned webhook id — along with the session it was registered on and a hash of the registration configuration — in workflow static data, and reuses them on later checks.
- On activate, the node compares a hash of the delivery URL, events, secret, and session against
the stored one. A mismatch means the registration is stale: it is deleted from the session it was
registered on and recreated with the current configuration. Otherwise the node confirms the webhook
still exists with
GET /api/sessions/{sessionId}/webhooks/{webhookId}, and creates one withPOST /api/sessions/{sessionId}/webhooksif it does not. - On deactivate, the node issues
DELETE /api/sessions/{sessionId}/webhooks/{webhookId}. A404is treated as already deleted; any other error propagates so activation fails loudly rather than orphaning a registration that would keep delivering.
Changing the secret, the events, or the session takes effect on the next activation — deactivate and reactivate the workflow, and the node re-registers automatically. No manual cleanup on the server is needed.
Events
The Events field offers the same list in both the trigger and the action node's Webhook → Create and
Update operations, mirroring core's own event catalog. Package 0.9.1 offers all twenty-two events
the gateway dispatches.
| Event | Fires when |
|---|---|
message.received | A new message is received. |
message.sent | A message is sent successfully. |
message.ack | A message delivery or read acknowledgement occurs. |
message.failed | A message fails to send. |
message.revoked | A message is deleted for everyone. |
message.edited | A message's text or media is edited. |
message.reaction | A reaction is added to or removed from a message. |
status.received | A contact's Status (Story) is received. |
session.status | Any session status change. |
session.qr | A new QR code is generated. |
session.authenticated | The session is authenticated. |
session.disconnected | The session loses connection. |
session.reconnect_loop | A session is stuck in a reconnect loop — once per 5 consecutive attempts. |
session.restriction | WhatsApp places or lifts a restriction on the account. |
presence.update | A subscribed chat's presence changes. Baileys only, and silent until the chat is subscribed with POST /api/sessions/{sessionId}/presence/subscribe; whatsapp-web.js answers that route with 501. |
group.join | A participant joins a group the session belongs to. |
group.leave | A participant leaves a group the session belongs to. |
group.update | A group's metadata or participant roster changes. |
call.received | An incoming WhatsApp call is detected. Both engines. |
call.accepted | An incoming call is answered. Baileys only. |
call.rejected | An incoming call is declined, including by auto-reject. Baileys only. |
call.missed | An incoming call goes unanswered. Baileys only. |
whatsapp-web.js hooks the call collection's insert and sees no status at all, so it can report the
ring but never how the call ended. A workflow triggered on call.accepted, call.rejected, or
call.missed simply never runs on a whatsapp-web.js session. call.received fires on both engines.
Every event above exists on every server this package supports, so no per-event version floor
discriminates between them any more — the ≥ 0.14.0 package floor covers the whole catalog. See
Compatibility.
Output shape
Each delivery is an envelope. The node passes the parsed JSON body straight through, so $json is
the envelope and the event-specific payload is under data.
| Field | Description |
|---|---|
event | The event name, for example message.received. |
timestamp | ISO 8601 time the event was emitted, for example 2024-01-15T10:30:00Z. |
sessionId | Session the event belongs to. |
idempotencyKey | Stable key for the logical event. |
deliveryId | Per-delivery id. Repeated across retries of the same delivery. |
data | The event payload. Read message fields from here. |
{
"event": "message.received",
"timestamp": "2024-01-15T10:30:00Z",
"sessionId": "default",
"idempotencyKey": "a1b2c3d4-...",
"deliveryId": "e5f6a7b8-...",
"data": {
"id": "3EB0F5A2B4C...",
"chatId": "628123456789@c.us",
"from": "628123456789@c.us",
"body": "Hello!",
"type": "text",
"timestamp": 1705312200
}
}
Reading the output:
- Reference payload fields through
data, for example{{ $json.data.body }}and{{ $json.data.chatId }}. - Read the message identifier from
data.id. Incoming payloads useid, notmessageId. - OpenWA retries failed deliveries with the same
deliveryId. De-duplicate on it if your downstream actions are not idempotent — either with the node's Deduplicate Deliveries toggle or a Remove Duplicates node. - Message
typeis engine-neutral: voice notes arevoice, shared contacts arecontact, and plain chats aretext. - Some payloads carry extra fields under
data:type: "masked"marks a withheld business message, and amessage.revokedevent carriesrevokedId, the id of the revoked message.
If the request body is missing or not an object, the node emits no items for that delivery rather than failing.
Signature verification
When Webhook Secret is set, OpenWA signs each delivery and the node verifies it before running the workflow. The signature scheme:
- OpenWA computes
HMAC-SHA256(secret, rawBody)over the exact bytes it transmits and sends the result asX-OpenWA-Signature: sha256=<hex>. - The node reads the raw request body — it does not re-serialize the parsed JSON, which could reorder keys or change whitespace and reject a valid delivery — then recomputes the expected
sha256=<hex>and compares. - Comparison uses a constant-time check (
timingSafeEqual). A length mismatch is treated as a non-match before the comparison runs. - Verification returns false when either the secret or the signature header is absent. With a secret configured, a delivery whose signature is missing or wrong is rejected with HTTP 401 and produces no workflow run.
- If the running n8n cannot supply the raw body at all, the node logs a warning and rejects the delivery with
401rather than silently re-serializing and dropping valid deliveries at random.
Leave Webhook Secret empty to skip verification and accept unsigned deliveries. For end-to-end webhook setup and the same signature scheme used outside n8n, see Webhooks.
Common errors
| Symptom | Cause | Fix |
|---|---|---|
| Credential test fails on save | API key rejected by GET /api/sessions | Use a valid key from the dashboard; see Authentication. |
Session ID contains invalid characters | Session id has .., /, or \ | Pick the session from the dropdown, or supply its UUID from an expression. |
Chat ID cannot be empty | Message sent with no Chat ID | Provide a chat id like 628123456789@c.us. |
Phone number must contain only digits | Check Exists got non-digit input that survived stripping | Pass digits only, for example 628123456789. |
| Base64 image or document rejected by OpenWA | Missing MIME type on a base64 payload | Set the MIME Type field, or use the Binary Data or URL source. |
400 when creating a webhook | The server does not know one of the selected events | session.restriction, presence.update, call.accepted, call.rejected, and call.missed need OpenWA ≥ 0.14.0. Upgrade the gateway, or deselect the events it does not know. |
404 on one operation while the rest work | The route postdates the server | The action node's routes top out at v0.10.9; see Compatibility. |
| A call-outcome trigger never runs | The session runs whatsapp-web.js | call.accepted, call.rejected, and call.missed are Baileys-only. Use call.received, which fires on both engines. |
| Trigger fires once and then goes quiet | The webhook was registered against n8n's test URL, which stops after one delivery | Activate the workflow so the trigger registers its production URL. |
| Trigger subscribed to a group event never runs | The session isn't a member of any group, or no group activity has occurred | Confirm the session has joined a group and that group activity (joins/leaves/roster changes) is happening. group.join, group.leave, and group.update are emitted by both engines. |
401 Unauthorized on every delivery | Signature mismatch between server and node secrets | Use the same Webhook Secret on both sides; reactivate the workflow after changing it. |
403 on an operation that used to work | The credential's role is too low | Writes need an OPERATOR key; the API Key resource, System → Get Settings, System → Get Audit Log, and Webhook → Get Delivery Failures need an ADMIN key. |
Compatibility
This package targets a self-hosted OpenWA server ≥ 0.14.0, verified against v0.23.1. Two things set that floor independently.
The routes the action node calls top out at v0.10.9: the profile writes, groups/join,
groups/{id}/settings, messages/edit, and calls/{id}/reject arrived in v0.10.3, the bulk contact
profile-pictures route in v0.10.1, and the stored-status media download in v0.10.9. Against an older
server those specific operations answer 404 and the rest keep working.
The event catalog is what actually sets 0.14.0. session.restriction, presence.update,
call.accepted, call.rejected, and call.missed do not exist in core before v0.14.0 — a v0.10.9
server knows 17 events, not 22 — and the server validates a webhook registration against its own
event list, so a Trigger subscribing to any of the five is refused at registration rather than
degrading quietly. That is a harder failure than a 404 on one operation, which is why it, and not
the routes, is the supported floor.
Next steps
- n8n integration guide — install the package and build your first workflow.
- Webhooks — the event payloads and signing scheme behind the Trigger node.
- API Reference — the HTTP endpoints each operation calls.
- Sending messages — payload details for the message operations.