How WhatsApp webhooks actually work
Where WhatsApp events come from, what a delivery receipt really tells you, and why "receiving webhooks" means something different depending on the platform.
Webhooks are how WhatsApp tells you what happened after you sent a message. Getting them right is most of the difference between an integration that feels reliable and one that leaves your support team guessing.
The direction that matters
Meta does not send events to whoever sent the message. It sends them to a single callback URL configured on the WhatsApp Business Account. That URL belongs to one system, and every event for that account goes there.
This has a consequence worth understanding before you choose a platform: if a platform receives Meta’s webhooks on your behalf, then "can I receive webhook events?" splits into two very different questions. Does the platform receive events from Meta? And does it forward them on to your server?
Verifying that an event is real
A webhook endpoint is a public URL, so anyone can post to it. Meta signs every payload with an HMAC in the X-Hub-Signature-256 header, computed over the raw request body. Two implementation details catch people out:
- You must hash the raw bytes, not a re-serialised object. Parsing JSON and stringifying it again changes whitespace and key order, and the signature will never match.
- Reject anything that fails verification rather than logging and continuing, or the endpoint is decorative.
What the statuses mean
A message moves through sent, delivered and read, and can fail at any point. These are reports from Meta about what happened on WhatsApp’s side, not guarantees about a human:
- sent — accepted by WhatsApp for delivery.
- delivered — it reached the recipient’s device.
- read — the recipient opened the chat. Users can disable read receipts, so absence of read is not evidence of anything.
- failed — carries a reason from Meta, which is the part worth surfacing to your team.
Match events to messages with the message id
When you send a message you get back Meta’s message id — the wamid. Every later status event references that same id. Store it against your own record at send time, or you will have no way to connect a delivery event to the order, invoice or ticket it belongs to.
{ "statusCode": 200, "message": "Success", "data": { "id": 1842, "metaMessageId": "wamid.HBgLOTE5…", "status": "sent" }}Design for events arriving late, twice, or out of order
Webhook delivery is asynchronous and retried. Assume you may see the same event more than once, and that a read event can arrive before you have finished processing the delivered event. Make handlers idempotent, keyed on the message id and status, and never move a message backwards from read to delivered.
Want to manage your WhatsApp infrastructure?
WA Console handles WABA management, API integration, messaging visibility and webhook events from one place.
WA Console developer platform →