Back to docs

Webhooks

Verify signatures

Validate Styrar-Signature on every delivery with HMAC-SHA256.

The signature follows a Stripe-style scheme. It signs "{timestamp}.{raw_body}" with HMAC-SHA256 using your endpoint secret.

  1. Parse Styrar-Signature into t (unix timestamp) and v1 (hex digest).
  2. Reject if t is outside your tolerance (we recommend 5 minutes).
  3. Compute the expected digest and compare with v1 using a constant-time check.
JavaScript
import crypto from 'node:crypto'

function verifyStyrarWebhook(secret, signatureHeader, rawBody, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((part) => part.trim().split('=')),
  )

  const timestamp = Number(parts.t)
  const receivedDigest = parts.v1 || ''

  if (!Number.isFinite(timestamp)) return false
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false

  const expectedDigest = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex')

  try {
    return crypto.timingSafeEqual(
      Buffer.from(expectedDigest, 'utf8'),
      Buffer.from(receivedDigest, 'utf8'),
    )
  } catch {
    return false
  }
}

Always verify against the raw request body before parsing JSON.

Reliability

  • Deliveries are at-least-once. Deduplicate using Styrar-Event-Id or the envelope id.
  • Failed deliveries retry with exponential backoff until success or max attempts.
  • If your server returns HTTP 410, Styrar disables the endpoint automatically.
  • Respond with 2xx as soon as you have accepted the event; process heavy work asynchronously.

Limits

  • HTTPS required in production for callback URLs.
  • 25 endpoints per personal or company workspace scope.
  • Signing secrets are shown once on create and rotate; store them in your secrets manager.

Join the beta waitlist

By signing up you agree to receive marketing email. See our Privacy Policy.