Receive webhooks
Rather than polling, give us a URL and we will POST events to it as they happen.
Set your callback URL
In the console, go to Settings → Console → Webhook endpoint:
- Put your public HTTPS URL in Endpoint URL.
- Turn Deliver events on.
- Copy the webhook signing secret and store it with your other secrets. Your handler needs it to prove an event is ours.
There is no API for any of this — an API key cannot change where your events go.
Nothing is delivered until the endpoint is set, so no events are queued up waiting for it. Set it before you need it.
The events
| Event | Fires when |
|---|---|
message.sent | We handed the message to WhatsApp |
message.delivered | It reached the device |
message.read | The user opened it |
message.failed | It will not arrive |
inbound.received | The user replied to you |
verify.delivered | A code reached the user |
verify.approved | A code was entered correctly |
verify.failed | A verification failed |
template.status_changed | Meta approved or rejected a template |
usage.threshold | A key passed 80% or 100% of its monthly limit |
inbound.received matters more than it looks: there is no endpoint that reads replies, so this
webhook is the only way to see one.
Every delivery is signed
The URL is public, and anyone who finds it can POST to it. Each delivery carries an
X-Msgeasy-Signature header that proves it came from us, and your handler must check it before
trusting the body.
How to check it, in each framework, is in Write a webhook handler.
The payload
{
"id": "msg:0f3a...:delivered",
"type": "message.delivered",
"sequence": 2,
"createdAt": "2026-09-06T10:35:00.000Z",
"data": { "messageId": "msg_...", "status": "delivered", "whatsappMessageId": "wamid..." }
}id is derived from the event, not random, so it is your dedupe key. sequence ranks the status.
Both matter because events can arrive twice and out of order —
Write a webhook handler shows how to handle that.
Delivery
Answer with a 2xx. A delivery that keeps failing is retried and then dropped — the schedule, and
what to check when nothing arrives, are in
Write a webhook handler.
If you need a second source of truth on a message, poll
messages.get as a backstop.