Guides

Webhook Setup

Receive signed Klarefi events and verify webhook signatures

Overview

Klarefi sends signed, versioned domain events for intake, case, review, document, and webhook delivery activity. Webhooks are useful in both system_of_action and system_of_intelligence integrations.

All webhook deliveries are sent to registered endpoints and signed with HMAC-SHA256. Per-request webhook URLs are rejected; configure endpoint URLs in the dashboard so delivery policy, retries, and signing secrets stay consistent.

Setting Up Webhooks

1. Register an Endpoint

Register a webhook endpoint in the Klarefi dashboard under Webhooks. You'll receive an endpoint signing secret (whsec_...) to verify incoming events. Secrets are scoped to a registered endpoint and are shown only once.

2. Implement Your Receiver

Your endpoint must:

  • Accept POST requests with JSON body
  • Return a 2xx status code within 30 seconds
  • Verify the signature before processing
  • Process duplicate deliveries idempotently using the stable delivery_id

Signature Verification

Every webhook includes an X-Klarefi-Signature header:

X-Klarefi-Signature: t=1704067200,v1=abc123def456...

The signature is computed as: HMAC-SHA256(signing_secret, timestamp + "." + raw_body)

Event Payloads

Events use a versioned name and carry schema metadata. The event name is stable within a version; additive fields may appear over time, so ignore unknown keys.

{
  "event_id": "evt_01J7W9S4TSQ0T4SH43JYB9W5R8",
  "delivery_id": "whd_01J7W9S52C2ZK1XFY2GM7Z7SAK",
  "event_type": "v1.case.completed",
  "schema_version": "v1",
  "trace_id": "trc_01J7W9S4V8ZKH4W4B8EG9J7TKC",
  "created_at": "2026-05-01T12:34:56.000Z",
  "data": {
    "case_status": "complete"
  }
}

delivery_id is stable for a delivery attempt series and should be used for idempotency. event_id identifies the domain event. trace_id can be used when correlating dashboard delivery logs with receiver logs.

Event Catalog

Webhook endpoints can subscribe to individual event types or * for the full MVP catalog:

  • v1.intake.session_created
  • v1.intake.submitted
  • v1.case.processing
  • v1.case.applicant_blocked
  • v1.case.needs_review
  • v1.case.completed
  • v1.case.failed
  • v1.review.completed
  • v1.document.processed
  • v1.document.failed
  • v1.intake.gap_resolved
  • v1.webhook.delivery_failed
  • *

TypeScript

import { verifyWebhookSignature } from "@klarefi/sdk";
import express from "express";

const app = express();

app.post(
  "/webhooks/klarefi",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    try {
      const event = await verifyWebhookSignature(
        req.body.toString(),
        req.headers["x-klarefi-signature"] as string,
        "whsec_your_signing_secret",
      );

      console.log("Received event:", event.event_type, event.delivery_id);

      res.sendStatus(200);
    } catch (err) {
      console.error("Webhook verification failed:", err);
      res.sendStatus(401);
    }
  },
);

Python

from klarefi import verify_webhook_signature, WebhookVerificationError
from flask import Flask, request

app = Flask(__name__)

@app.route("/webhooks/klarefi", methods=["POST"])
def handle_webhook():
    try:
        event = verify_webhook_signature(
            raw_body=request.get_data(as_text=True),
            signature_header=request.headers.get("X-Klarefi-Signature"),
            signing_secret="whsec_your_signing_secret",
        )

        if event["event_type"] == "v1.case.completed":
            print("Case completed:", event["data"]["case_id"])
            # Process the results in event["data"]

        return "", 200

    except WebhookVerificationError as e:
        print("Webhook verification failed:", e)
        return "", 401

Event Handling Guidance

Treat webhook events as integration signals, then read the current case or session state from the canonical runtime-backed API surface when you need the latest result.

This avoids coupling your integration to a long list of event-specific assumptions.

Testing Webhooks

Send a test event to verify your receiver works before going live:

curl -X POST https://api.klarefi.com/api/v1/webhooks/test \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint_url": "https://your-app.com/webhooks/klarefi",
    "signing_secret": "whsec_your_signing_secret"
  }'

Retry Policy

If delivery fails, Klarefi retries with backoff and marks the delivery as pending, delivering, retrying, delivered, or failed in the dashboard. Exhausted deliveries are moved to the dead-letter queue and can emit v1.webhook.delivery_failed to subscribed endpoints. Use the dashboard delivery logs, delivery_id, and trace_id to debug failures or replay failed deliveries.

On this page