Webhooks
Webhooks
Receive Asks events on your server in real time — event types, signed deliveries, verification, and retries.
Webhooks push events to your server as they happen — a new message, an escalation, a captured lead — so you can react without polling. Deliveries are signed, retried on failure, and logged so you can inspect and replay them.
Create an endpoint
Create endpoints from the dashboard at app.asks.app/integrations/webhooks, or via the API with the webhooks:manage scope:
curl https://api.asks.app/v1/webhook_endpoints \
-H "Authorization: Bearer ask_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/asks/webhooks",
"enabled_events": ["message.created", "agent.escalated"]
}'The response includes the signing secret (whsec_…) exactly once — store it securely. The URL must be HTTPS and is validated against internal, loopback, and metadata addresses at registration and again at every delivery.
Event types
Subscribe to specific events, or ["*"] for all:
| Event | Fires when |
|---|---|
conversation.created | A conversation is created. |
conversation.updated | A conversation changes (status, assignment, …). |
conversation.closed | A conversation is closed. |
message.created | A message is added to a conversation. |
customer.created | A customer is created. |
customer.updated | A customer is updated. |
lead.captured | The agent captures lead contact details. |
ticket.created | A ticket is created. |
ticket.updated | A ticket is updated. |
ticket.resolved | A ticket is resolved. |
sla.at_risk | A ticket approaches an SLA target. |
sla.breached | A ticket misses an SLA target. |
agent.escalated | The AI agent escalates to a human. |
The sla.* events fire when SLA tracking is enabled for the workspace. Their data is the ticket resource plus two extra fields: sla_metric (first_response, next_response, or resolution) and sla_due_at (the target that was at risk or missed).
The dashboard's Test action (or POST /webhook_endpoints/{id}/test) sends a synthetic ping event.
Deliveries
Events arrive as a POST with a JSON envelope; data carries the event's payload (for message.created, a message object shaped like the REST resource):
{
"id": "cmc1a2b3…",
"type": "message.created",
"created_at": "2026-07-06T12:00:00.000Z",
"data": { "object": "message", "id": "cmc1a2b4…" }
}| Header | Value |
|---|---|
Asks-Signature | t=<unix>,v1=<hmac> — verify this (below). |
Asks-Event-Id | The event id (matches id in the body). |
Asks-Event-Type | The event type. |
Asks-Webhook-Id | The delivery id. |
User-Agent | Asks-Webhooks/1.0 |
Respond with any 2xx within 10 seconds to acknowledge. Anything else counts as a failure.
Verify the signature
The Asks-Signature header is Stripe-style: t=<unix timestamp>,v1=<hex HMAC>, where the HMAC is HMAC-SHA256(secret, "{t}.{raw body}"). Verify against the raw request body and reject deliveries older than 300 seconds:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyAsksSignature(rawBody, header, secret, tolerance = 300) {
const parts = Object.fromEntries(
header.split(",").map((kv) => kv.split("=")),
);
const t = Number(parts.t);
if (!t || !parts.v1) return false;
if (Math.abs(Date.now() / 1000 - t) > tolerance) return false;
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(parts.v1, "hex");
const b = Buffer.from(expected, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}Compute the HMAC over the exact raw body bytes. Parsing and re-serializing the JSON changes the bytes and breaks verification — read the raw body before your framework's JSON middleware touches it.
Retries and auto-disable
- Failed deliveries retry with exponential backoff starting at 1 minute — up to 8 attempts per delivery.
- After 15 consecutive failed deliveries, the endpoint is automatically disabled and the workspace is notified by email. Re-enable it with
PATCH /webhook_endpoints/{id}and"status": "enabled", which also clears the failure counter. - Inspect attempts with
GET /webhook_endpoints/{id}/deliveriesand replay one withPOST /webhook_endpoints/{id}/deliveries/{deliveryId}/retry.
Roll the secret
If a signing secret leaks, POST /webhook_endpoints/{id}/roll_secret generates a new one (returned once). The old secret stops working immediately, so update your verifier in the same deploy.
Event log
An event is recorded whenever at least one enabled endpoint subscribes to its type — whether or not the delivery succeeded. Events no endpoint listens for are not stored. Browse the log with GET /events. All management endpoints are documented in the Webhook endpoints reference.