Skip to content

API

Webhooks

Webhooks push events to your server as they happen: a conversation starts, a customer asks for a human, a document finishes processing. Create endpoints under Developer → Webhooks.

Events

FieldTypeDescription
conversation.startedeventA new conversation began (widget or API).
conversation.finishedeventA conversation was resolved or went idle.
human.requestedeventAn end user asked for human handoff.
document.uploadedeventA document was added and queued for processing.
document.processedeventIngestion finished; the document is searchable.
document.failedeventIngestion failed — the payload includes the error.
knowledge.syncedeventA website crawl completed and the index was refreshed.
feedback.submittedeventAn end user rated an assistant answer.
api_key.createdeventA new API key was created in your organization.

Subscribe an endpoint to specific events or to * for everything.

Delivery format

Deliveries are POST requests with a JSON body:

json
{
  "id": "evt_8f2c1a...",
  "event": "human.requested",
  "createdAt": "2026-07-12T10:30:00.000Z",
  "data": {
    "conversationId": "cm_abc123",
    "projectId": "cm_prj789",
    "reason": "Wants to change billing address",
    "customerEmail": "jane@example.com"
  }
}

Verifying signatures

Every delivery is signed with your endpoint's secret (whsec_..., shown when you create the endpoint). The X-KB-Signature header contains sha256=<hex digest> — an HMAC-SHA256 of the raw request body. Always verify before trusting a payload:

verify.ts
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyWebhook(rawBody: string, header: string, secret: string) {
  const expected = "sha256=" +
    createHmac("sha256", secret).update(rawBody).digest("hex");
  return (
    header.length === expected.length &&
    timingSafeEqual(Buffer.from(header), Buffer.from(expected))
  );
}

// Express example — use the raw body, not the parsed JSON:
// app.post("/webhooks/asklify", express.raw({ type: "*/*" }), (req, res) => {
//   const ok = verifyWebhook(req.body.toString(), req.get("X-KB-Signature")!, secret);
//   if (!ok) return res.status(401).end();
//   const event = JSON.parse(req.body.toString());
//   res.status(200).end();
// });
Compute the HMAC over the raw request body exactly as received. Parsing and re-serializing the JSON first will change key ordering or whitespace and break the signature.

Responding and retries

Respond with a 2xx within a few seconds — do slow work asynchronously after acknowledging. Failed deliveries are retried with backoff; endpoints that keep failing are visible (with delivery logs) under Developer → Webhooks, where you can also rotate secrets or disable an endpoint.

Best practices

Make handlers idempotent (dedupe on the delivery id), verify signatures before any processing, and use one endpoint per environment so staging events never hit production.