Portal
Documentation: all sections

Webhooks

Subscribe to lifecycle events out-of-band from the inference path. Create subscriptions from the dashboard.

Event types

The receipt stream

receipt_minted is the one to point a collector at. It fires once for every signed receipt, the moment it is minted, across inference, embeddings, /v1/messages, and sandbox runs. The payload carries the receipt, signature, and signer, plus the kind, status, and cost_micro_usd, so every metered call lands in your own observability or audit stack as it happens, already signed and independently verifiable through POST /v1/receipts/verify.

It is metadata only by construction, the same as the receipt itself: no prompt, completion, or code ever travels in the event. That makes it safe to route to a SIEM, a data warehouse, or a spend dashboard without opening a hole in the privacy contract.

Delivery

Each event POSTs JSON to your URL with two headers:

Verifying signatures

import { createHmac, timingSafeEqual } from "node:crypto";

function verifySable(req: Request, secret: string): boolean {
const sig = req.headers.get("x-sable-signature") ?? "";
const expected = "sha256=" + createHmac("sha256", secret)
  .update(req.body)
  .digest("hex");
return timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

Retries & auto-disable

Delivery is retried with exponential backoff: an immediate attempt, then retries after 30s, 5m, and 1h, up to four attempts per event. Any failed attempt retries, whether it was a non-2xx response or a network error, until that budget is spent. Events queue in a durable outbox, so the retry schedule survives gateway restarts and deploys rather than dying with the process. Each event records exactly one webhook_deliveries row capturing the number of attempts and the last status seen.

After 5 consecutive events fail every attempt, the webhook is automatically disabled (disabled_at is set) and stops receiving events until you re-create it. A single delivered event resets the counter.

Inspecting and testing deliveries

Two session-authed endpoints make a misbehaving receiver debuggable without guessing: