Browse sections
Webhooks
Get an HTTP request on your server the moment a conversation, message or contact changes, and verify it came from us.
A webhook sends a POST request to a URL on your server whenever something you chose happens in your workspace, such as a new message. You do not need to keep asking the API for changes.
Add a webhook
You need the Administrator role.
- Open Settings, then Integrations.
- On the Webhooks card (1), select Configure (2).
- Select Add new webhook.
- Enter the Webhook URL (1). It must be a public
httpsaddress on your server. - Optionally, enter a Webhook Name (2) so you can tell your webhooks apart.
- Under Events (3), tick the events you want.
- Select Create webhook (4).
- The webhook's Secret appears. Copy it to your server's settings, then select Done. You can see it again later in the webhook's edit form.
Events
The name in the payload's event field, and its label in the form:
conversation_created: Conversation Createdconversation_status_changed: Conversation Status Changed (open, resolved, pending, snoozed)conversation_updated: Conversation Updated (for example labels, assignee or attributes)message_created: Message created (incoming and outgoing messages, and private notes with"private": true; activity lines are not sent)message_updated: Message updated (for example a delivery status change)webwidget_triggered: Live chat widget opened by the usercontact_created: Contact createdcontact_updated: Contact updatedconversation_typing_onandconversation_typing_off: Conversation Typing On / Off
What arrives
The body is JSON, sent with Content-Type: application/json. It always has event and an account object; the rest depends on the event. A shortened message_created:
{
"event": "message_created",
"id": 9876,
"content": "Where is my order?",
"message_type": "incoming",
"private": false,
"created_at": "2026-10-29T08:15:02Z",
"account": { "id": 12, "name": "My Store" },
"inbox": { "id": 29, "name": "Store WhatsApp" },
"sender": { "id": 42, "name": "Sara", "phone_number": "+966500000000" },
"conversation": { "id": 123, "status": "open", "labels": [], "meta": { "assignee": null } }
}conversation.idis the number the inbox shows, the same one the API uses.account.idhere is the workspace's numeric ID, not theacc_ID in your URL.- The
…_updatedandconversation_status_changedevents addchanged_attributes, with each changed field's previous and current value.
Verify the signature
Every request carries three headers:
X-Hadir-Delivery: a unique ID for this delivery.X-Hadir-Timestamp: when it was sent, in Unix seconds.X-Hadir-Signature:sha256=followed by the HMAC SHA256, in hex, of the timestamp, a dot, and the raw body, keyed with the webhook's secret.
Compute the same value on your server from the raw body, before parsing it, and compare. In Node.js:
const crypto = require('crypto');
function isFromHadir(rawBody, headers, secret) {
const ts = headers['x-hadir-timestamp'];
const expected = 'sha256=' + crypto.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`).digest('hex');
const given = String(headers['x-hadir-signature'] || '');
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
return fresh && given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}In PHP: hash_equals('sha256=' . hash_hmac('sha256', $ts . '.' . $rawBody, $secret), $signature). Rejecting old timestamps, as above, stops someone from replaying a captured request.
Timeouts and retries
- Your server has 5 seconds to answer. Reply with any
2xxquickly, and do the slow work afterwards. - A delivery that times out or gets a non-
2xxanswer is not retried, and the dashboard does not show failed deliveries. If you must not miss anything, also check the API from time to time. - Deliveries can arrive out of order. Use
created_atand the IDs, not arrival order.
Note: webhooks keep working even if your plan later stops including the API; only adding or editing them is refused. Delete a webhook you no longer need from the same page.
Thanks for your feedback ✓
We got your note and will review the article with it in mind.