Platform · Webhooks

Webhooks

Webhooks let your backend react to events without polling. Every delivery is signed with HMAC-SHA256 and includes a replayable ID so you can deduplicate at-least-once delivery.

Available events

  • redaction.completedFired when a /redact or /process call returns 2xx.
  • redaction.failedFired on any 5xx that exhausts internal retries.
  • pattern.createdFired when POST /patterns creates a custom detector.
  • pattern.deletedFired when a pattern is removed.
  • subscription.updatedPlan or seat count changed on a workspace.
  • key.rotatedFired when an API key is rotated or revoked.

Payload format

Every webhook is a POST with a JSON body. The signature is in the Savitar-Signature header.

POST https://your.app/webhook
{
  "id": "evt_01HX9MQA8B3E2W4N6F",
  "type": "redaction.completed",
  "created": "2026-05-24T14:02:11Z",
  "workspace": "ws_abc123",
  "data": {
    "session_id": "req_5j2g6sw72a",
    "entities_found": 3,
    "duration_ms": 124
  }
}

Verifying signatures

Compute an HMAC-SHA256 of the request body using your endpoint's secret, then compare in constant time.

import crypto from "node:crypto";

export function verifySignature(rawBody: string, header: string, secret: string): boolean {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const provided = header.replace(/^sha256=/, "");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(provided));
}

Retries & replays

We retry non-2xx responses with exponential backoff for 24 hours. After that, deliveries are marked failed and can be manually replayed from the dashboard for up to 30 days.