To receive WhatsApp messages and delivery status on the WhatsApp Business (Cloud) API, you register an HTTPS callback URL and a verify token in Meta\'s App dashboard, subscribe to the messages webhook field, and answer Meta\'s one-time GET verification challenge by echoing back the hub.challenge value. After that, Meta sends every inbound message and status update to your URL as a POST request, which your server parses and acts on.
This is the step-by-step setup for India teams on Cloud API v24.0 in 2026 — verification, field subscriptions, payload handling and the security check most guides skip.
What a webhook does
A webhook is the inbound half of the API. Your outbound sends go to Meta over REST; everything coming back — a customer\'s reply, a "delivered" or "read" receipt, a template status change — arrives only if you have a webhook registered. No webhook means your automation is deaf: you can send but never know what happened. Pair this with the outbound setup in our WhatsApp Business API setup: step-by-step (India 2026).
Prerequisites
- A Meta App with the WhatsApp product added, plus a WhatsApp Business Account (WABA) and a phone number ID.
- A public HTTPS endpoint with a valid TLS certificate — Meta will not deliver to plain HTTP or a self-signed cert. For local testing, tunnel with a tool like ngrok.
- A verify token — any secret string you choose; you type the same value into the dashboard and your code.
Step 1 — Handle the GET verification challenge
When you save the webhook, Meta sends a GET to your URL with three query params: hub.mode, hub.verify_token and hub.challenge. Your job: check the token matches, then return the raw hub.challenge as plain text with HTTP 200.
// Laravel example
public function verify(Request $r) {
if ($r->query('hub_mode') === 'subscribe'
&& $r->query('hub_verify_token') === env('META_VERIFY_TOKEN')) {
return response($r->query('hub_challenge'), 200);
}
return response('Forbidden', 403);
}
If you return anything other than the exact challenge value, the dashboard shows "The callback URL or verify token couldn\'t be validated."
Step 2 — Register the callback URL and verify token
In your Meta App dashboard, open WhatsApp → Configuration → Webhooks, click Edit, and enter your HTTPS callback URL and the same verify token string. Meta fires the GET challenge immediately; a green tick confirms Step 1 worked.
Get a 1-minute BSP audit on WhatsApp
Drop your WhatsApp number — we line-item your current invoice against Meta India rates in under 60 seconds. India-hosted, DPDP-compliant.
Step 3 — Subscribe to webhook fields
Verification alone sends you nothing. On the same Configuration screen, subscribe to the messages field — that single field covers inbound messages and status callbacks (sent, delivered, read, failed). Subscribe only to what you consume; extra fields just add noise.
Step 4 — Handle the POST payload
Meta now POSTs a JSON envelope to your URL. The shape is nested: entry[].changes[].value. Inside value you get either a messages array (someone messaged you) or a statuses array (an update on a message you sent).
{
"entry": [{
"changes": [{
"value": {
"metadata": { "phone_number_id": "1019255067941899" },
"messages": [{
"from": "9199XXXXXXXX",
"id": "wamid.XXXX",
"type": "text",
"text": { "body": "Hi, need a demo" }
}]
}
}]
}]
}
Always return HTTP 200 fast, then process asynchronously (push to a queue). If your handler is slow or errors, Meta retries the same payload with backoff and can temporarily throttle delivery — see WhatsApp Cloud API rate limits and throttling (India 2026).
Step 5 — Verify the payload signature
Anyone who learns your URL can POST fake events. Meta signs every request with an X-Hub-Signature-256 header — an HMAC-SHA256 of the raw body keyed with your App Secret. Reject any request whose computed signature does not match. Skipping this check is the most common security hole in DIY webhook setups.
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, env('META_APP_SECRET'));
if (!hash_equals($expected, $request->header('X-Hub-Signature-256'))) {
abort(403);
}
Common errors
- "Callback URL couldn\'t be validated" — your GET handler is not returning the raw
hub.challenge, or the verify token differs by a character. - Verified but no messages arrive — you forgot Step 3; subscribe to the
messagesfield. - Duplicate processing — Meta retries on non-200 or timeout. Deduplicate on the message
id(wamid…) so a retry does not double-fire your flow. - Works locally, fails in production — TLS cert invalid or the endpoint behind auth. Meta needs an openly reachable HTTPS URL.
Skip the plumbing
You do not have to build any of this. RichAutomate manages webhook registration, signature verification, retries and payload parsing for you, and surfaces inbound messages and statuses through a clean dashboard and public API — on a ₹0-setup, usage-only model. Start on a free WhatsApp Business API tier and pay only Meta\'s per-message charge once you go live.