Webhooks API
Receive signed Klarefi events, send test deliveries, and acknowledge handoff delivery
Klarefi delivers signed events to webhook endpoints registered in the dashboard. Use webhooks as integration signals, then read the current case or package when your system needs canonical state.
Use your workspace API base URL
Set
KLAREFI_API_BASE_URLto the value in Settings → Developer before using API examples. Current workspaces may use ahttps://<deployment>.convex.siteURL.
v1.webhook.test is emitted only by the test endpoint. Subscription events use
the catalog names in the dashboard, such as v1.intake.submitted and
v1.case.completed.
Event shape
{
"event_id": "evt_01J7W9S4TSQ0T4SH43JYB9W5R8",
"delivery_id": "whd_01J7W9S52C2ZK1XFY2GM7Z7SAK",
"event_type": "v1.case.completed",
"semantic_event_type": "case.completed",
"schema_version": "v1",
"created_at": "2026-05-01T12:34:56.000Z",
"occurred_at": "2026-05-01T12:34:50.000Z",
"org_id": "org_abc123",
"case_id": "case_abc123",
"session_id": null,
"external_case_id": "claim_12345",
"external_applicant_id": "applicant_789",
"external_customer_id": "customer_456",
"idempotency_key": "session_claim_12345",
"trace_id": "trace_claim_12345",
"data": {
"case_status": "completed"
}
}Deliveries are at least once. Process duplicates idempotently by delivery_id.
Retry schedule
Klarefi makes up to 5 delivery attempts. After a failed attempt, retries are scheduled after 60 seconds, 5 minutes, 30 minutes, and 2 hours.
After the final failed attempt, the delivery is marked failed. Klarefi emits
webhook.delivery_failed, delivered as catalog event
v1.webhook.delivery_failed for matching webhook subscriptions, unless the
failed delivery was already a delivery-failed notification. Klarefi also creates
an integration notification. If a case.completed handoff delivery exhausts
its attempts, the case handoff state is marked dispatch failed.
Signature verification
Each delivery includes:
X-Klarefi-Signature: t=1704067200,v1=abc123def456...The signature is:
HMAC-SHA256(signing_secret, timestamp + "." + raw_body)Use the raw request body before JSON parsing.
Install the SDK:
npm install @klarefi/nodeimport { constructEvent, KlarefiWebhookSignatureError } from "@klarefi/node";
export async function POST(request: Request) {
const rawBody = await request.text();
try {
const event = constructEvent(
rawBody,
request.headers.get("X-Klarefi-Signature"),
process.env.KLAREFI_WEBHOOK_SECRET!,
);
if (event.event_type === "v1.case.completed") {
// Read the case package and update your system of record.
}
return Response.json({ received: true });
} catch (error) {
if (error instanceof KlarefiWebhookSignatureError) {
return new Response("Invalid signature", { status: 401 });
}
throw error;
}
}Test a webhook receiver
Required scope: webhooks:test
npx klarefi webhooks test \
--endpoint-url https://your-app.example.com/webhooks/klarefi \
--signing-secret whsec_your_signing_secretUse this command when you already have KLAREFI_API_KEY configured. The HTTP
equivalent is:
curl -X POST "$KLAREFI_API_BASE_URL/api/v1/webhooks/test" \
-H "Authorization: Bearer $KLAREFI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"endpoint_url": "https://your-app.example.com/webhooks/klarefi",
"signing_secret": "whsec_your_signing_secret"
}'{
"success": true,
"status_code": 200
}To verify a captured payload locally:
npx klarefi webhooks verify \
--payload payload.json \
--signature "t=1704067200,v1=..." \
--secret whsec_your_signing_secretAcknowledge a delivery
Required scope: webhooks:acknowledge
With an existing Klarefi client:
await klarefi.webhooks.acknowledge("whd_123", {
acknowledgement_id: "ack_claim_12345",
});curl -X POST "$KLAREFI_API_BASE_URL/api/v1/webhooks/deliveries/whd_123/ack" \
-H "Authorization: Bearer $KLAREFI_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "acknowledgement_id": "ack_claim_12345" }'{
"acknowledged": true,
"already_acknowledged": false,
"delivery_id": "whd_123",
"case_id": "case_abc123",
"handoff_state": "acknowledged"
}Acknowledgement is useful when your system wants Klarefi to record that a decision-ready handoff has been received.