Webhooks

Get notified when async jobs finish, when usage crosses a threshold, or when an incident affects your traffic.

Event types

EventWhen it fires
usage.thresholdSpend crosses a configured % of cap.
key.revokedAny API key is revoked.
model.deprecatedA model you've used is scheduled for retirement.
incident.affecting_youA region or component you use is degraded.
batch.completed (Phase 2)Batch job finishes.

Setup

Console → Settings → Webhooks → New endpoint. Pick events, paste a URL.

Payload shape

{
  "id":         "evt_01HV...",
  "type":       "usage.threshold",
  "created_at": "2026-05-13T09:11:02Z",
  "data": {
    "threshold_pct": 80,
    "spend_usd":     400,
    "cap_usd":       500
  }
}

Signature verification

Every webhook carries a Tomoul-Signature header in the form t=<unix>,v1=<hex>. Verify with HMAC-SHA256 over <unix>.<raw_body> using the endpoint's signing secret.

import hmac, hashlib
 
def verify(payload: bytes, header: str, secret: str) -> bool:
    parts = dict(kv.split("=", 1) for kv in header.split(","))
    expected = hmac.new(
        secret.encode(),
        f"{parts['t']}.{payload.decode()}".encode(),
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(parts["v1"], expected)

Reject any request whose signature doesn't validate. Also reject requests older than 5 minutes (t field) — that's how we prevent replay.

Retry behaviour

Non-2xx responses retry with exponential backoff for 24 hours (10 attempts total). After that the event is dropped — but stays visible in the console's webhook log for 30 days so you can manually reprocess.

Last updated 13 May 2026Edit this page on GitHub