OutemitAll posts

2026-09-04 · Outemit

Verify Standard Webhooks signatures correctly

Outemit signs every delivery with the Standard Webhooks scheme. Getting verify wrong usually means one of four mistakes: reading a parsed body, ignoring timestamp skew, decoding the secret incorrectly, or forgetting dual-sign during rotation.

Signed content

The signed string is webhook-id.webhook-timestamp.rawBody. Use the raw request bytes, not a re-serialized JSON object. Many frameworks parse JSON before your handler runs; keep a raw buffer middleware for webhook routes.

Headers that matter

  • webhook-id - unique message id. Dedupe side effects on this.
  • webhook-timestamp - Unix seconds. Reject if outside your skew window (commonly five minutes).
  • webhook-signature - one or more v1,... signatures. Accept if any matches.

Secret format

Secrets look like whsec_.... Libraries strip the prefix and base64 decode the remainder before HMAC-SHA256. Hand-rolled verify must do the same.

Rotation grace

When you rotate, Outemit dual-signs for a grace window so old and new secrets both verify. During that window, accept either signature. After grace, only the new secret should succeed.

Copy-paste snippets: /docs/signing. Try a payload in the verifier tool.