Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.alterscope.org/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks push risk events to your endpoint as they happen — an alternative to holding a WebSocket open. Deliveries are signed so you can verify they came from Alterscope.

Subscribe

curl -H "Authorization: Bearer $ALTERSCOPE_API_KEY" \
     -H "Content-Type: application/json" \
     -X POST \
     -d '{
       "url": "https://your.app/alterscope-webhook",
       "events": ["peg.depeg.start", "peg.depeg.end", "vault.cap.changed"]
     }' \
  "https://api.alterscope.org/v2/webhooks"
On creation, the response returns a signing_secret (prefix whsec_) exactly once — store it in your secrets manager, because you can’t retrieve it again. You cannot supply your own secret; the platform generates it. Rotate it via POST /v2/webhooks/{id}/rotate-secret. Subscribe to the event types you care about; examples include peg.depeg.start, peg.depeg.end, and vault.cap.changed. See the Event catalog for every type, when it fires, and a sample payload.

Verify the signature

Every delivery includes an Alterscope-Signature header in the form t=<unix_ts>,v1=<hex_hmac_sha256>. The v1 value is the HMAC-SHA256 of "<t>.<raw_body>" (the timestamp, a literal dot, then the raw request body), keyed with your signing_secret. Recompute it, compare in constant time, and reject deliveries whose timestamp is outside a ~5-minute tolerance — that bounds replay attacks:
import hashlib, hmac, time

def verify(raw_body: bytes, header: str, secret: str, tolerance_s: int = 300) -> bool:
    # header looks like: "t=1716902400,v1=abc123..."
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, v1 = parts.get("t"), parts.get("v1")
    if not t or not v1:
        return False

    # Reject stale timestamps to bound replay.
    if abs(time.time() - int(t)) > tolerance_s:
        return False

    signed = f"{t}.".encode() + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)
Reject any delivery whose signature doesn’t match or whose timestamp is stale.
A legacy X-Alterscope-Signature header — a plain HMAC-SHA256 of the raw body (no timestamp prefix) — is dual-emitted alongside Alterscope-Signature during a 60-day transition window and is deprecated. New integrations should verify Alterscope-Signature; migrate any existing checks off the legacy header before the window closes.

Manage subscriptions

OperationEndpoint
List / createGET / POST /v2/webhooks
Get / update / deleteGET / PATCH / DELETE /v2/webhooks/{id}
Inspect deliveriesGET /v2/webhooks/{id}/deliveries
Send a test eventPOST /v2/webhooks/{id}/test
Rotate the signing secretPOST /v2/webhooks/{id}/rotate-secret
After rotating, accept both the old and new signature for a short overlap so in-flight deliveries still verify.

Replay missed events

If your endpoint was down, replay events from the unified feed within your tier’s replay window (see Rate limits):
curl -H "Authorization: Bearer $ALTERSCOPE_API_KEY" \
  "https://api.alterscope.org/v2/events/replay?since_event_id=01J9Z0K3M4N5P6Q7R8S9T0V1W2&limit=100"
Signed webhooks are available on the Team tier and higher; see Rate limits for per-tier limits.