Skip to main content
Your webhook URL is public, so anyone who learns it can send requests to it. Ciarem signs every request with your endpoint’s signing secret. Checking that signature is how your server tells a real Ciarem event from a forged one. Verify before you trust the body.

The signing secret

Each endpoint has its own secret. It starts with whsec_.
  • In the dashboard: shown when you add the endpoint, and again any time on the endpoint’s page with Show secret. Only admins can see it.
  • With the API: returned once, in the response of POST /v1/webhook-endpoints.
Treat it like a password: keep it in your secret manager or an environment variable, never in code or in a browser.

The signature header

Every request carries a Ciarem-Signature header:
The signature is computed over the timestamp, a dot, and the raw request body, using your signing secret as the key:

How to verify

1

Read the raw body

Take the request body exactly as the bytes arrived, before any JSON parsing. Parsing and re-serializing changes spacing and character escaping, and the signature will no longer match.
2

Split the header

Split Ciarem-Signature on , and then on = to get t and v1.
3

Compute the expected signature

Build the message t + "." + raw body and compute its HMAC-SHA256 with your signing secret. Use the whole secret, including the whsec_ prefix, as it is.
4

Compare safely

Compare your result with v1 using a constant-time comparison function, not ==.
5

Check the timestamp

Reject the request if t is more than 5 minutes away from your server’s clock. This stops someone from capturing a real request and replaying it later.
If any step fails, answer 400 and do nothing with the body.

Code you can copy

Check your code with a known example

Use these values to confirm your verification code computes the right signature, without waiting for a real event. Skip the timestamp check while you run this, since the example’s timestamp is in the past. You can produce the same value from a terminal:

When verification fails

Good practices

  • One secret per endpoint. If you run staging and production servers, give each its own endpoint so a leaked staging secret cannot forge production events.
  • Rotate by replacing the endpoint. A secret cannot be changed in place. To rotate, add a new endpoint with the same URL and events, update your server to accept the new secret, then delete the old endpoint. While both exist, you receive each event twice, once per endpoint, with the same event id, so deduplicating on id keeps this harmless.
  • Every retry is signed again. A retried delivery has the same body and event id but a new t and a new signature, so the 5-minute check works for retries too.
  • Verification proves origin, not uniqueness. A verified event can still be a duplicate. Deduplicate on id as well.