Webhooks
You don't configure any callback on Meta. We receive every event from the connected accounts, validate Meta's signature and redeliver to the endpoints you register.
The delivery body
It's Meta's envelope, byte for byte. Handlers already written for the Cloud API work unchanged.
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "111222333444555",
"changes": [
{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "5541987111527",
"phone_number_id": "106540352242922"
},
"messages": [
{
"from": "5541999999999",
"id": "wamid.HBgNNTU0MTk5OTk5OTk5OQ...",
"timestamp": "1785312000",
"type": "text",
"text": { "body": "Hi, did my order ship?" }
}
]
}
}
]
}
]
}
Headers on every delivery
| Header | Contents |
|---|---|
X-Joinotify-Signature-256 | sha256=<hex> — the delivery's HMAC |
X-Joinotify-Timestamp | Unix seconds, included in the HMAC |
X-Joinotify-Event | Event name, e.g. messages |
X-Joinotify-Delivery | Delivery ID, stable across retries |
User-Agent | Joinotify-Webhook/1.0 |
Three rules that prevent most problems
Answer 2xx first, process afterwards. The timeout is 20 seconds. A handler that
writes to the database, calls three APIs and only then responds will blow up in
production.
Validate the signature against the raw body. If you let the framework parse the JSON first, the signature will never match.
Be idempotent. A delivery can repeat. Deduplicate by X-Joinotify-Delivery or by the
message wamid.
Where to go next
- Configure — register, filter and test endpoints.
- Verify the signature — the HMAC, with examples in Node, Python and PHP.
- Event catalogue — the 20 events and what each one carries.
- Delivery and retries — timeouts, backoff and the delivery log.