Webhooks
Guides

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:

Terminal
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:

EventFires when
conversation.createdA conversation is created.
conversation.updatedA conversation changes (status, assignment, …).
conversation.closedA conversation is closed.
message.createdA message is added to a conversation.
customer.createdA customer is created.
customer.updatedA customer is updated.
lead.capturedThe agent captures lead contact details.
ticket.createdA ticket is created.
ticket.updatedA ticket is updated.
ticket.resolvedA ticket is resolved.
sla.at_riskA ticket approaches an SLA target.
sla.breachedA ticket misses an SLA target.
agent.escalatedThe 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):

JSON
{
  "id": "cmc1a2b3…",
  "type": "message.created",
  "created_at": "2026-07-06T12:00:00.000Z",
  "data": { "object": "message", "id": "cmc1a2b4…" }
}
HeaderValue
Asks-Signaturet=<unix>,v1=<hmac> — verify this (below).
Asks-Event-IdThe event id (matches id in the body).
Asks-Event-TypeThe event type.
Asks-Webhook-IdThe delivery id.
User-AgentAsks-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:

JavaScript
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}/deliveries and replay one with POST /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.