Webhooks deliver real-time events to your URL as JSON POST requests. You configure webhooks per number on the Webhooks page in the dashboard or via POST /v1/webhooks — see the Receive Messages guide for setup and the Events reference for full payload schemas.
Events overview
| Group | Events |
|---|
| Outbound status | message.sent, message.delivered, message.read, message.failed |
| Inbound | message.received, message.reply, message.group, message.newsletter |
| Number lifecycle | number.created, number.connected, number.disconnected, number.removed |
| Voice calls (Meta only) | call.ringing, call.connected, call.ended, call.missed, call.permission_updated, calls (raw Meta envelope) |
A webhook only fires for events in its events list. An empty list dispatches nothing; use "*" to subscribe to every event.
Payload schema (v3)
Every message.* / number.* event arrives as:
{
"event": "message.sent",
"data": { }
}
All data fields are camelCase. Phone numbers are always E.164 with + (no device suffix, no @s.whatsapp.net/@lid). Timestamps are ISO 8601 in a single createdAt field. Normalized call.* events are flat (no data wrapper).
Correlation with the 202 response
POST /v1/messages/send responds HTTP 202 with id and correlationId. Use these to tie webhooks back to your send:
202 field | Webhook equivalent |
|---|
id | id on message.sent / delivered / read / failed (same value) |
correlationId | Repeats on outbound status events and on message.reply / message.received when correlated |
| (not in the 202) | WhatsApp messageId — first appears on message.sent |
On message.reply, quotedMessageId equals the messageId of your original message.sent, and contentReplied carries the quoted text.
The message.read event (and Read status in logs) only occurs when the recipient has WhatsApp read receipts enabled. Otherwise the lifecycle stops at message.delivered.
Delivery notes
number.disconnected is emitted after a health check confirms the disconnect — not on every brief connection flap.
- With data retention off (PII modes), conditional fields such as
content may be empty; IDs and timestamps always exist.
- Events the number’s provider cannot emit are silently dropped from a subscription.