Skip to main content
Your endpoint URL is public, so anyone could send it a request. Every ReyGrid delivery is signed with your endpoint’s signing secret. Verify the signature before you trust the payload.

The signature header

The signed payload is the timestamp, a dot, and the raw request body:

Verify a request

1

Read the raw body

Use the exact bytes you received. Parsing the JSON and serializing it again changes whitespace and key order, and the signature won’t match.
2

Split the header

Split X-ReyGrid-Signature on , then each part on = to get t and v1.
3

Compute the expected signature

HMAC-SHA256 of {t}.{raw body} with your signing secret (the full whsec_… string), as lowercase hex.
4

Compare and check the age

Compare with v1 using a constant-time comparison, and reject requests whose t is more than 5 minutes away from your clock to block replays.

Framework notes

Use express.raw({ type: "application/json" }) on the webhook route (not express.json()), then req.body.toString("utf8") is the raw body.
Flask: request.get_data(). FastAPI: await request.body(). Both return the raw bytes to pass to verify_reygrid.

Rotating the secret

Select the rotate button next to the secret on the endpoint card in Console → Webhooks. The new secret applies to the next delivery immediately, so update your server’s environment right after rotating.
Treat the signing secret like a password: keep it server-side, never commit it, and rotate it if it leaks.

Best practices

  • Respond fast. Return 2xx as soon as the signature checks out and process the event in the background. Requests time out after 10 seconds.
  • Be idempotent. Retries reuse the same event id (also in X-ReyGrid-Delivery). Skip IDs you’ve already processed.
  • Don’t rely on order. Events can arrive out of order. Use created when ordering matters.
  • Ignore unknown types. Return 2xx for event types you don’t handle, so new events never cause failures.