Trigger workflows from WhatsApp Business messages via Meta Cloud API webhooks.
The WhatsApp trigger receives messages from the Meta WhatsApp Business platform. Inbound messages from any phone arrive as a whatsapp_business_account webhook entry; the trigger flattens the first message and exposes the full envelope on <whatsapp1.raw>.
How to configure
- In Meta for Developers open your app â WhatsApp â Configuration â Webhook â Edit. Paste the Webhook URL as the Callback URL and pick a Verify Token (any random string you choose) â paste the same value into the trigger's verify-token field. Meta does a one-time GET handshake with
hub.mode=subscribe&hub.verify_token=<token>&hub.challenge=<n>; the trigger replies with thehub.challengeif the token matches. - Subscribe to the
messagesfield under Webhook fields (andmessage_statusif you want delivery receipts). Then under App settings â Basic copy the App Secret and paste it as the trigger's signing secret. Meta signs requests with HMAC-SHA256 over the raw body and sendsX-Hub-Signature-256: sha256=<hex>. The trigger default-denies unsigned or invalid-signed requests with401. - WhatsApp delivers a
whatsapp_business_accountentry containingchanges[].value.messages[]. The trigger flattens the first inbound message:<whatsapp1.from>(E.164 sender phone),<whatsapp1.text>(body),<whatsapp1.messageId>(wamid.*),<whatsapp1.phoneNumberId>(your business number that received it). The full envelope is on<whatsapp1.raw>. - Verify by sending a WhatsApp message to your business number from any phone. Expect a fire within ~2 seconds. Meta retries non-2xx for up to 7 days with exponential backoff â the trigger ACKs
200immediately and processes asynchronously. Test numbers added in the Meta dashboard work without a paid messaging tier.
Signature format
| Header | Value |
|---|---|
X-Hub-Signature-256 | sha256=<hex> HMAC-SHA256 over the raw request body using the App Secret |
The wamid.* from entry[0].changes[0].value.messages[0].id is the dedup key. Status updates (message_status) deliver under a different field and use the status id for deduplication.
Sample payload
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "102290129340398",
"changes": [
{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "15551234567",
"phone_number_id": "106540352242922"
},
"contacts": [
{
"profile": { "name": "Alex Chen" },
"wa_id": "15555550100"
}
],
"messages": [
{
"from": "15555550100",
"id": "wamid.HBgLMTU1NTU1NTAxMDAVAgARGBI5RkMzQjZCNkVDQTk0RDk5MEUA",
"timestamp": "1745700000",
"text": { "body": "Hi, I need to reschedule my appointment." },
"type": "text"
}
]
}
}
]
}
]
}Verify with the bundled scripts
bun apps/sat/tests/staging/triggers/whatsapp/verify.ts \
https://mybotbox.com/api/webhooks/trigger/<path> \
--secret=<meta-app-secret>python3 apps/sat/tests/staging/triggers/whatsapp/verify.py \
https://mybotbox.com/api/webhooks/trigger/<path> \
--secret=<meta-app-secret>Source: apps/sat/tests/staging/triggers/whatsapp/.
Troubleshooting
- Webhook verification fails on save in Meta dashboard â the verify token in the trigger does not match what you typed in the dashboard. Both fields are case-sensitive; retype rather than copy-paste if special characters could be invisible whitespace.
401after verification succeeded â App Secret mismatch. App Secret lives under App settings â Basic and is distinct from the temporary access token shown in WhatsApp â API setup. Don't confuse them.- Workflow doesn't fire on real WhatsApp messages â either the receiving number is not subscribed to the
messagesfield, or your test phone is not in the Meta dashboard's allowlist (required while in dev mode). Add the phone under WhatsApp â API setup â Add phone number. - Duplicates â Meta retries non-2xx for 7 days. The trigger ACKs
200immediately and dedupes onwamidviawebhook_event_dedup.