Skip to main content
Version: v0.23.5

n8n Node Reference

Exact field-level reference for the two nodes in the @rmyndharis/n8n-nodes-openwa package (v1.0.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.

List results emit one item per row on node version 2

Nineteen operations answer a bare JSON array. On node version 2, the version a newly added node gets, each row becomes its own item, so {{ $json.id }} reads a row directly and an empty list emits zero items, which stops the next node unless Always Output Data is on. A node saved on any release up to and including 1.0.0 stays on node version 1 across the package upgrade and keeps the whole array on a single item, so an existing {{ $json[0].id }} expression still works there. A node added while on 1.0.0 carries version 1 too, so it returns to the whole array on upgrade; delete and re-add it to move it to version 2.

See Output and error handling for the affected operations, the ones that keep their shape on both versions, and what each workflow pattern becomes on version 2.

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​

Noden8n typeDirectionPurpose
OpenWAopenWaActionSend messages and manage sessions, chats, contacts, groups, labels, templates, status, channels, keys, and webhooks
OpenWA TriggeropenWaTriggerTriggerStart 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.

FieldRequiredDescription
Server URLYesBase 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 KeyYesSent 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 1.0.1 covers the nineteen resources 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.

ResourceOperationMethod + path
SessionCreatePOST /api/sessions
SessionStartPOST /api/sessions/{sessionId}/start
SessionStopPOST /api/sessions/{sessionId}/stop
SessionForce KillPOST /api/sessions/{sessionId}/force-kill
SessionDeleteDELETE /api/sessions/{sessionId}
SessionGet QRGET /api/sessions/{sessionId}/qr
SessionRequest Pairing CodePOST /api/sessions/{sessionId}/pairing-code
SessionGet StatusGET /api/sessions/{sessionId}
SessionList AllGET /api/sessions
SessionGet Stats OverviewGET /api/sessions/stats/overview
SessionLog OutPOST /api/sessions/{sessionId}/logout
SessionGet ConfigGET /api/sessions/{sessionId}/config
SessionUpdate ConfigPATCH /api/sessions/{sessionId}/config
SessionGet ProxyGET /api/sessions/{sessionId}/proxy
SessionUpdate ProxyPATCH /api/sessions/{sessionId}/proxy
MessageSend TextPOST /api/sessions/{sessionId}/messages/send-text
MessageSend ImagePOST /api/sessions/{sessionId}/messages/send-image
MessageSend VideoPOST /api/sessions/{sessionId}/messages/send-video
MessageSend AudioPOST /api/sessions/{sessionId}/messages/send-audio
MessageSend DocumentPOST /api/sessions/{sessionId}/messages/send-document
MessageSend StickerPOST /api/sessions/{sessionId}/messages/send-sticker
MessageSend LocationPOST /api/sessions/{sessionId}/messages/send-location
MessageSend ContactPOST /api/sessions/{sessionId}/messages/send-contact
MessageSend PollPOST /api/sessions/{sessionId}/messages/send-poll
MessageSend TemplatePOST /api/sessions/{sessionId}/messages/send-template
MessageSend BulkPOST /api/sessions/{sessionId}/messages/send-bulk
MessageGet Batch StatusGET /api/sessions/{sessionId}/messages/batch/{batchId}
MessageCancel BatchPOST /api/sessions/{sessionId}/messages/batch/{batchId}/cancel
MessageReplyPOST /api/sessions/{sessionId}/messages/reply
MessageReactPOST /api/sessions/{sessionId}/messages/react
MessageEditPOST /api/sessions/{sessionId}/messages/edit
MessageDeletePOST /api/sessions/{sessionId}/messages/delete
MessageForwardPOST /api/sessions/{sessionId}/messages/forward
MessageListGET /api/sessions/{sessionId}/messages
MessageGet HistoryGET /api/sessions/{sessionId}/messages/{chatId}/history
MessageGet ReactionsGET /api/sessions/{sessionId}/messages/{chatId}/{messageId}/reactions
MessageGet MediaGET /api/sessions/{sessionId}/messages/{chatId}/{messageId}/media
MessagePinPOST /api/sessions/{sessionId}/messages/pin
MessageUnpinPOST /api/sessions/{sessionId}/messages/unpin
MessageStarPOST /api/sessions/{sessionId}/messages/star
MessageVote PollPOST /api/sessions/{sessionId}/messages/vote-poll
MessageSend ProductPOST /api/sessions/{sessionId}/messages/send-product
ContactCheck ExistsGET /api/sessions/{sessionId}/contacts/check/{phoneNumber}
ContactGet InfoGET /api/sessions/{sessionId}/contacts/{contactId}
ContactGet PhoneGET /api/sessions/{sessionId}/contacts/{contactId}/phone
ContactGet Profile PictureGET /api/sessions/{sessionId}/contacts/{contactId}/profile-picture
ContactGet Profile PicturesGET /api/sessions/{sessionId}/contacts/profile-pictures?ids=
ContactListGET /api/sessions/{sessionId}/contacts
ContactList BlockedGET /api/sessions/{sessionId}/contacts/blocked
ContactSavePUT /api/sessions/{sessionId}/contacts/{contactId}
ContactDeleteDELETE /api/sessions/{sessionId}/contacts/{contactId}
ContactBlockPOST /api/sessions/{sessionId}/contacts/{contactId}/block
ContactUnblockDELETE /api/sessions/{sessionId}/contacts/{contactId}/block
ChatListGET /api/sessions/{sessionId}/chats
ChatMark ReadPOST /api/sessions/{sessionId}/chats/read
ChatMark UnreadPOST /api/sessions/{sessionId}/chats/unread
ChatDeletePOST /api/sessions/{sessionId}/chats/delete
ChatClear MessagesDELETE /api/sessions/{sessionId}/chats/{chatId}/messages
ChatArchivePOST /api/sessions/{sessionId}/chats/archive
ChatPinPOST /api/sessions/{sessionId}/chats/pin
ChatMutePOST /api/sessions/{sessionId}/chats/mute
ChatSet StatePOST /api/sessions/{sessionId}/chats/typing
GroupListGET /api/sessions/{sessionId}/groups
GroupCreatePOST /api/sessions/{sessionId}/groups
GroupJoinPOST /api/sessions/{sessionId}/groups/join
GroupGet Join InfoGET /api/sessions/{sessionId}/groups/join-info?code=
GroupGetGET /api/sessions/{sessionId}/groups/{groupId}
GroupLeavePOST /api/sessions/{sessionId}/groups/{groupId}/leave
GroupAdd ParticipantsPOST /api/sessions/{sessionId}/groups/{groupId}/participants
GroupRemove ParticipantsDELETE /api/sessions/{sessionId}/groups/{groupId}/participants
GroupPromote ParticipantsPOST /api/sessions/{sessionId}/groups/{groupId}/participants/promote
GroupDemote ParticipantsPOST /api/sessions/{sessionId}/groups/{groupId}/participants/demote
GroupUpdate SubjectPUT /api/sessions/{sessionId}/groups/{groupId}/subject
GroupUpdate DescriptionPUT /api/sessions/{sessionId}/groups/{groupId}/description
GroupGet SettingsGET /api/sessions/{sessionId}/groups/{groupId}/settings
GroupUpdate SettingsPUT /api/sessions/{sessionId}/groups/{groupId}/settings
GroupGet Invite CodeGET /api/sessions/{sessionId}/groups/{groupId}/invite-code
GroupRevoke Invite CodePOST /api/sessions/{sessionId}/groups/{groupId}/invite-code/revoke
GroupGet Membership RequestsGET /api/sessions/{sessionId}/groups/{groupId}/membership-requests
GroupApprove Membership RequestsPOST /api/sessions/{sessionId}/groups/{groupId}/membership-requests/approve
GroupReject Membership RequestsPOST /api/sessions/{sessionId}/groups/{groupId}/membership-requests/reject
GroupGet PictureGET /api/sessions/{sessionId}/groups/{groupId}/picture
GroupSet PicturePUT /api/sessions/{sessionId}/groups/{groupId}/picture
GroupDelete PictureDELETE /api/sessions/{sessionId}/groups/{groupId}/picture
ProfileSet NamePUT /api/sessions/{sessionId}/profile/name
ProfileSet StatusPUT /api/sessions/{sessionId}/profile/status
ProfileSet PicturePUT /api/sessions/{sessionId}/profile/picture
ProfileDelete PictureDELETE /api/sessions/{sessionId}/profile/picture
LabelListGET /api/sessions/{sessionId}/labels
LabelGetGET /api/sessions/{sessionId}/labels/{labelId}
LabelCreate or UpdatePUT /api/sessions/{sessionId}/labels/{labelId}
LabelDeleteDELETE /api/sessions/{sessionId}/labels/{labelId}
LabelGet ChatsGET /api/sessions/{sessionId}/labels/{labelId}/chats
LabelGet for ChatGET /api/sessions/{sessionId}/labels/chat/{chatId}
LabelAdd to ChatPOST /api/sessions/{sessionId}/labels/chat/{chatId}
LabelRemove From ChatDELETE /api/sessions/{sessionId}/labels/chat/{chatId}/{labelId}
StatusListGET /api/sessions/{sessionId}/status
StatusGet by ContactGET /api/sessions/{sessionId}/status/{contactId}
StatusGet MediaGET /api/sessions/{sessionId}/status/{statusId}/media
StatusDeleteDELETE /api/sessions/{sessionId}/status/{statusId}
StatusSend TextPOST /api/sessions/{sessionId}/status/send-text
StatusSend ImagePOST /api/sessions/{sessionId}/status/send-image
StatusSend VideoPOST /api/sessions/{sessionId}/status/send-video
StatusSend VoicePOST /api/sessions/{sessionId}/status/send-voice
TemplateListGET /api/sessions/{sessionId}/templates
TemplateCreatePOST /api/sessions/{sessionId}/templates
TemplateGetGET /api/sessions/{sessionId}/templates/{templateId}
TemplateUpdatePUT /api/sessions/{sessionId}/templates/{templateId}
TemplateDeleteDELETE /api/sessions/{sessionId}/templates/{templateId}
ChannelListGET /api/sessions/{sessionId}/channels
ChannelGetGET /api/sessions/{sessionId}/channels/{channelId}
ChannelGet MessagesGET /api/sessions/{sessionId}/channels/{channelId}/messages
ChannelCreatePOST /api/sessions/{sessionId}/channels
ChannelSubscribePOST /api/sessions/{sessionId}/channels/subscribe
ChannelUnsubscribeDELETE /api/sessions/{sessionId}/channels/{channelId}
ChannelDeletePOST /api/sessions/{sessionId}/channels/{channelId}/delete
ChannelMutePOST /api/sessions/{sessionId}/channels/{channelId}/mute
ChannelDemote AdminPOST /api/sessions/{sessionId}/channels/{channelId}/admins/demote
ChannelTransfer OwnershipPOST /api/sessions/{sessionId}/channels/{channelId}/owner/transfer
CallRejectPOST /api/sessions/{sessionId}/calls/{callId}/reject
CallCreate LinkPOST /api/sessions/{sessionId}/calls/link
ObservabilityCheckGET /api/health
ObservabilityCheck LivenessGET /api/health/live
ObservabilityCheck ReadinessGET /api/health/ready
SystemGet SettingsGET /api/settings
SystemGet Stats OverviewGET /api/stats/overview
SystemGet Message StatsGET /api/stats/messages
SystemGet Session StatsGET /api/stats/sessions/{sessionId}
SystemGet Audit LogGET /api/audit
SystemSearchGET /api/search
API KeyListGET /api/auth/api-keys
API KeyCreatePOST /api/auth/api-keys
API KeyGetGET /api/auth/api-keys/{keyId}
API KeyUpdatePUT /api/auth/api-keys/{keyId}
API KeyRevokePOST /api/auth/api-keys/{keyId}/revoke
API KeyDeleteDELETE /api/auth/api-keys/{keyId}
API KeyValidatePOST /api/auth/validate
WebhookCreatePOST /api/sessions/{sessionId}/webhooks
WebhookGetGET /api/sessions/{sessionId}/webhooks/{webhookId}
WebhookListGET /api/sessions/{sessionId}/webhooks
WebhookUpdatePUT /api/sessions/{sessionId}/webhooks/{webhookId}
WebhookDeleteDELETE /api/sessions/{sessionId}/webhooks/{webhookId}
WebhookTestPOST /api/sessions/{sessionId}/webhooks/{webhookId}/test
WebhookList AllGET /api/webhooks
WebhookGet Delivery FailuresGET /api/webhooks/delivery-failures
Automation RuleListGET /api/sessions/{sessionId}/automation-rules
Automation RuleCreatePOST /api/sessions/{sessionId}/automation-rules
Automation RuleGetGET /api/sessions/{sessionId}/automation-rules/{ruleId}
Automation RuleUpdatePUT /api/sessions/{sessionId}/automation-rules/{ruleId}
Automation RuleDeleteDELETE /api/sessions/{sessionId}/automation-rules/{ruleId}
CatalogGetGET /api/sessions/{sessionId}/catalog
CatalogList ProductsGET /api/sessions/{sessionId}/catalog/products
CatalogGet ProductGET /api/sessions/{sessionId}/catalog/products/{productId}
MediaCheck AvailabilityGET /api/sessions/{sessionId}/media/convert
MediaConvert to Voice NotePOST /api/sessions/{sessionId}/media/convert/voice
MediaConvert to VideoPOST /api/sessions/{sessionId}/media/convert/video
PresenceSubscribePOST /api/sessions/{sessionId}/presence/subscribe
PresenceGetGET /api/sessions/{sessionId}/presence/{chatId}
PresenceSet Own PresencePUT /api/sessions/{sessionId}/presence

Values that land in a URL path — Session ID, Batch ID, Webhook ID, Label ID, Rule 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. Values that legitimately carry such characters are checked for emptiness and URL-encoded instead: the WhatsApp JIDs (chat, contact, group, channel), the Message ID a reaction or media read addresses, and the Product ID from a catalog listing.

Not offered by the node

Send Catalog and PUT /api/settings were removed from the server in v0.19.0 — both had answered 501 since they shipped. 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. The Catalog resource reads a Baileys session's catalog; on a whatsapp-web.js session every catalog operation answers 501. Sending a product from that catalog is Message → Send Product, not a Catalog operation.

Separately, the node is not a full mirror of the API. Four server areas have no resource: plugin management (/api/plugins/*), the infrastructure routes (/api/infra/*), Integration Fabric instance management (/api/integration/*), and the Prometheus metrics scrape. Within the resources it does cover, the operation tables above are the authoritative list: an operation absent from them is absent from the node. Reach anything missing with n8n's HTTP Request node using the same credential.

Media source model​

Every operation that carries media — Message → Send Image, Send Video, Send Audio, Send Document and Send Sticker; Profile → Set Picture; Group → Set Picture; and Status → Send Image, Send Video and Send Voice — shares one source model. A Source field offers three ways to supply the bytes, and the remaining fields follow from it:

SourceExtra fieldsRequest fields sent
Binary DataBinary Property (default data)base64 (the buffer encoded) and mimetype, read from the binary metadata
URL(the media URL field)url
Base64Base64 Data, MIME Typebase64 and mimetype (the MIME Type field)

Two of them differ in their labels. Group → Set Picture and Status → Send Voice name the first option Binary rather than Binary Data, default to it rather than to URL, and call the field that follows Input Binary Field rather than Binary Property. Everywhere else the option reads Binary Data, the default is URL, and the field is Binary Property. Media → Convert follows the same shorter naming; see Media resource.

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 and status voice notes, image/webp for stickers, image/jpeg for profile pictures, group pictures and status images, and video/mp4 for status video.

Base64 needs a MIME type

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.

OperationFieldsNotes
CreateSession Name, Session Config (JSON), Proxy URLSession Name is required: 3–50 characters, letters, numbers, and hyphens only. Session Config is an optional JSON object, for example {"autoRejectCalls":true}; a non-object value fails the item. Proxy URL is optional and validated the same way Update Proxy validates it, but a blank value is omitted rather than sent, since the server's DTO reads a blank as a malformed URL. Returns the new session's UUID.
StartSession Name or IDStarts the session and connects to WhatsApp.
StopSession Name or IDStops the session and disconnects.
Force KillSession Name or IDForce-kills a stuck session's engine.
DeleteSession Name or IDDeletes the session.
Get QRSession Name or IDReturns the QR code for scanning authentication.
Request Pairing CodeSession Name or ID, Phone NumberPhone 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. Start the session and poll Get Status until status reads qr_ready before requesting a code: an unstarted session answers 400, a started one that has not reached qr_ready answers 409, and one that already reads ready is linked and answers 400. See Sessions.
Get StatusSession Name or IDReturns the status of one session.
List AllOptions: Limit, OffsetReturns every session, paginated.
Get Stats Overview(none)Overview statistics across all sessions.
Log OutSession Name or IDAsks WhatsApp to remove this companion device, then tears the engine down. Unlike Stop it needs a live engine, and the session must be paired again afterwards.
Get ConfigSession Name or IDThe session's stored configuration.
Update ConfigSession Name or ID, Config FieldsA PATCH: only the fields you add are sent, and anything left out keeps its stored value. At least one is required.
Get ProxySession Name or IDServer v0.23.4 and newer. Reports the scheme, the host and port, and whether credentials are embedded. It never returns the credentials themselves.
Update ProxySession Name or ID, Proxy URL, Clear ProxyServer v0.23.4 and newer. Writes the proxy without restarting anything, so a change takes effect on the next Start. Refuses a session-scoped key.

Session Config on Create takes the same three keys the collection below offers, spelled as JSON: autoRejectCalls, maxReconnectAttempts and reconnectBaseDelay. Those are the only keys the server reads. Anything else is stored and ignored, so a misspelled key is accepted silently and never takes effect.

The Config Fields collection on Update Config:

FieldTypeNotes
Auto Reject CallsbooleanDecline every incoming call automatically. Re-read on each call, so it applies immediately.
Max Reconnect AttemptsnumberHow many consecutive reconnects to attempt, -1 to 20. -1 means unlimited and is both the default and the only way back to it once a cap is set; the node sends it as the null the server spells unlimited with. 0 is a real value meaning never reconnect, leaving the session down until it is started by hand. Applies from the next Start, not to a reconnect already under way.
Reconnect Base Delay (Ms)numberBase backoff between attempts, 1000 to 300000. Applies from the next Start.

Proxy URL is a full URL with its scheme (http, https, socks4 or socks5), at most 255 characters; a value without a scheme or without a host fails the item. Credentials embedded in the URL work on Baileys, but whatsapp-web.js cannot authenticate a SOCKS proxy. An unreachable proxy does not fail fast: no QR is ever delivered and Start times out after about 30 seconds.

Clear Proxy removes the stored proxy instead of setting one, because the server spells removal as an explicit null that a text field cannot express. While it is on, Proxy URL is ignored. The node tests it against true rather than for truthiness, so an expression resolving to the string "false" does not wipe a working proxy. With the toggle off, a blank Proxy URL fails the item rather than being sent, which would otherwise turn the PATCH into a no-op read reporting the old proxy as though it had been written.

Message resource​

The twenty-seven 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.

FieldTypeRequiredDescription
Session Name or IDoptionsYesThe session to act through.
Chat Name or IDoptionsYes (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 }.

FieldTypeRequiredMaps to
MessagestringYestext
Link PreviewoptionsNolinkPreview. Baileys builds a preview only when this asks for one; whatsapp-web.js builds one by default and this suppresses it.
Custom Link PreviewcollectionNocustomLinkPreview. Supplies the card yourself, so nothing is fetched. Offers URL, Title and Description; the first two are both required or nothing is sent, and the URL must also appear literally in the message text or WhatsApp renders no card at all. Baileys only: whatsapp-web.js answers 501 rather than dropping it silently.

Send Image — the media source model, plus an optional caption. Request body { chatId } plus the source fields, and caption when set.

FieldTypeRequiredNotes
Image Sourceoptions: Binary Data, URL, Base64YesDefault URL.
Binary PropertystringYes (binary)Default data.
Image URLstringYes (url)Public URL of the image.
Base64 DatastringYes (base64)Base64-encoded image bytes.
MIME TypestringYes (base64)For example image/png. Default image/jpeg.
CaptionstringNoSent 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.

FieldTypeRequiredNotes
Audio Sourceoptions: Binary Data, URL, Base64YesDefault URL.
Binary PropertystringYes (binary)Default data.
Audio URLstringYes (url)Public URL of the audio.
Base64 DatastringYes (base64)Base64-encoded audio bytes.
MIME TypestringYes (base64)Default audio/ogg; codecs=opus. For a plain audio file set its real type (for example audio/mpeg).
Send as Voice NotebooleanNoDefault 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.

FieldTypeRequiredNotes
Document Sourceoptions: Binary Data, URL, Base64YesDefault URL.
Binary PropertystringYes (binary)Default data.
Document URLstringYes (url)Public URL of the document.
Base64 DatastringYes (base64)Base64-encoded document bytes.
MIME TypestringYes (base64)For example application/pdf. Default application/pdf.
FilenamestringNoSent as filename. Default document.pdf.
CaptionstringNoSent as caption when set.

Send Sticker — same source model. WhatsApp expects a WebP sticker, ideally 512×512.

FieldTypeRequiredNotes
Sticker Sourceoptions: Binary Data, URL, Base64YesDefault URL.
Binary PropertystringYes (binary)Default data.
Sticker URLstringYes (url)Public URL of the sticker (WhatsApp expects a WebP image).
Base64 DatastringYes (base64)Base64-encoded sticker bytes.
MIME TypestringYes (base64)Default image/webp; WhatsApp requires WebP.
Mentions

Send Text, Send Image, Send Video, Send Audio, Send Document, Send Sticker, Send Template, Reply and Edit all 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.

Quoting from a send

Send Text, Send Image, Send Video, Send Audio, Send Document, Send Sticker, Send Location, Send Contact and Send Poll each accept an optional Quoted Message ID, sent as quotedMessageId. It is how a reply carries media, a location, a contact or a poll: Reply itself sends text only, and its own Quoted Message ID is required rather than optional. The two sets are not the same, and neither follows from the other. Send Template and Edit can mention but cannot quote.

An id the engine cannot resolve fails the send outright rather than delivering it unquoted, and Baileys can only quote a message it has already stored.

Send Location — request body { chatId, latitude, longitude }.

FieldTypeRequiredMaps to
LatitudenumberYeslatitude
LongitudenumberYeslongitude
Location NamestringNoSent as description (OpenWA's field for the location label) when set.
AddressstringNoSent as address, the street line WhatsApp shows under the label.

Send Contact — request body { chatId, contactName, contactNumber }.

FieldTypeRequiredMaps to
Contact NamestringYescontactName — display name for the shared contact card.
Contact NumberstringYescontactNumber — 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.

FieldTypeRequiredNotes
QuestionstringYesSent as name. Maximum 255 characters.
Optionsstring listYesThe answers to vote on. Between 2 and 12 — anything outside that range fails the item. Each option is also capped at 100 characters server-side.
Allow Multiple AnswersbooleanNoDefault 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.

FieldTypeRequiredNotes
Template Name or IDoptionsYes (or Template Name)Id of the template to render. When both this and Template Name are set, the id wins.
Template NamestringYes (or Template Name or ID)Used only when the id is empty. Providing neither fails the item.
Variables (JSON)jsonNoValues 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.

FieldTypeRequiredNotes
Messages (JSON)jsonYesArray 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 IDstringNoCustom batch id; must be unique per session. Leave empty to let the server generate one.
OptionscollectionNoLeft empty, the server applies its own defaults (delay 3000 ms, randomize on, stop-on-error off).

The Options collection offers:

OptionTypeDefaultNotes
Delay Between Messages (Ms)number3000Milliseconds to wait between sends, 1000–60000.
Randomize DelaybooleanonAdds a random 0–2000 ms on top of the delay.
Stop on ErrorbooleanoffAborts 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:

FieldTypeRequiredNotes
Batch IDstringYesThe batch id returned by Send Bulk.

Reply — request body { chatId, quotedMessageId, text }.

FieldTypeRequiredNotes
Quoted Message IDstringYesFull serialized id of the message to quote (for example true_628123456789@c.us_3EB0…), as returned by send operations or delivered by the Trigger.
MessagestringYesThe reply text, sent as text.

React — request body { chatId, messageId, emoji }.

FieldTypeRequiredNotes
Message IDstringYesFull serialized id of the target message.
EmojistringNoThe emoji to react with. Leave empty to remove your existing reaction — the empty value is sent deliberately.

Edit — request body { chatId, messageId, body }.

FieldTypeRequiredNotes
Message IDstringYesFull serialized id of the message to edit.
MessagestringYesThe replacement body, maximum 4096 characters.

Delete — request body { chatId, messageId, forEveryone }.

FieldTypeRequiredNotes
Message IDstringYesFull serialized id of the message to delete.
Delete for EveryonebooleanNoDefault 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.

FieldTypeRequiredNotes
From Chat Name or IDoptionsYesThe chat the message currently lives in.
To Chat Name or IDoptionsYesThe chat to forward it to.
Message IDstringYesFull 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.

OptionTypeDefaultNotes
After Row IDstringunsetKeyset cursor: the id of the previous page's last message. Anchors the page to a row rather than a count, so a message arriving mid-walk cannot repeat or skip one. Takes precedence over Offset.
Chat Name or IDoptions—Only return messages from this chat.
Fromstring—Only return messages from this sender.
Inline MediabooleantrueTurn off to omit inline media payloads, keeping each row's { omitted, sizeBytes } marker. The media budget is per response, so a paged walk pays it again on every page.
Limitnumber50Max results, 1 to 100.
Offsetnumber0Records to skip before collecting the result set.

Unlike Get History and Get Reactions beside it, List answers an envelope ({ messages, total }) and so still produces a single item; see Output and error handling.

Get History reads a chat's history from the device. whatsapp-web.js only; Baileys answers 501, so on a Baileys session reach for List, which serves the gateway's own stored copy on both engines. Requires a Chat ID; the Options collection offers:

OptionTypeDefaultNotes
DeepbooleanoffPull older messages from the device instead of only what the server has stored.
Include MediabooleanoffInclude media payloads in the returned messages.
Limitnumber50Max number of results to return.

Get Reactions reads the reactions on one message. whatsapp-web.js only; Baileys answers 501. The Trigger's message.reaction event fires on both engines, so a Baileys workflow tracks reactions as they arrive rather than reading them back.

FieldTypeRequiredNotes
Chat Name or IDoptionsYesThe chat the message lives in.
Message IDstringYesFull serialized id of the message.

Get Media downloads the media attached to one message.

FieldTypeRequiredNotes
Chat Name or IDoptionsYesThe chat the message lives in.
Message IDstringYesFull serialized id of the message.
Put Output in FieldstringYesName of the output binary property, default data.

The bytes are attached as a binary property rather than put on json, so the item's json is empty. This one reads from the gateway's own archive rather than the engine, so it works while the session is stopped, and a 404 is its only failure.

Pin and Unpin take request body { chatId, messageId }, plus durationSeconds on Pin alone.

FieldTypeRequiredNotes
Chat Name or IDoptionsYesThe chat the message lives in.
Message IDstringYesFull serialized id of the message.
Pin DurationoptionsPin only24 Hours (the default), 7 Days, or 30 Days. WhatsApp accepts only these three windows, and there is no way to read a pin back, so a workflow cannot check or refresh one.

Star takes request body { chatId, messageId, star }.

FieldTypeRequiredNotes
Chat Name or IDoptionsYesThe chat the message lives in.
Message IDstringYesFull serialized id of the message.
StarbooleanYesOn by default; turn it off to remove the star. Always sent, since the server has no default and omitting it is a 400. A star is private to this account and never visible to the other party.

Vote Poll casts a vote on a poll someone else sent, with request body { chatId, pollMessageId, options }. whatsapp-web.js only; Baileys answers 501.

FieldTypeRequiredNotes
Chat Name or IDoptionsYesThe chat the poll lives in.
Message IDstringYesThe poll message's id. Sent as pollMessageId, not messageId.
Selected Optionsstring listYesThe option texts to select, at most 12. Matched by text against the poll's own options, so they must match exactly: a different case or a stray space selects nothing while still reporting success. An option whose own text contains a comma must be supplied as a JSON array, since a comma-separated list would split it. The vote replaces any previous selection, and an empty list clears it, so the key is always sent.

Send Product sends a product card from this account's catalog, with request body { chatId, productId } plus body when a message is set. Baileys only; whatsapp-web.js answers 501, which is the same engine restriction the Catalog resource carries, so the operation that finds a product id and the one that sends it agree on the engine.

FieldTypeRequiredNotes
Chat Name or IDoptionsYesRecipient.
Product IDstringYesThe product's id in this account's catalog; find it with Catalog → List Products. An id that is not in the catalog answers 404. A product with no image cannot be sent as a card, which the server reports as a 400.
MessagestringNoOptional text alongside the card. Sent as body.
Media to a channel is Baileys only

Send Image, Send Video, Send Audio, Send Document and Send Sticker all answer 501 on whatsapp-web.js when the Chat Name or ID is a channel (<id>@newsletter). The same operations work on either engine for a person or a group. Send Text to a channel works on both.

Contact resource​

Check Exists takes a Phone Number, Get Profile Pictures takes a list of ids, List and List Blocked take only pagination or nothing at all, and every other contact operation takes a Contact Name or ID (a WhatsApp JID such as 628123456789@c.us).

OperationFieldTypeRequiredNotes
Check ExistsPhone NumberstringYesDigits only, for example 628123456789. The node strips +, spaces, -, and (); a value with any non-digit left over fails the item.
Get InfoContact Name or IDoptionsYesFor example 628123456789@c.us. Empty values fail the item.
Get PhoneContact Name or IDoptionsYesResolves the contact's phone number.
Get Profile PictureContact Name or IDoptionsYesReturns the contact's profile-photo URL.
Get Profile PicturesContact IDsstring listYesPictures 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.
ListOptions: Limit, OffsetcollectionNoReturns the session's contacts, paginated.
List Blocked(none)n/an/aThe ids this account has blocked. Bare id strings, not contact objects; see the wrapping note under Output and error handling.
SaveContact Name or ID, First Name, Last NamestringFirst Name yesWrites the addressbook entry. Both names are capped at 100 characters.
DeleteContact Name or IDoptionsYesRemoves the entry from the addressbook. The chat and its history are untouched.
BlockContact Name or IDoptionsYesBlocks the contact.
UnblockContact Name or IDoptionsYesUnblocks 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.

Save overwrites the whole entry rather than patching it, so a blank Last Name clears any last name already stored. The node omits the key when it is blank rather than sending null, which the engine would write as a literal null.

List Blocked returns ids alone on both engines. whatsapp-web.js can resolve full contact models and Baileys cannot, so the server publishes the honest common subset instead of letting the two engines describe the same account differently.

Chat resource​

Chat operations act on a conversation rather than the session. Most post the target chat in the request body; List takes none, and Clear Messages is the one that names the chat in the path and is a real DELETE.

OperationFieldsNotes
ListOptions: Limit (default 50), Offset (default 0)The session's chats, one item per chat. Each row carries archived, pinned and muted, plus muteExpiration when muted, so the state the write operations below set can be read back.
Mark ReadChat Name or ID, Message IDsBody { chatId }, plus messageIds when supplied. Leave the ids empty to mark the whole chat read; supply them to ack specific messages, at most 100.
Mark UnreadChat Name or IDBody { chatId }.
DeleteChat Name or IDBody { chatId }. A POST, not a DELETE — the server takes the chat id in the body here.
Clear MessagesChat Name or IDDELETE /api/sessions/{sessionId}/chats/{chatId}/messages. Empties the chat but keeps it in the list.
ArchiveChat Name or ID, ArchiveBody { chatId, archive }. Set Archive off to unarchive.
PinChat Name or ID, PinBody { chatId, pin }. WhatsApp allows at most three pinned chats.
MuteChat Name or ID, Mute UntilBody { chatId, muteUntil }, epoch milliseconds. A seconds-scale value lands in 1970 and the mute expires immediately.
Set StateChat Name or ID, StateBody { 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, Join, and Get Join Info are session-level; every other operation takes a Group Name or ID (a JID such as 120363021234567890@g.us).

OperationFieldsNotes
ListOptions: Limit (1–1000), OffsetLeft empty, the server applies its own defaults (limit 1000, offset 0).
CreateGroup Name, ParticipantsName 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.
JoinInvite CodeThe part after https://chat.whatsapp.com/. A full invite link is accepted and reduced to the code. Maximum 128 characters.
Get Join InfoInvite CodePreviews the group behind a code without joining, so it is safe to run on a code from an untrusted source. Same link tolerance and 128-character cap as Join. There is no participant list, only a count, and only when WhatsApp discloses one; fields the engine does not report are omitted rather than defaulted.
GetGroup Name or IDGroup info including participants.
LeaveGroup Name or IDLeaves the group.
Add / Remove / Promote / Demote ParticipantsGroup Name or ID, ParticipantsBody { 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 SubjectGroup Name or ID, SubjectRequired, maximum 100 characters.
Update DescriptionGroup Name or ID, DescriptionMaximum 1024 characters. An empty value is sent as-is and clears the description.
Get SettingsGroup Name or IDReads announce, locked, the member-add mode, and the disappearing-message timer.
Update SettingsGroup Name or ID, SettingsPartial — settings you leave out stay untouched, and at least one is required.
Get Invite CodeGroup Name or IDThe invite code and link.
Revoke Invite CodeGroup Name or IDRevokes the code and generates a new one.
Get Membership RequestsGroup Name or IDThe join-approval queue, one item per pending request. Only populated when the group has admin approval enabled, and admin-only on both engines.
Approve / Reject Membership RequestsGroup Name or ID, RequestersBody { participants }, capped at 256. Leave Requesters empty to act on the whole queue rather than failing, which is why it is the one participant list the node accepts empty. An empty queue is a no-op returning an empty results list.
Get PictureGroup Name or IDThe group picture's URL.
Set PictureGroup Name or ID, Picture Source (+ source fields)The media source model, defaulting to Binary; base64 falls back to image/jpeg. The resolved media fields form the whole request body. Admin-only, and a base64 or binary payload over the server's media cap answers 413.
Delete PictureGroup Name or IDRemoves the picture. Admin-only.

The Settings collection offers:

OptionTypeDefaultNotes
AnnouncebooleanoffOnly admins can send messages to the group.
LockedbooleanoffOnly admins can edit the group info.
Member Add ModeoptionsAll MembersWho may add participants: All Members (all) or Admins Only (admins).
Disappearing Messages (Seconds)number604800Disappearing-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. Approve and Reject Membership Requests report the same way. On whatsapp-web.js the engine pauses 250 to 500 ms between requesters as upstream anti-abuse pacing, so clearing a long queue is a proportionally long request: raise the node's timeout before running it on a busy group.

Profile resource​

Changes the session's own WhatsApp profile.

OperationFieldsNotes
Set NameNameRequired, maximum 25 characters.
Set StatusStatusMaximum 139 characters. An empty value is sent as-is and clears the about text.
Set PicturePicture Source, and the matching Binary Property / Picture URL / Base64 Data + MIME TypeThe media source model; base64 defaults to image/jpeg. The resolved media fields form the whole request body.
Delete Picture(none)Removes the account's own picture.

Label resource​

WhatsApp Business labels — the catalogue on the account, and the labels attached to one chat.

OperationFieldsNotes
List(none)whatsapp-web.js only; Baileys answers 501. Every label on the account.
GetLabel Name or IDwhatsapp-web.js only; Baileys answers 501. One label.
Create or UpdateLabel ID, Fields: Name, ColorBaileys only; whatsapp-web.js answers 501. A PUT, because the id is caller-chosen: an unused id creates, an existing one rewrites that label rather than failing. At least one field is required, and the write replaces the whole label: a field left out is not preserved, so send every field the label should keep.
DeleteLabel IDBaileys only; whatsapp-web.js answers 501. The label disappears from every chat it was on.
Get ChatsLabel Name or IDwhatsapp-web.js only; Baileys answers 501.
Get for ChatChat Name or IDwhatsapp-web.js only; Baileys answers 501. The labels attached to a chat.
Add to ChatChat Name or ID, Label Name or IDBody { labelId }.
Remove From ChatChat Name or ID, Label Name or IDBoth ids go in the path.

The whole resource is split down the middle, and no session gets both halves. Baileys carries the label writes and cannot query labels at all; whatsapp-web.js carries every read and cannot edit a label. Only Add to Chat and Remove From Chat work on both, since those write the chat rather than the label.

That split is also why Create or Update and Delete take a plain-text Label ID rather than the dropdown the other operations use: the picker is fed by a read the engine serving those two writes cannot perform, so a picker would always be empty there.

The Fields collection on Create or Update:

FieldTypeNotes
NamestringLabel text, up to 100 characters. A blank value fails the item rather than being dropped: the server marks the field non-empty, so a blank cannot mean "clear the name". Leaving the field out is not a safe no-op either: the write replaces the whole label, so a name that is not sent is lost.
ColornumberAn index into WhatsApp's twenty predefined colours, 0 to 19, not a hex value. 0 is a real colour, so the field lives in a collection to keep "not set" distinguishable. A read returns a hex string that cannot be converted back, so read-then-write does not round-trip the colour.

Status resource​

Reads the Status (Stories) feed and posts new updates.

OperationFieldsNotes
List(none)The status feed.
Get by ContactContact Name or IDOne contact's status updates.
Get MediaStatus ID, Put Output in FieldStreams 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.
DeleteStatus IDDeletes one of your own status updates.
Send TextText, Background Color, Font, RecipientsBody { text } plus backgroundColor, font, and recipients when set. Text is required, maximum 4096 characters.
Send ImageImage Source (+ source fields), Caption, RecipientsThe media object nests under image rather than sitting flat on the body.
Send VideoVideo Source (+ source fields), Caption, RecipientsThe media object nests under video.
Send VoiceAudio Source (+ source fields), Background Color, RecipientsPosts an audio status as a voice note. The media object nests under audio, and there is no caption. The source dropdown defaults to Binary; base64 falls back to audio/ogg; codecs=opus.
FieldTypeNotes
Background ColorcolorSent as backgroundColor. Leave empty for the server default.
FontoptionsFont 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.
CaptionstringMaximum 1024 characters.
Recipientsstring listWho may see this status: at most 256 @c.us or @lid ids, never a group. Required on the Baileys engine, which honours it. whatsapp-web.js ignores it entirely and posts to the whole contact list whether a list is supplied or not, logging a warning server-side when one is, so treat it as an audience restriction on Baileys alone.

Template resource​

Reusable message bodies with {{variable}} placeholders, stored per session and rendered by Message → Send Template.

OperationFieldsNotes
List(none)Every template in the session.
CreateName, Body, Header, FooterName (max 100) and Body (max 4096) are required; Header and Footer are optional, max 1024 each.
GetTemplate Name or IDOne template.
UpdateTemplate Name or ID, Update FieldsPartial: the collection offers Body, Footer, Header, and Name, with the same limits. At least one is required.
DeleteTemplate Name or IDDeletes the template.

A blank value in Update Fields means different things per field, because the server validates them differently. Name and Body are non-empty on the server, so a blank one fails the item with a message naming the field rather than being silently dropped, which would report success while leaving the template untouched. Header and Footer carry no such rule, so a blank there is a deliberate clear and is sent as one. Add a field only to change it; remove it from the collection to leave it alone.

Channel resource​

WhatsApp Channels (newsletters) the session follows.

OperationFieldsNotes
List(none)whatsapp-web.js only; Baileys answers 501. Followed channels.
GetChannel Name or IDOne channel. Works on both engines.
Get MessagesChannel Name or ID, Options: Limit (1 to 100, default 50)whatsapp-web.js only; Baileys answers 501. A channel's messages.
CreateChannel Name, DescriptionName is required, maximum 100 characters; Description is optional, maximum 2048. The account becomes the owner, which is what makes Delete possible later. A blank description is omitted rather than sent as an empty one.
SubscribeInvite CodeBaileys only; whatsapp-web.js answers 501, because its library subscribes by channel id and has no invite-code path. The part after https://whatsapp.com/channel/. A full link is accepted and reduced to the code.
UnsubscribeChannel Name or IDA DELETE on the channel — it unfollows rather than deletes.
DeleteChannel Name or IDIrreversible, and every subscriber loses the channel. Owner only. Deliberately a POST on a separate path so a slip of the wrist cannot turn Unsubscribe into this.
MuteChannel Name or ID, MuteSilences notifications for this account; the subscription is untouched. The flag defaults to on and is always sent, since the server has no default of its own. Turn it off to unmute.
Demote AdminChannel Name or ID, User IDDemotes an admin back to a subscriber. Owner only, and Baileys only: whatsapp-web.js answers 501 because the module function its library targets no longer exists. There is no promote counterpart on either engine, so an admin is promoted from the WhatsApp app and demoted here.
Transfer OwnershipChannel Name or ID, New Owner IDIrreversible: once it lands this session is no longer the owner and cannot take the channel back through this API. Owner only, and Baileys only; whatsapp-web.js answers 501.

Channels are the most engine-split resource here, and the split runs both ways: Baileys is the only engine that can subscribe by invite code, and whatsapp-web.js is the only one that can list channels or read their messages. So neither engine covers the whole resource, and a workflow that subscribes to a channel cannot then list it on the same session. Get, Create, Unsubscribe, Delete and Mute are the operations that work on either.

User ID and New Owner ID accept a bare phone number, which the server qualifies into a JID.

Unsubscribe and Delete are the pair to keep straight: the first leaves a channel someone else runs, the second destroys one this account owns. They differ in both verb and path for that reason.

Call resource​

OperationFieldsNotes
RejectSession Name or ID, Call IDThe call id as delivered by the Trigger's call events. Pair it with call.received to auto-decline.
Create LinkSession Name or ID, Call Type, Start TimeGenerates a shareable WhatsApp call link anyone can join. Call Type is Video (the default) or Audio. Start Time is a date-time picker the node converts to epoch milliseconds; leave it empty for now, which is what the blank picker means, because the server requires the field. The response carries the link alone with no expiry, so the node cannot report how long it stays valid.

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.

OperationNotes
CheckGET /api/health — the server's health JSON as-is.
Check LivenessThe liveness probe.
Check ReadinessThe 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.

OperationFieldsNotes
Get Settings(none)The server settings document. ADMIN key, unscoped.
Get Stats Overview(none)Overview statistics across the instance. ADMIN key, unscoped.
Get Message StatsPeriodMessage statistics across the instance. ADMIN key, unscoped. Period is Last 24 Hours (the default), Last 7 Days, or Last 30 Days, and the bucket size follows from it: hourly for 24 hours, daily for the longer windows. The route binds its query to a DTO, so period is the only key it accepts and anything else is refused rather than ignored.
Get Session StatsSession Name or IDStatistics for one session. Any valid key.
Get Audit LogFiltersThe audit log. ADMIN key. Unlike the other ADMIN reads here it accepts a session-scoped key, which simply narrows the result.
SearchQuery, FiltersCross-session message search. Needs an OPERATOR key, so a VIEWER key answers 403 on this read; q is the only required parameter. On an instance running a plugin search provider, 503 means the provider did not answer and is worth retrying, 502 means it answered with an unusable shape and a retry will not help, and 501 means no provider is configured. The built-in provider returns neither 502 nor 503.

The Search filters:

FilterTypeNotes
Chat IDstringOnly 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 TodateTimeBounds 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.
DirectionoptionsIncoming or Outgoing.
FromstringOnly return messages from this sender.
Limit / OffsetnumberPagination, defaults 50 and 0.
Session Name or IDoptionsOnly search within this session.
TypestringOnly return messages of this type, for example text or image.

The Get Audit Log filters:

FilterTypeNotes
ActionstringOnly entries for this action.
API Key Name or IDoptionsOnly entries recorded for this key. Sent to the API as apiKeyId.
Limit / OffsetnumberPagination, defaults 50 and 0; Limit is capped at 200 in the UI.
Session Name or IDoptionsOnly entries for this session.
SeverityoptionsOne of info (the default), warn or error. A dropdown, not free text.

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.

OperationFieldsNotes
List(none)Every key.
CreateName, FieldsName is required; the Fields collection carries the optional restrictions below.
GetAPI Key Name or IDOne key. The id, not the key itself.
UpdateAPI Key Name or ID, FieldsPartial — only the fields you set are changed, and an empty list never clears an existing whitelist. At least one field is required.
RevokeAPI Key Name or IDDeactivates the key.
DeleteAPI Key Name or IDRemoves the key.
Validate(none)Validates the credential this node is already authenticating with. Works with any valid key.

The Fields collection offers:

OptionTypeDefaultNotes
Namestring—A friendly name for the key.
RoleoptionsViewerAdmin, Operator, or Viewer.
Expires AtdateTime—When the key stops working. The node normalises whatever the field resolves to into an ISO-8601 string, and refuses a date already in the past or more than a hundred years out. The server accepts any ISO date and checks neither, so this catches a mistake the API would answer 200 to.
Allowed IPsstring list—Restrict the key to these addresses. Single IPs and CIDR ranges are both accepted.
Allowed Sessionsstring list—Restrict the key to these sessions, by id. A session name matches nothing, so it silently scopes the key to no session at all.

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.

FieldTypeRequiredNotes
Webhook URLstringYesDestination that receives event deliveries.
EventsmultiOptionsYesOne or more events. At least one must be selected.
Webhook Secretstring (password)NoIf 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.

FieldTypeRequiredNotes
Webhook Name or IDoptionsYesThe webhook to update. The dropdown lists a session's webhooks by delivery URL.
Update FieldscollectionNoThe changes to apply — see the options below.

The Update Fields collection offers:

OptionTypeNotes
URLstringNew delivery URL.
EventsmultiOptionsReplaces the full set of subscribed events (not merged). When set, at least one event must be selected.
ActivebooleanWhether the webhook is enabled.
Retry CountnumberMaximum delivery attempts, 0–5.
Secretstring (password)A non-empty value rotates the HMAC-SHA256 signing secret; an empty value is ignored, so a blank field cannot accidentally unsign a webhook.
Clear SecretbooleanStops signing. It sends secret: "", which the server reads as "stop signing", so disabling signature verification no longer needs a recreate or a hand-built request.
Headers (JSON)jsonCustom 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)jsonAdvanced 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.

OperationFieldsNotes
GetSession Name or ID, Webhook Name or IDOne webhook.
ListSession Name or IDThe session's webhooks.
DeleteSession Name or ID, Webhook Name or IDRemoves it.
TestSession Name or ID, Webhook Name or IDSends a test delivery.

List All and Get Delivery Failures span every session, so neither shows a Session ID field.

OperationOptionsNotes
List AllLimit, OffsetWebhooks 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 FailuresLimit, Offset, Session Name or IDFailed deliveries; this route is the one that does accept a session filter. ADMIN key.

Automation Rule resource​

Server-side auto-reply rules. Every operation takes Session Name or ID; Get, Update and Delete also take a Rule ID, the value Create or List returned.

OperationFieldsNotes
List(none beyond the session)The session's rules, one item per rule.
GetRule IDOne rule.
CreateName, Reply Text, Conditions, Additional FieldsName is capped at 100 characters and Reply Text at 4096.
UpdateRule ID, Update FieldsOnly the fields you add are sent; anything left out keeps its stored value.
DeleteRule IDRemoves it.

Conditions is JSON in the same shape as a webhook filter, {"conditions":[{"field":"isGroup","operator":"is","value":false}]}. Every condition must match. Leave it empty and the rule answers every inbound message.

Additional Fields on Create, and Update Fields on Update, both carry Cooldown (Seconds) (default 60, how long the rule stays quiet in a chat after replying there) and Enabled (default true). Update additionally accepts Name, Reply Text and Conditions.

These rules run on the gateway, not in n8n

A matching message is answered even when the workflow is not running, which makes them the right tool for an out-of-hours acknowledgement and the wrong one for anything needing workflow logic. Conditions use the same field set as webhook filters, so they only ever see message events.

Catalog resource​

Reads a WhatsApp Business product catalog. Every operation takes Session Name or ID.

OperationFieldsNotes
List ProductsOptions (Limit, Page)Products, paginated. Limit defaults to 50 and Page to 1.
Get ProductProduct IDOne product.
Get(none beyond the session)The catalog's own metadata.
Baileys only, and a 503 here can be permanent

whatsapp-web.js answers 501 on every catalog operation. Use List Products to find the product id that Message → Send Product needs. A 503 can mean WhatsApp left the catalog query unanswered, which it does permanently for some business accounts, so treat a repeated 503 as that account being unsupported rather than as a transient worth retrying.

Media resource​

Server-side conversion into the formats WhatsApp actually plays. Every operation takes Session Name or ID.

OperationFieldsNotes
Check Availability(none beyond the session)Whether conversion is configured and ffmpeg is runnable.
Convert to Voice NoteMedia Source, and the field that source needsProduces Ogg/Opus.
Convert to VideoMedia Source, and the field that source needsProduces a compatible MP4.

Media Source selects one of Binary (default; takes Input Binary Field, default data), URL (takes Media URL), or Base64 (takes Base64 Data). No MIME type is sent, because the server reads it from the bytes.

Conversion feeds a send, and is optional on the server

Conversion returns base64 and mimetype ready to feed straight into a send. Convert to Voice Note produces the Ogg/Opus that Message → Send Audio (Base64 source, Send as Voice Note on) or Status → Send Voice needs; Convert to Video produces the MP4 for Message → Send Video. Nothing else in the pipeline transcodes, so without this an MP3 sent as a voice note produces a microphone bubble that will not play. Conversion is opt-in on the server and needs ffmpeg: run Check Availability first, and read a 503 as conversion being disabled or busy rather than as a bad request.

Presence resource​

Presence subscription, per-chat reads, and the account's own availability. Every operation takes Session Name or ID.

OperationFieldsNotes
SubscribeChat Name or IDSubscribes to presence updates for that chat, so presence.update events start arriving.
GetChat Name or IDThe last reported presence for that chat. Answers an empty object when nothing has been reported yet.
Set Own PresenceAvailableWhether the account announces itself as online.
Presence is connection-scoped

A subscription and the account's own availability both live on the socket, so a restart, a Stop/Start, or any automatic reconnect ends them, and nothing on the server re-issues them. Re-run these from a Trigger branch on session.status reaching ready, not once at workflow start. Subscribe is Baileys only; whatsapp-web.js answers 501 and never reports presence at all.

Set Own Presence has a side effect worth knowing: WhatsApp routes notifications away from the phone while a linked device is online, so a workflow-driven session left available suppresses the account holder's own alerts. Turn it off to hand them back. There is no read-back, and the setting resets on every reconnect.

Output and error handling​

On success, each input item produces one output item containing the OpenWA JSON response, with two exceptions. A route answering a bare JSON array emits one item per row on node version 2, each carrying pairedItem back to the input item that produced it; on node version 1 that array stays whole on the single item. And the two media reads, Message → Get Media and Status → Get Media, return raw bytes, which the node attaches as a binary property rather than putting on json, leaving that item's json empty. A DELETE that answers 204 No Content surfaces as { "success": true } so downstream nodes receive a readable item instead of an empty one.

List output depends on the node version

The action node declares versions 1 and 2. Version 2, which a newly added node gets, emits one item per row for a route answering a bare JSON array. Version 1 keeps the whole array on a single item's json, exactly as 0.10.0 did. n8n keeps a node's saved version across package upgrades, so a workflow built before 1.0.0 that reads {{ $json[0].id }} is unaffected by the upgrade and needs no change.

1.0.0 shipped the per-row output under version 1, so a node added while on 1.0.0 carries version 1 too and returns to the whole array once the package is upgraded to 1.0.1. Delete and re-add that node to move it to version 2.

On version 2:

  • {{ $json[0].id }} becomes {{ $json.id }}, evaluated once per row.
  • {{ $json.length }} becomes {{ $('OpenWA').all().length }}.
  • A Code node reading $input.first().json as the array reads $input.all().map(item => item.json), or switches to Run Once for Each Item and reads $json.
  • A Split Out node placed after the operation to fan the array out is redundant, and fails because it has no field left to point at. Remove it.

An empty list emits zero items on version 2, not one holding [], so the next node does not run at all. Turn on Always Output Data where a branch must continue past an empty result, and drop any {{ $json.length === 0 }} check, which no longer has an item to run on. With several input items the output is one flat list: three input items listing ten chats each produce thirty items.

The nineteen affected operations: Session → List All; Chat → List; Contact → List and List Blocked; Group → List and Get Membership Requests; Message → Get History and Get Reactions; Label → List, Get Chats and Get for Chat; Template → List; Channel → List and Get Messages; Webhook → List, List All and Get Delivery Failures; Automation Rule → List; API Key → List.

Contact → List Blocked answers bare id strings, and a string is not valid item json, so on version 2 each row arrives wrapped: { "data": "628123456789@c.us" }. Version 1 passes the bare array of strings through untouched.

Operations answering an envelope keep their single item and their nested array on both node versions, because spreading the rows would lose the envelope's own fields: Message → List ({ messages, total }), System → Search, System → Get Audit Log, Status → List and Get by Contact, Contact → Get Profile Pictures, and Catalog → List Products, whose pagination would be lost with it.

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​

FieldTypeRequiredNotes
Session Name or IDoptionsYesSession to receive events from, chosen from the same dropdown the action node uses. Sanitized like the action node (no empty, .., /, or \).
EventsmultiOptionsYesEvents to subscribe to. Default ['message.received']. At least one is required.
Webhook Secretstring (password)NoShared secret for signature verification, at least 16 characters. The node checks the length itself before registering, so a short one fails at activation rather than as a server 400. See Signature verification.
FiltersjsonNoServer-side filters, {"conditions":[{"field":"type","operator":"is","value":["text"]}]}. The gateway drops a non-matching event before delivering, so it never starts an execution. Conditions are ANDed, at most 20. Fields: sender, recipient, body, type, isGroup, kind, fromMe, hasMedia, mentions. kind (server v0.23.4+) is the only way to single out or exclude a Channel post, which isGroup reports as false along with everything else. Filters narrow message events only: session, group and call events arrive regardless. Within the message family an is condition on a field an event does not carry suppresses that event outright, so a sender filter combined with a Message Ack subscription drops every ack. A filtered-out delivery is silent, so an over-strict filter looks exactly like nothing having happened.
Deduplicate DeliveriesbooleanNoDefault off. Drops a repeated delivery of the same idempotencyKey, remembering the 500 most recent keys 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 carries the session (…/webhook/openwa-<sessionId>), so a glance at the URL says which session it serves. What keeps two Triggers apart is the prefix n8n puts in front of that path: the node's own webhook id, or the workflow id plus the node name when the node has none. That prefix is per node instance, so even two Triggers on the same session inside one workflow get distinct delivery URLs. The session segment is there for legibility, not isolation.

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, session, and filters 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 with POST /api/sessions/{sessionId}/webhooks if it does not. A 404 there means recreate; any other error is inconclusive, so it propagates rather than risking a duplicate registration, which the server would not de-duplicate by URL.
  • Existing is not the same as delivering, so the node also checks the registration it read back. The server dispatches only to webhooks with active: true, and the URL, the event list, and the filters can all be edited out from under the node, from the dashboard, the API, or the action node's own Webhook → Update. Any of those would leave the trigger reporting healthy while nothing reached it, so a drifted registration is deleted and rebuilt exactly like a stale one. Filters are compared ignoring key order, since the server round-trips them through a JSON column. The secret is the one registered field not compared: the server never serializes it back, and the config hash already catches a local change to it.
  • On deactivate, the node issues DELETE /api/sessions/{sessionId}/webhooks/{webhookId}. A 404 is treated as already deleted; any other error propagates so activation fails loudly rather than orphaning a registration that would keep delivering.
Re-registering after a configuration change

Changing the secret, the events, the filters, or the session takes effect on the next activation — deactivate and reactivate the workflow, and the node re-registers automatically. Editing the registration on the server has the same effect in reverse: the node notices on the next activation and rebuilds it from the workflow's own configuration. 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 1.0.1 offers all twenty-three events the gateway dispatches.

EventFires when
message.receivedA new message is received.
message.sentA message is sent successfully.
message.ackA message delivery or read acknowledgement occurs.
message.failedA message fails to send.
message.revokedA message is deleted for everyone.
message.editedA message's text, or a media message's caption, is edited. The payload carries the new text and a hasMedia flag, never replacement media: WhatsApp cannot edit the attachment itself.
message.reactionA reaction is added to or removed from a message.
status.receivedA contact's Status (Story) is received.
session.statusAny session status change.
session.qrA new QR code is generated.
session.authenticatedThe session is authenticated.
session.disconnectedThe session loses connection.
session.reconnect_loopA session is stuck in a reconnect loop — once per 5 consecutive attempts.
session.restrictionWhatsApp places or lifts a restriction on the account.
presence.updateA 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.joinA participant joins a group the session belongs to.
group.leaveA participant leaves a group the session belongs to.
group.updateA group's metadata or participant roster changes.
group.join_requestSomeone asks to join a group the session administers. Fires only when the group has admin approval enabled.
call.receivedAn incoming WhatsApp call is detected. Both engines.
call.acceptedAn incoming call is answered. Baileys only.
call.rejectedAn incoming call is declined, including by auto-reject. Baileys only.
call.missedAn incoming call goes unanswered. Baileys only.
The call outcomes fire on one engine 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.16.0 package floor covers the whole catalog. See Compatibility.

group.join_request joined this catalog in package 0.9.2; core has dispatched it since v0.15.0. On 0.9.1 it is absent, and because the trigger and the Webhook → Create and Update operations share this one list, no node offers it there. On that version, register the subscription by hand with n8n's HTTP Request node against POST /api/sessions/{sessionId}/webhooks, pointing it at an n8n Webhook node's URL.

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.

FieldDescription
eventThe event name, for example message.received.
timestampISO 8601 time the event was emitted, for example 2024-01-15T10:30:00Z.
sessionIdSession the event belongs to.
idempotencyKeyStable key for the logical event.
deliveryIdIdentifies a single delivery attempt. Re-minted on a crash replay, so it is not a dedup key.
dataThe 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 use id, not messageId.
  • OpenWA delivers at least once: a failed POST is retried and a crash-stranded delivery is replayed, both under the same idempotencyKey. De-duplicate on that key if your downstream actions are not idempotent, either with the node's Deduplicate Deliveries toggle or a Remove Duplicates node. Do not key on deliveryId: a replay carries a new one.
  • Message type is engine-neutral: voice notes are voice, shared contacts are contact, and plain chats are text.
  • Some payloads carry extra fields under data: type: "masked" marks a withheld business message, and a message.revoked event carries revokedId, 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 as X-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 401 rather 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​

SymptomCauseFix
Credential test fails on saveAPI key rejected by GET /api/sessionsUse a valid key from the dashboard; see Authentication.
Session ID contains invalid charactersSession id has .., /, or \Pick the session from the dropdown, or supply its UUID from an expression.
Chat ID cannot be emptyMessage sent with no Chat IDProvide a chat id like 628123456789@c.us.
Phone number must contain only digitsCheck Exists got non-digit input that survived strippingPass digits only, for example 628123456789.
Base64 image or document rejected by OpenWAMissing MIME type on a base64 payloadSet the MIME Type field, or use the Binary Data or URL source.
400 when creating a webhookThe server does not know one of the selected eventssession.restriction, presence.update, call.accepted, call.rejected, and call.missed need OpenWA ≥ 0.14.0; group.join_request needs ≥ 0.15.0. Upgrade the gateway, or deselect the events it does not know.
404 on one operation while the rest workThe route postdates the serverSession → Get Proxy and Update Proxy need a server on v0.23.4 or newer; every other route the node calls exists from v0.16.0. See Compatibility.
A call-outcome trigger never runsThe session runs whatsapp-web.jscall.accepted, call.rejected, and call.missed are Baileys-only. Use call.received, which fires on both engines.
Trigger fires once and then goes quietThe webhook was registered against n8n's test URL, which stops after one deliveryActivate the workflow so the trigger registers its production URL.
Trigger subscribed to a group event never runsThe session isn't a member of any group, or no group activity has occurredConfirm 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 deliverySignature mismatch between server and node secretsUse the same Webhook Secret on both sides; reactivate the workflow after changing it.
403 on an operation that used to workThe credential's role is too low, or its session scope is too narrowWrites need an OPERATOR key, and so do several reads: Session → Get QR, Template → List and Get, Webhook → Get, List and List All, System → Search, and every Automation Rule operation. The API Key resource (except Validate), System → Get Settings, Get Audit Log, Get Stats Overview and Get Message Stats, and Webhook → Get Delivery Failures need an ADMIN key. Separately, a session-scoped key is refused outright on the API-key operations, on System → Get Settings, Get Stats Overview and Get Message Stats, and on Session → Create and Update Proxy, whatever its role.
409 on Request Pairing CodeThe session has not reached qr_ready yet, or a code was already acceptedRun Session → Get Status until status is qr_ready, then request the code; after a code is accepted, wait for ready.
502 or 503 on System → SearchA plugin search provider is active and misbehaved503 means it did not answer, so wire n8n's retry-on-fail; 502 means it answered with an unusable shape and retrying will not help. The built-in provider returns neither.

Compatibility​

This package targets a self-hosted OpenWA server ≥ 0.16.0, verified against v0.23.4. Two things set that floor independently.

The routes the action node calls set it at v0.16.0, where Call → Create Link arrived. Most of the rest of the surface landed in v0.14.0 (message pin, star and vote; chat archive and clear; presence; media conversion; voice statuses; group pictures and join preview; channel administration; label writes; automation rules). Session config followed in v0.14.5, membership requests and the blocklist read in v0.15.0, and chat mute and pin in v0.16.0 alongside the call link. Two operations sit above the floor: Session → Get Proxy and Session → Update Proxy need ≥ 0.23.4, where the per-session proxy became readable and patchable rather than fixed at creation. Against an older server those specific operations answer 404 and everything else keeps working.

The event catalog is what actually sets 0.15.0. group.join_request does not exist in core before v0.15.0, and session.restriction, presence.update, call.accepted, call.rejected and call.missed do not exist before v0.14.0 — a v0.14.x server knows 22 events, not 23 — and the server validates a webhook registration against its own event list, so a Trigger subscribing to any of the six is refused at registration rather than degrading quietly. That is a harder failure than a 404 on one operation. Package 0.9.1 and earlier could not select group.join_request at all, so their effective floor was 0.14.0.

Since the routes now set the higher of the two, 0.16.0 is the supported floor for 1.0.1.

Next steps​