Skip to main content
Every webhook delivery carries an HMAC-SHA256 signature in the X-Awardee-Signature header. Verify it on every request before parsing or acting on the body. A request that fails verification is either a misconfiguration or an attempt to impersonate Awardee.

Signing secret

The signing secret is shown on the webhook endpoint’s detail page in the dashboard. It looks like:
Treat it as a server-side credential. If it leaks, rotate it from the dashboard. Each endpoint has its own secret — leaking one doesn’t compromise the others.

Signature format

The X-Awardee-Signature header is a comma-separated list of key/value pairs:
  • t — Unix seconds at signing time. Also sent in X-Awardee-Timestamp.
  • v1 — HMAC-SHA256, lowercase hex, of the string <t>.<raw_body>, signed with the endpoint’s whsec_… secret.
The leading scheme prefix (v1=) leaves room for a future hash upgrade. Match by prefix, not by position.

Verifying

The verification recipe is: rebuild the signed string, HMAC it, compare in constant time.
HMAC the raw request body. Re-serializing JSON before signing — even just to add a trailing newline or normalize key order — invalidates the signature. Express, FastAPI, Rails, and Next.js all require explicit raw-body access:
  • Express. app.use(express.raw({ type: "application/json" })) for the webhook route.
  • FastAPI. Read await request.body() before any await request.json().
  • Next.js (app router). Read await req.text() and parse JSON yourself.
  • Rails. request.raw_post.
Whatever your framework, verify your handler receives the exact bytes Awardee sent.

Replay attacks

The t= timestamp lets you reject deliveries that are stale. Compare it to your server clock and refuse anything older than five minutes:
Pair this with delivery idempotency so a legitimately retried delivery (which carries the same X-Awardee-Delivery) is still recognized and ignored, while a captured-and-replayed request is rejected by the timestamp check.

Rotating the secret

Rotating the signing secret invalidates the old secret immediately on the next delivery. To rotate without dropping events:
1

Generate a new secret

The dashboard offers “Rotate signing secret” on each endpoint. The old secret stays valid for a 24-hour grace window.
2

Update verification

Roll your service so it accepts either the old or the new secret. Return success if either validates.
3

Cut over

Once you’ve confirmed deliveries are verifying with the new secret in your logs, remove the old one.