Verify signature
Every Stridge delivery is signed with HMAC-SHA256 over the timestamp and the raw envelope body. Verify it before you trust anything in the payload — a missing or invalid signature means the request did not come from Stridge.
Request headers
Stridge attaches three headers to every delivery:
| Header | Description |
|---|---|
webhook-id | Event idempotency key — the same value as the envelope id. |
webhook-timestamp | Unix timestamp (seconds) when the delivery was attempted. |
webhook-signature | HMAC-SHA256(secret, "{timestamp}.{envelopeJSON}"), hex-encoded. |
The secret is the per-subscriber signing secret shown when you create the subscriber in the Dashboard — see Subscribe to webhooks.
Signature computation
The signature is computed over the timestamp and the raw envelope JSON body, joined by a ., using your subscriber's signing secret:
message = webhook-timestamp + "." + raw_request_body
signature = HMAC-SHA256(signing_secret, message)Verify it against the webhook-signature header before trusting the body — and compare with a constant-time check:
import { createHmac, timingSafeEqual } from 'node:crypto'
export function verifyWebhookSignature(
secret: string,
body: string,
timestamp: string,
receivedSignature: string,
) {
const message = `${timestamp}.${body}`
const expected = createHmac('sha256', secret).update(message).digest('hex')
return timingSafeEqual(Buffer.from(expected), Buffer.from(receivedSignature))
}Verify the signature against the raw request body — parse the JSON
only after the check passes. Re-serializing the body first will change
the bytes and break the signature. Reject deliveries with an old
webhook-timestamp (more than a few minutes off your server clock) to
reduce replay risk.
Failure modes
A verification failure should always return a non-2xx response so Stridge marks the delivery as failed and the retry policy kicks in — see Retries. Common causes:
- Wrong secret — your endpoint is using a stale secret. Check the subscriber's current secret in the Dashboard; rotate if needed.
- Body re-serialized — your framework parsed the JSON, re-stringified it, and signed the wrong bytes. Capture the raw body before any JSON middleware runs.
- Trailing whitespace / encoding drift — some proxies append a newline or rewrite encoding. Compare hex character-for-character against the raw body bytes.