Receive and verify WhatsApp Business Platform (Cloud API) webhooks from Meta. Use when setting up WhatsApp webhook handlers, completing the GET verification handshake, debugging X-Hub-Signature-256 signature verification, or handling inbound message and message status (sent, delivered, read, failed) events under the whatsapp_business_account object.
Receive and verify WhatsApp Business Platform (Cloud API) webhooks from Meta. Use when setting up WhatsApp webhook handlers, completing the GET verification handshake, debugging X-Hub-Signature-256 signature verification, or handling inbound message and message status (sent, delivered, read, failed) events under the whatsapp_business_account object.
Receive webhooks from the WhatsApp Business Platform (Cloud API), delivered by
Meta's Graph API. WhatsApp webhooks are Meta webhooks: they require a one-time
GET verification handshake and sign every POST with X-Hub-Signature-256.
They do not follow the Standard Webhooks spec.
When to Use This Skill
How do I receive WhatsApp webhooks?
How do I complete the WhatsApp / Meta webhook verification handshake (hub.challenge)?
How do I verify the WhatsApp X-Hub-Signature-256 signature?
Why is my WhatsApp webhook signature verification failing?
How do I handle inbound WhatsApp messages vs. message status updates?
Two Things Every Endpoint Must Do
GET handshake — When you register the endpoint, Meta sends a GET with
, , and . If the mode is
and the token matches your configured verify token, respond
with the raw value as the body (no JSON, no quotes).
hub.mode=subscribe
hub.verify_token
hub.challenge
subscribe
200
hub.challenge
POST signature check — Every event POST carries
X-Hub-Signature-256: sha256=<hex>. Compute HMAC-SHA256 over the raw request
body using your app secret and compare timing-safe.
Verification (core)
Compute HMAC-SHA256 over the raw bytes of the request body keyed on your Meta
app secret, then compare against the hex digest after sha256=. Use the raw
body exactly as received — Meta escapes non-ASCII characters (e.g. é), so
re-serializing parsed JSON produces a different, failing digest.
Meta's official whatsapp Node SDK is built for sending messages via the
Cloud API; it does not expose webhook HMAC verification, so verify manually with
the standard algorithm above (see references/verification.md).
For complete handlers with the GET handshake, event dispatch, and tests, see:
Dispatch by iterating entry[].changes[] and branching on change.field. For the
messages field, inbound user messages arrive in value.messages[] and
outbound status updates arrive in value.statuses[] — the same field carries both.
WHATSAPP_APP_SECRET=your_meta_app_secret # App Dashboard > App Settings > Basic > App Secret
WHATSAPP_VERIFY_TOKEN=your_own_random_string # You choose this; must match the dashboard value
Verify over the raw body — Meta escapes unicode; re-serialized JSON fails.
Dedupe by message/event id — retries (up to 7 days, decreasing frequency) go
to every subscribed app, and updates may batch up to 1000 entries per POST
(payloads up to 3 MB).
Two secrets — the app secret signs POSTs; the verify token is only for the
GET handshake. They are different values.
Live mode — some webhooks only fire when the app is in Live mode, and a valid
TLS certificate is required.
We recommend installing the webhook-handler-patterns skill alongside this one for handler sequence, idempotency, error handling, and retry logic. Key references (open on GitHub):
Handler sequence — Verify first, parse second, handle idempotently third
Idempotency — Prevent duplicate processing (dedupe by WhatsApp message/event id)
Error handling — Return codes, logging, dead letter queues
facebook-webhooks - Facebook, Instagram, and Messenger webhooks — same Meta Graph API mechanism; canonical reference for the shared handshake + X-Hub-Signature-256 verification
hookdeck-event-gateway - Webhook infrastructure that replaces your queue — guaranteed delivery, automatic retries, replay, rate limiting, and observability for your webhook handlers