X-RadiumOne-Signature header. Verify it against
the raw request body before you trust anything in the payload — an unverified
webhook is just an HTTP POST from whoever can reach your endpoint.
Header anatomy
Two companion headers accompany every delivery:
X-RadiumOne-Event-Id (same value
as the payload’s id, useful for logging before you’ve parsed the body) and
X-RadiumOne-Event-Type.
Algorithm
- Parse
v,t, andsfrom the header. - Build the signing string:
`${v}.${t}.`(literal dot-joinedvandt) concatenated with the raw request body bytes — not a re-serialized copy. - Compute
HMAC-SHA256(key, signing_string)and hex-encode it. - Compare it to
susing a constant-time comparison — never===orhmac == string, which can leak timing information about how many leading bytes matched. - Reject if
tis outside your tolerance window (300 seconds / 5 minutes is the reference implementation’s default) — this defends against replaying an old, otherwise-valid delivery.
Verify the signature
Read the raw body before any JSON parsing — most frameworks parse the request body
automatically, which discards the exact bytes the signature was computed over. See
Build your handler for the full handler
order (raw body → verify → dedupe → enqueue → respond).
Known-answer test
RadiumOne’s own signer is tested against known-answer vectors, using the same dummy secret (never a real key). Run them against your own verifier to confirm you’ve implemented the algorithm correctly before going live. A representative subset:
The valid case uses secret
whsec_0000000000000000000000000000000000000000000000000000000000000000 and header v=1,t=1700000000,k=66687aad,s=e4cd0b87e9dd8eeb3390b2d4e7d35b07480bfab5a1d687bfe055fd7337a7b119. The full vector set — including tampered, expired, wrong-version, and malformed/forged cases — is tested against real Node.js, Python, PHP, and Java implementations of this algorithm before every release.
Tolerance and replay
- A 5-minute (300 second) tolerance on
tis the reference default — narrower windows increase the chance a slow network rejects a legitimate delivery; wider windows extend how long a captured signature stays replayable. - Dedupe on the event
idregardless of your tolerance window — a retried delivery (see Retries, ordering, and duplicates) is a legitimate re-send with a fresh, valid signature, not a replay.
Rotating your secret
Rotating your webhook secret is a support-assisted operation today — see Register your endpoint. There’s no automatic overlap window on RadiumOne’s side: once your secret is rotated, the previous secret is irrecoverable. Deliveries already queued before the rotation, though, may still be retried using the old signature for as long as they keep retrying (up to the full backoff schedule, about 30 hours — see Retries, ordering, and duplicates). If you want those in-flight retries to keep verifying, keep your old secret available in your verifier for that same window after you rotate, then remove it.Next steps
Webhooks overview
Handler steps: verify, dedupe, enqueue, respond.
Webhook event types
Every event and its payload shape.