Webhooks
Subscribe to events and react in real time.
Webhooks
Webhooks push events to your HTTPS endpoint as things happen in your workspace — new tickets, replies, status changes — so you can sync to your own systems without polling.
Manage endpoints
Two ways to register an endpoint:
- Admin UI — Admin → Developer Portal → Webhooks: add your URL, pick events, copy the generated signing secret. Deliveries and retries are visible there too.
- API — the
webhook-managerfunction exposesGET/POST/PUT/DELETE /endpoints,POST /endpoints/:id/test,GET /deliveriesandPOST /deliveries/:id/retry. Authenticate with an API key that has thewebhooksoradminscope (x-api-keyheader).
Events
ticket.created,ticket.updated,ticket.resolved,ticket.reopened,ticket.assignedticket.replied,ticket.replied.customer,ticket.replied.agent— agent replies carry the reply body inline indata.reply.messageand are emitted for human agents, AI replies and API replies alike.customer.created,customer.updatedchat.started,chat.ended,chat.messagecsat.submitted,csat.ratedarticle.published,article.updatedwebhook.test— sent by the endpoint test button.
Payload
POST https://your-app.com/webhooks/answerridge
X-AnswerRidge-Event: ticket.replied.agent
X-AnswerRidge-Timestamp: 1727350000
X-AnswerRidge-Signature: sha256=<hmac-hex>
{
"id": "evt_<event id>",
"type": "ticket.replied.agent",
"tenant_id": "…",
"created_at": "2026-09-26T12:00:00Z",
"data": {
"ticket": { "id": "…", "ticket_number": 15, "subject": "…", "email": "…" },
"reply": { "id": "…", "message": "…", "sender_type": "agent", "sender_name": "…" }
}
}
Verify the signature
Recompute HMAC-SHA256(signing_secret, "${X-AnswerRidge-Timestamp}.${raw body}") and compare hex with the value after sha256= in X-AnswerRidge-Signature (constant-time compare). Reject timestamps more than ~5 minutes old to prevent replay.
// Node.js
import crypto from "node:crypto";
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.AR_SIGNING_SECRET)
.update(`${req.headers["x-answerridge-timestamp"]}.${rawBody}`)
.digest("hex");
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-answerridge-signature"]));
Retries & idempotency
Non-2xx responses retry with backoff (up to 5 attempts). Deliveries are fire-and-forget for agents — a failing endpoint never blocks a reply. Make your handler idempotent: id repeats on retries, and reply events carry the stable data.reply.id, so dedupe on that. Return any 2xx quickly and process async.