- Webhooks & events
- Practitioner
- Developers
Webhook Subscription
Also called: App webhook configuration · Callback URL and verify token · Webhook fields subscription · Application Subscriptions API
The app-level setup that tells Meta where to send WhatsApp webhooks: a callback URL, a verify token and the WABA fields you want to receive.
Reviewed
What is a webhook subscription?
A webhook subscription is the configuration on your Meta app that switches webhooks on. It has three parts: a callback URL (your public HTTPS endpoint), a verify token you choose, and the list of WhatsApp Business Account fields to receive — messages for inbound messages and statuses, plus fields such as message_template_status_update, account_update or phone_number_quality_update.
You set it in the App Dashboard under WhatsApp > Configuration (or Use cases > Customize > Configuration for apps built on the WhatsApp use case), or with the Application Subscriptions API: POST /{APP_ID}/subscriptions with object=whatsapp_business_account, callback_url, verify_token and fields, where {APP_ID} is your Meta App ID and the call uses an app access token. Setting or editing the URL or token triggers the webhook verification request, and the change is saved only if your endpoint echoes hub.challenge with a 200.
The subscription sets one default URL and one field list for every WhatsApp asset the app serves. It does not connect any account by itself: each WABA must also be attached to the app through the subscribed apps endpoint, POST /{WABA_ID}/subscribed_apps — a separate step and the most common reason a correctly configured endpoint receives nothing. A per-WABA or per-number exception to the default URL is a webhook override.
Key takeaways
- A webhook subscription is the app-level setting that tells Meta where to send WhatsApp webhooks and which fields to send.
- It has three parts: an HTTPS callback URL, a verify token you choose, and the WhatsApp Business Account fields to receive.
- Saving the URL or token triggers a verification GET; the change saves only if your endpoint echoes
hub.challengewith a 200. - Each WABA must also be attached with
POST /{WABA_ID}/subscribed_apps, or no events arrive for it. - Meta warns that some webhooks are not sent while an app is in Development mode, so switch it to Live.
Interactive stop
Tick off a subscription that actually delivers
9/9
ticked
- Required
- 7 / 7
- Optional
- 2 / 2
Events will flow
Every item ticked.
Events will flow. 9 of 9 ticked.
How does a webhook subscription work?
Stand up the endpoint
Publish a webhook endpoint: a public HTTPS URL with a valid CA-signed certificate — Meta does not support self-signed ones — that answers GET verification requests and POST events.
Choose a verify token
Pick a long random string, store it as a secret on the server, and use the same value in the subscription.
Save the callback URL
Enter the URL and token in WhatsApp > Configuration, or call
POST /{APP_ID}/subscriptions. Meta immediately sends thehub.challengeGET; the save succeeds only if your endpoint echoes it.Subscribe to fields
Tick
messagesplus the account fields your team acts on, or pass them as a comma-separatedfieldslist. Read the result back withGET /{APP_ID}/subscriptions.Attach each WABA
Call
POST /{WABA_ID}/subscribed_appswith a token that can manage that account. Until you do, the subscription has no account to send events for.Go Live and test
Switch the app to Live mode, send a test payload from the Configuration panel, then message the business number and watch a real
messagesPOST arrive.
Common mistakes with a webhook subscription
Configuring the app but not the WABA
The callback verifies and the fields are ticked, yet nothing arrives, because the WABA was never attached with
subscribed_apps. Check withGET /{WABA_ID}/subscribed_apps.Subscribing only to messages
You get conversations but miss template pauses, quality changes and account restrictions. Add the account fields your operations team acts on.
Leaving the app in Development mode
Meta warns that some webhooks are not sent while an app is in Dev mode. Switch it to Live before relying on production traffic.
Dashboard-only configuration
Hand-edited settings drift between staging and production and vanish when someone edits the wrong app. Manage the subscription through the API in a deploy step and verify it with a GET.
Changing the URL before the new endpoint is ready
Each edit of the URL or token runs a fresh handshake against the new values. Deploy the endpoint and its token first, then save, or the change is rejected.
A webhook subscription in code
# 1. Create or update the app-level subscription (app access token = {APP_ID}|{APP_SECRET})curl -X POST "https://graph.facebook.com/v26.0/{APP_ID}/subscriptions" \-d "object=whatsapp_business_account" \-d "callback_url=https://api.example.in/webhooks/whatsapp" \-d "verify_token={VERIFY_TOKEN}" \-d "fields=messages,message_template_status_update,phone_number_quality_update,account_update" \-d "access_token={APP_ID}|{APP_SECRET}"# -> {"success": true}, once your endpoint has echoed hub.challenge# 2. Read it backcurl "https://graph.facebook.com/v26.0/{APP_ID}/subscriptions?access_token={APP_ID}|{APP_SECRET}"# 3. Attach a WhatsApp Business Account so its events flow to the subscriptioncurl -X POST "https://graph.facebook.com/v26.0/{WABA_ID}/subscribed_apps" \-H "Authorization: Bearer {ACCESS_TOKEN}"
Steps 1 and 2 configure the app; step 3 connects an account. You need both.
A webhook subscription: key facts and limits
- Parts
- Callback URL, verify token, subscribed fields
- Object
- whatsapp_business_account
- API
- POST /{APP_ID}/subscriptions with an app access token
- Certificate
- Valid CA-signed TLS; self-signed not supported
- Saved when
- Your endpoint echoes hub.challenge with a 200
- Also required
- POST /{WABA_ID}/subscribed_apps for each WABA
- App mode
- Live — some webhooks are not sent in Dev mode
Why does a webhook subscription matter?
Every inbound message, delivery status and account alert depends on this one configuration. Subscribe to too little and you miss template pauses or quality drops; configure the app without attaching the WABA and nothing arrives at all; leave the app in Development mode and Meta warns that some webhooks will not be sent. Getting the subscription right — and keeping it in code rather than in someone's memory of the dashboard — is what makes webhooks dependable across environments.
Example: Subscriptions as code in Nagpur
A Nagpur logistics start-up keeps its webhook subscription in a deploy script. On each release it calls POST /{APP_ID}/subscriptions for its staging and production apps with messages, message_template_status_update and phone_number_quality_update, reads the list back with a GET and fails the deploy if a field is missing; its onboarding job calls subscribed_apps for every new franchise WABA. The check paid off when a teammate debugging in the dashboard unticked message_template_status_update on production — the next deploy failed loudly instead of hiding a template pause during the festive rush.
Webhook Subscription FAQs
Can staging and production share one webhook subscription?+
What is the difference between the webhook subscription and subscribed_apps?+
Can I set up the webhook subscription through the API instead of the dashboard?+
Do I need one subscription per phone number?+
Can different numbers send webhooks to different URLs?+
Best practices for a webhook subscription
- Use a different verify token per environment so a staging endpoint can never verify a production subscription.
- Keep the verify token separate from the app secret: the token only answers the handshake, while the app secret signs every POST.
- Read the subscription back after every change and alert if a field disappears.
- Return 200 for every field from day one, even before its handler exists.
- Write down which team owns each subscribed field and acts on its events.
Talk to InfiQ
From definition to your first message
InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.