Documentation Index
Fetch the complete documentation index at: https://docs.signa.so/llms.txt
Use this file to discover all available pages before exploring further.
TypeScript / Node — SDK helper
The@signa-so/sdk package exports a thin wrapper over
standardwebhooks:
- Returns
truefor a valid signature againstSECRET. - Returns
falseon stale timestamps (>5 min skew, enforced by the reference library). - Accepts rotation overlap (
v1,<curr> v1,<prev>) — verifies if either entry passes.
JSON.parse round-trip
first. Mismatched whitespace breaks the HMAC.
TypeScript / Node — without the SDK
Python
Installstandardwebhooks:
Go
Idempotency
Usewebhook-id (the value, not the body) as your application-level
idempotency key. The same alert delivered twice (retry, redeliver,
duplicate dispatch) will carry the same webhook-id, so your business
logic (creating tickets, sending notifications, writing to your own DB)
just needs to check “have I processed this id?” — exactly-once behaviour
without any extra plumbing.
Important: do NOT dedup blindly on webhook-id alone at the infrastructure layer
A common pitfall: a queue/proxy in front of your handler does
if (seenWebhookIds.has(headers['webhook-id'])) return; and silently
drops legitimate retries. Our dispatcher reuses webhook-id across
retries on purpose — that’s how application-level idempotency works —
but it means an infrastructure-layer dedup keyed only on webhook-id
will swallow a retry that your handler actually wanted to see (e.g. the
first attempt timed out before your handler committed).
If you need infrastructure-layer dedup (retry-storm protection, queue
fan-out, observability counters), key on the tuple
(webhook-id, webhook-attempt) instead. The webhook-attempt header
is the delivery attempt number — 1 for the first delivery, 2 for
the first retry, and so on.
Security note:webhook-attemptis NOT part of the signed envelope. Per the Standard Webhooks spec, onlywebhook-id,webhook-timestamp, and the body are signed. An attacker who replays a captured request can set anywebhook-attemptvalue they like. Use it only for dedup-counting and observability — never as input to a security decision.
Common pitfalls
- Re-serialising the body. Verify against the bytes you received,
not against
JSON.stringify(JSON.parse(body)). Whitespace matters. - Comma vs space in
webhook-signature. During rotation the header contains TWO entries separated by a SINGLE SPACE. Some libraries split on commas — make sure yours follows the spec. - Forgetting timestamp freshness. A leaked secret + stale signature is replayable. The SDK helper enforces 5-min skew automatically; if you roll your own, do the same.