Core

Webhooks

Webhooks let your backend receive asynchronous updates from Scorift. When an event is too slow for the synchronous POST /v1/score response — such as a case disposition, an escalation, or a rule outcome — we push a signed JSON payload to an HTTPS endpoint you control. Every webhook is HMAC-signed and delivered with at-least-once semantics, so you can keep your own systems, audit trails, and queues in sync with the decisions Scorift makes.

Why use webhooks

  • Case lifecycle — receive updates when a flagged transaction is approved or rejected by an analyst.
  • Async deep checks — get notified when a deferred or long-range signal (e.g., a SIM swap report or sanctions update) changes a decision.
  • Rule audit — log every rule trigger in your own data warehouse for compliance and reporting.

Register an endpoint

POST /v1/webhooks
{
  "url": "https://api.acme.com/hooks/scorift",
  "events": ["case.dispositioned", "score.async", "rule.triggered"],
  "description": "Prod case pipeline"
}

Event catalog

EventWhen it fires
score.asyncA deferred score completes (>50ms deep-check).
case.createdA new case is opened, either by rule or analyst.
case.dispositionedAn analyst sets fraud, safe, or chargeback outcome.
rule.triggeredA rule fires in shadow or enforce mode.
signal.updatedA signal changes state (e.g. sim_swap detected).

Verifying signatures

Each request carries an X-Scorift-Signature header of the form t=<timestamp>,v1=<hmac_sha256>. Recompute the HMAC over {timestamp}.{raw_body} with your webhook secret and compare in constant time.

import { createHmac, timingSafeEqual } from "crypto";

function verify(body: string, header: string, secret: string) {
  const [tPart, sigPart] = header.split(",");
  const t = tPart.split("=")[1];
  const sig = sigPart.split("=")[1];
  const expected = createHmac("sha256", secret)
    .update(`${t}.${body}`).digest("hex");
  return timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

Retries & delivery

  • Retries follow exponential backoff up to 24 hours (max 12 attempts).
  • Respond with a 2xx status within 5 seconds — otherwise the delivery is retried.
  • Failed deliveries are surfaced in Settings → Webhooks with full payload replay.