Premium tier
Webhook Alerts
Get notified the moment a composite regime flips, with HMAC-signed POSTs to your endpoint.
Overview
Webhook alerts replace the daily-polling workflow. When the ingestion run detects that a composite signal's direction has changed since the previous as-of date, the dispatcher POSTs a signed JSON payload to every active subscription registered for that signal.
- Premium-tier feature. Free and Standard subscribers can read the API but cannot register webhook subscriptions.
- Currently triggers on regime flips only (direction change between consecutive composite values). Threshold-based events are queued for a future release.
- Single-attempt delivery with a 10-second timeout. No retry today; failures are recorded against the subscription's last-fire status.
Create A Subscription
From the authenticated app, open Settings → Webhooks and click Add subscription. The signing secret is shown ONCE on creation; copy it to your environment immediately.
Programmatically:
curl https://www.signalbench.dev/api/v1/user/webhooks \
-X POST \
-H "content-type: application/json" \
--cookie "<your-session-cookie>" \
-d '{"url":"https://your-server.example.com/sb-webhook","signal_id":"composite.equity.regime"}'Successful response includes the signing secret one time:
{
"id": 12,
"url": "https://your-server.example.com/sb-webhook",
"signal_id": "composite.equity.regime",
"event_type": "regime_flip",
"secret": "whsec_abc123..."
}Payload Format
Every delivery is a POST with this JSON body:
{
"version": "1",
"event": "regime_flip",
"signal_id": "composite.equity.regime",
"signal_name": "Equity Regime",
"as_of_date": "2026-05-16",
"previous_direction": "improving",
"current_direction": "deteriorating",
"previous_score": 0.18,
"current_score": -0.22,
"delivered_at": "2026-05-16T06:30:42.812Z"
}Headers attached to every delivery:
| Header | Value |
|---|---|
| content-type | application/json |
| user-agent | signal-bench-webhook/1.0 |
| x-signalbench-event | regime_flip |
| x-signalbench-signal-id | the composite id |
| x-signalbench-signature | sha256=<hex digest> |
Verifying The Signature
Compute HMAC-SHA256 of the raw request body using your stored secret, then compare against the digest in x-signalbench-signature (strip the sha256= prefix). Reject the delivery if the digests do not match — a mismatch means either the secret is wrong or the body was tampered with in transit.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifySignalBenchWebhook(
rawBody: string,
signatureHeader: string | undefined,
secret: string
): boolean {
if (!signatureHeader?.startsWith("sha256=")) return false;
const provided = Buffer.from(signatureHeader.slice(7), "hex");
const expected = createHmac("sha256", secret).update(rawBody).digest();
if (provided.length !== expected.length) return false;
return timingSafeEqual(provided, expected);
}import hmac, hashlib
def verify_signalbench_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool:
if not signature_header.startswith("sha256="):
return False
provided = bytes.fromhex(signature_header[len("sha256="):])
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
return hmac.compare_digest(provided, expected)Compute the HMAC over the exact bytes you received, not a JSON-parsed-and-re-serialized version. Re-serialization changes whitespace and key order and will break the signature.
List And Delete
# List your subscriptions (does not return secrets)
curl https://www.signalbench.dev/api/v1/user/webhooks --cookie "<your-session-cookie>"
# Delete a subscription
curl -X DELETE https://www.signalbench.dev/api/v1/user/webhooks/12 \
--cookie "<your-session-cookie>"Limits And Reliability
- Single delivery attempt per event. If your receiver is down or slow (>10s), the delivery is marked failed and not retried.
- The dispatcher runs once per ingestion cycle (daily). You will not receive intra-day webhooks for the same signal even if it moves within a day.
- Each subscription's last_fired_at, last_fire_status, and last_fire_message are visible in the settings UI for debugging.
- Your endpoint should respond quickly with 2xx. We do not parse the response body.
Exponential-backoff retry with a delivery-log table is on the roadmap. Today, treat webhooks as advisory and reconcile against the API if state matters.