Reference
4 min read
Outgoing Webhooks
StateAnchor can POST gate verdicts to a URL you control every time a sync run completes. Use this to route gate decisions into Slack, PagerDuty, your own incident system, or any HTTP endpoint.
Creating a webhook endpoint
- Open your project and go to Settings → Webhooks.
- Click Add endpoint.
- Enter the destination URL (must start with
https://). - Click Save. StateAnchor generates a shared signing secret for the endpoint and shows it once -- copy it now. You will use this secret to verify incoming payloads on your server.
Payload format
StateAnchor sends an HTTP POST with Content-Type: application/json. The payload shape:
{
"event": "gate.result",
"project_id": "proj_abc123",
"sync_run_id": "run_xyz789",
"gate_action": "block" | "allow" | "approval_required",
"gate_lane": "ERR" | "WARN" | "INFO" | "PASS",
"gate_score": 0-100,
"repo": "owner/repo",
"sha": "abc1234...",
"ref": "refs/heads/main",
"timestamp": "2026-04-22T10:00:00Z"
}Verifying signatures
Every delivery includes a X-StateAnchor-Signatureheader containing an HMAC-SHA256 digest of the raw request body, keyed with your endpoint's signing secret.
To verify on your server:
const crypto = require("crypto");
function verify(body, signatureHeader, secret) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expected)
);
}Always verify the signature before processing the payload. Reject requests whose signature does not match -- they may be forged.
Delivery log
StateAnchor records every delivery attempt for each endpoint. Open Settings → Webhooks and click an endpoint to see the last 50 delivery attempts, including:
- HTTP status code returned by your server
- Response time in milliseconds
- Timestamp of the attempt
- Whether the delivery was retried
Retry behavior
StateAnchor retries failed deliveries with exponential backoff. A delivery is considered failed if your server returns a non-2xx status code or does not respond within the timeout window. After 5 failed attempts the delivery is marked permanently failed and will not be retried.
Deliveries are best-effort. If your endpoint is offline for an extended period, some gate results may not be delivered. The StateAnchor dashboard always has the authoritative gate history.
Idempotency
Retried deliveries send the same payload with the same sync_run_id. Your endpoint should be idempotent -- processing the same run ID twice should produce the same result as processing it once.
Deleting an endpoint
Open Settings → Webhooks, find the endpoint, and click Delete. Future deliveries to that URL will stop immediately. Historical delivery records are retained for audit purposes.
Related
- stateanchor.yaml reference -- webhook configuration fields
- Gate classification -- the ERR / WARN / PASS verdicts delivered via webhooks
- Sharing a gate result -- share links included in webhook payloads