Receive events with webhooks
Events, request format, signature check and retries. Available on Team and Business.
A webhook sends an HTTPS POST to your server when something happens in your workspace, for example when a conversation starts or a contact changes. Set them up under Settings → Workspace → API & webhooks → Add webhook.
Webhooks are part of the Team plan (5 endpoints) and the Business plan (25 endpoints). Only owners and admins can manage them.
Events
| Event | Sent when |
|---|---|
conversation.created |
A conversation starts |
conversation.updated |
Status, assignment or labels of a conversation change |
conversation.closed |
A conversation is resolved |
message.created |
A new message arrives or is sent. Internal notes are not included. |
contact.created |
A contact is saved |
contact.updated |
A contact changes |
rating.created |
A visitor rates a conversation |
Send test sends a webhook.test event to check your endpoint. You can't subscribe to it.
The request
Every request is a POST with a JSON body:
{
"id": "cm3x9…",
"event": "conversation.created",
"createdAt": "2026-11-06T09:12:44.120Z",
"workspaceId": "cm1a2…",
"data": { }
}
data holds the object the event is about. To see its exact fields, open the webhook, go to Deliveries and look at Sent for any delivery.
Headers:
| Header | Value |
|---|---|
X-Asktrix-Event |
The event name |
X-Asktrix-Delivery |
The delivery ID. It's the same as id in the body and doesn't change between retries. |
X-Asktrix-Signature |
t=<unix timestamp>,v1=<signature> |
User-Agent |
asktrix-webhooks/1 |
Answer with any 2xx status within 10 seconds. Redirects are not followed and count as a failure.
Check the signature
Each webhook has its own Signing secret (it starts with whsec_). The signature is an HMAC-SHA256, in hex, of the timestamp, a dot, and the raw request body.
Check it before you trust the request:
- Read
tandv1from theX-Asktrix-Signatureheader. - Reject the request if
tis more than 5 minutes away from your server time. - Compute HMAC-SHA256 of
<t>.<raw body>with your secret. - Compare it with
v1in constant time.
Use the raw body exactly as received. If your framework parses the JSON first and you serialize it again, the signature won't match.
Node.js example:
import { createHmac, timingSafeEqual } from "node:crypto";
export function isValidAsktrixRequest(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.trim().split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const given = String(parts.v1 ?? "");
return given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
Rotate creates a new secret. The old one stops working immediately, so update your server right after rotating.
Retries
If a delivery fails (timeout, connection error or a status outside 2xx), we try again after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours. That's six attempts in total. A retry has the same id, so you can skip duplicates.
If your endpoint keeps failing (20 failed attempts in a row, and a delivery has used up all six attempts), the webhook is switched off and the owners and admins of the workspace get a notification. In practice that means hours of failures, not a short outage. Fix your endpoint, then switch the webhook back on with Webhook active.
Delivery log
Deliveries shows the last 30 days per webhook: status, attempts, duration, what we sent and what your server answered. Filter by Failed and use Resend to deliver a single event again.
Limits
- The endpoint URL must use
https://and be reachable from the internet. Private and local addresses are blocked. - Webhooks only fire while your workspace is on a plan that includes them. After a downgrade, your endpoints are kept but receive nothing.
For every event payload and verification code in Node.js, Python and PHP, see the webhook developer docs.