Developers

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:

HeaderDescription
webhook-idEvent idempotency key — the same value as the envelope id.
webhook-timestampUnix timestamp (seconds) when the delivery was attempted.
webhook-signatureHMAC-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))
}
Warning

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.
Was this page helpful?