Message
Subscribes the tenant's Meta app to a WhatsApp Business Account on publish and starts one run per message, verified against Meta's X-Hub-Signature-256.
Start a run when a WhatsApp Business number receives a message, a delivery or read receipt, or an account notification from Meta.
Connection
- Required
- Yes — the node will not save without one
- Auth type
- API key
- Providers
- WhatsApp Business
- Secret shape
- {"access_token", "app_id", "app_secret"}
- Resolved by
- config.connection_id, else node.connection_id
- Note
- Three values, and they are not interchangeable. The access token (a System User token with whatsapp_business_management on the WABA) subscribes the business account; the app id owns the webhook subscription; the app secret is what every delivery is signed with. Publishing also needs MANTLE_APP_PUBLIC_BASE_URL set to an https URL Meta can reach — Meta refuses a callback it cannot validate.
Configuration
2 fields, none required. A dotted path is a nested object and name[] an array of objects — the editor renders the same tree.
| Field | Type | Required | Default | Constraints | Example |
|---|---|---|---|---|---|
business_account_id The numeric WhatsApp Business Account (WABA) id to watch — from Meta Business Manager, not the phone number id. Leave empty to use the one on the connection. | string | No | — | matches ^\d{5,}$ | 102290129340398 |
fields WABA webhook fields to subscribe to. 'messages' carries both inbound messages and the receipts for sent ones; any field Meta publishes on this object is accepted, not only the ones listed. | array | No | ["messages"] | 1–32 characters; array of string | — |
Example configuration
Every value below is the contract’s own example or default — nothing invented.
{
"business_account_id": "102290129340398",
"fields": [
"messages"
]
}Output
One shape.
whatsapp event
One message, receipt or account notification. `value` carries Meta's own payload, whose keys differ per message type, so the shape is open below the declared fields.
Extra keys beyond the ones listed can appear.
| Field | Type | Example |
|---|---|---|
waba_id The WhatsApp Business Account the event belongs to — Meta's `entry.id`. | string | 102290129340398 |
field The WABA webhook field that delivered it, e.g. messages or message_template_status_update. | string | messages |
kind message = somebody wrote to the business; status = a receipt for a message the business sent; change = an account-level notification. Branch on this before reading the fields below. | string | message |
message_id WhatsApp's own message id (wamid.…) — of the inbound message, or of the sent message a status refers to. Empty on account-level changes, and the idempotency key everywhere else. | string | wamid.HBgLMzE2MTIzNDU2NzgVAgASGBQzQTRCQ0RFRjEyMzQ1Njc4OUFCAA== |
message_type text, image, audio, video, document, sticker, location, contacts, button, interactive, reaction, order, system… Empty unless kind is message. | string | text |
text The message body, or the caption of a media message. Empty for message types that carry no text — read `value` for those. | string | Does it come in another color? |
from_number Who sent the inbound message, in WhatsApp's digits-only form (no +). Pass it straight to whatsapp.send_message to reply. | string | 31612345678 |
contact_name The sender's WhatsApp profile name, where they have one. | string | — |
status sent, delivered, read or failed — only when kind is status. | string | delivered |
recipient_id Who the status is about: the customer the business messaged. | string | — |
phone_number_id The business number that received (or sent) it — the Graph id, which is what the send nodes take, not the display number. | string | 106540352242922 |
display_phone_number The same business number as a human reads it. | string | 31612345678 |
timestamp When WhatsApp recorded the event, epoch seconds (Meta sends it as a string; it is parsed here). | number | 1717070400 |
received_at The same instant as an ISO-8601 UTC string, for nodes that want a date. | string | 2024-05-30T12:00:00Z |
value Meta's own change value, verbatim: metadata, contacts, and the whole messages/statuses array this event came out of. | object | — |
payload The entry the event arrived in, with every change it carried. | object | — |
{
"contact_name": "Kerry Fisher",
"display_phone_number": "31612345678",
"field": "messages",
"from_number": "31612345678",
"kind": "message",
"message_id": "wamid.HBgLMzE2MTIzNDU2NzgVAgASGBQzQTRCQ0RFRjEyMzQ1Njc4OUFCAA==",
"message_type": "text",
"payload": {
"changes": [],
"id": "102290129340398"
},
"phone_number_id": "106540352242922",
"received_at": "2024-05-30T12:00:00Z",
"recipient_id": "",
"status": "",
"text": "Does it come in another color?",
"timestamp": 1717070400,
"value": {
"contacts": [
{
"profile": {
"name": "Kerry Fisher"
},
"wa_id": "31612345678"
}
],
"messages": [
{
"from": "31612345678",
"id": "wamid.HBgLMzE2MTIzNDU2NzgVAgASGBQzQTRCQ0RFRjEyMzQ1Njc4OUFCAA==",
"text": {
"body": "Does it come in another color?"
},
"timestamp": "1717070400",
"type": "text"
}
],
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "31612345678",
"phone_number_id": "106540352242922"
}
},
"waba_id": "102290129340398"
}Notes
- Publishing points this WABA's webhooks at Mantle with Meta's per-WABA override, so a Meta app that already delivers elsewhere keeps doing so for everything except this business account. Unpublishing removes the override and the deliveries go back to the app's own callback.
- Meta validates the callback with a GET carrying hub.challenge. Mantle's provider ingress answers POST only, so registration fails with Meta's "URL couldn't be validated" until that route serves GET.
- Every delivery is verified against X-Hub-Signature-256, an HMAC-SHA256 over the raw body keyed on the app secret; an unsigned or mis-signed POST is refused with 401 before any run starts.
- One delivery can batch several messages and several receipts; each becomes its own run, deduped on WhatsApp's wamid (plus the status name for a receipt, since sent/delivered/read share one id).
- Replying to an inbound message is only free-form inside WhatsApp's 24-hour window; outside it, whatsapp.send_template is the only thing that reaches the customer.
Related WhatsApp Business nodes
See Message run in a workflow.
In a technical demo we add the WhatsApp Business connection, drop the node on the canvas and let Workflow Health pre-flight it before the first real run.