Skip to main content
Clausum notifies your systems of important events — fraud reports, case updates, disputes — by sending signed HTTP POST requests to endpoints you configure. See Webhook events for the full catalog.

1. Register an endpoint

In the dashboard, add a webhook with:
  • URL — a publicly reachable HTTPS endpoint on your server.
  • Events — the event types you want (e.g. fraud.detected, case.created).
  • Secret — Clausum generates a signing secret. Store it securely.

2. Understand the delivery

Each delivery includes these headers:
HeaderExampleDescription
X-Clausum-Signaturet=1716998400,v1=8a9b...HMAC signature
X-Clausum-Eventfraud.detectedEvent type
X-Clausum-Timestamp2026-05-29T18:30:00ZDelivery time
The body is JSON:
{
  "event": "fraud.detected",
  "timestamp": "2026-05-29T18:30:00.000Z",
  "data": { "case_id": "b1f2...", "reference_number": "CLM-LX9A2B", "reason": "chargeback" }
}

3. Verify the signature

The signature is computed as HMAC_SHA256(secret, "<timestamp>.<rawBody>") and encoded as t=<timestamp>,v1=<hex>. Verify against the raw request body before parsing.
import crypto from "crypto"

export function verifyClausumSignature(rawBody: string, header: string, secret: string): boolean {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")))
  const timestamp = parts["t"]
  const provided = parts["v1"]
  if (!timestamp || !provided) return false

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex")

  // constant-time comparison
  return crypto.timingSafeEqual(Buffer.from(provided), Buffer.from(expected))
}

4. Handle the event

export async function POST(req: Request) {
  const raw = await req.text() // raw body is required for verification
  const signature = req.headers.get("x-clausum-signature")

  if (!signature || !verifyClausumSignature(raw, signature, process.env.CLAUSUM_WEBHOOK_SECRET!)) {
    return new Response("Invalid signature", { status: 401 })
  }

  const event = JSON.parse(raw)

  switch (event.event) {
    case "fraud.detected":
      await onFraudDetected(event.data)
      break
    case "case.created":
      await onCaseCreated(event.data)
      break
    // ...
  }

  // Acknowledge fast; do heavy work asynchronously
  return new Response("ok", { status: 200 })
}

Best practices

Frameworks that auto-parse JSON can change the byte stream. Read the raw text first, verify, then parse.
Return a 2xx within a couple of seconds and offload processing to a queue. Slow responses are treated as failures and retried.
The same event can arrive more than once. De-duplicate using identifiers in data plus the event type and timestamp.
Optionally reject deliveries whose t is far from the current time to mitigate replay attacks.