Message

trigger.whatsapp_event
TriggerChat & messagingconnection requiredruns in-engine

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.

FieldTypeRequiredDefaultConstraintsExample
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.
stringNo—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.
arrayNo["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.

FieldTypeExample
waba_id
The WhatsApp Business Account the event belongs to — Meta's `entry.id`.
string102290129340398
field
The WABA webhook field that delivered it, e.g. messages or message_template_status_update.
stringmessages
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.
stringmessage
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.
stringwamid.HBgLMzE2MTIzNDU2NzgVAgASGBQzQTRCQ0RFRjEyMzQ1Njc4OUFCAA==
message_type
text, image, audio, video, document, sticker, location, contacts, button, interactive, reaction, order, system… Empty unless kind is message.
stringtext
text
The message body, or the caption of a media message. Empty for message types that carry no text — read `value` for those.
stringDoes 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.
string31612345678
contact_name
The sender's WhatsApp profile name, where they have one.
string—
status
sent, delivered, read or failed — only when kind is status.
stringdelivered
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.
string106540352242922
display_phone_number
The same business number as a human reads it.
string31612345678
timestamp
When WhatsApp recorded the event, epoch seconds (Meta sends it as a string; it is parsed here).
number1717070400
received_at
The same instant as an ISO-8601 UTC string, for nodes that want a date.
string2024-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.

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.