Webhooks
Webhooks send an HTTPS request to your URL when something happens in DeskAI, so another system can react without polling the REST API.
Add a webhook
- Go to Admin Portal → Webhooks (MSP admins) or API & webhooks (company admins), and click Add webhook.
- Enter the URL, a secret, and the events to send.
- Use Test to send a signed test event. The list shows the last response each webhook got.
A company’s webhooks receive events for its own tickets. Webhooks an MSP admin adds receive events for every ticket in the workspace.
Events
| Event | Sent when |
|---|---|
ticket.created | A new ticket has been through triage and routing, from any channel |
ticket.assigned | A ticket is assigned to an agent, by a person, by smart routing or through the API |
ticket.resolved | A ticket is resolved |
reply.sent | A reply is sent to the requester |
csat.submitted | The requester rates how it went |
Payload
Each event is a POST with a JSON body. data.ticket has the same fields as the REST API’s ticket; reply.sent adds data.message and csat.submitted adds data.csat.
{
"id": "5b0e6c1e-7d7f-4a52-9a53-3f1a9d7f2c10",
"event": "ticket.resolved",
"createdAt": "2026-09-16T14:02:11.000Z",
"data": {
"ticket": { "id": 1042, "subject": "Disk almost full on FS-02", "status": "resolved", ... }
}
}Verify the signature
With a secret set, each request has an X-DeskAI-Signature header like t=1789567331,v1=5f2c…. Compute an HMAC-SHA256 of the timestamp, a full stop and the raw request body with your secret, and compare it with v1. Reject requests whose timestamp is more than five minutes old.
import { createHmac, timingSafeEqual } from "crypto";
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac("sha256", secret).update(t + "." + rawBody).digest("hex");
return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Delivery
DeskAI waits up to 8 seconds for your endpoint to answer with a 2xx status, and tries each event once. The X-DeskAI-Event header names the event.