Skip to main content
Darwin signs every request the Standard Webhooks way, so you can use an existing library or a few lines of your own. Always verify before you trust a payload: anyone can send a POST to your URL.
  1. Take the raw request body exactly as received. Parsing and re-serialising the JSON changes the bytes and breaks the signature.
  2. Reject the request if webhook-timestamp is more than five minutes from your clock.
  3. Build the signed content: `${webhook-id}.${webhook-timestamp}.${body}`.
  4. Compute HMAC-SHA256 over it. The key is your signing secret without the whsec_ prefix, base64-decoded.
  5. Base64-encode the result and compare it, in constant time, with each v1, entry in webhook-signature. The header can hold several entries separated by spaces (during a secret rotation); accept if any matches.

Use a Standard Webhooks library

Any Standard Webhooks library verifies Darwin’s signatures, including Svix’s. Pass the raw body, the headers and the secret as Darwin shows it:
With the TypeScript SDK, await Darwin.webhooks.verify(body, headers, secret) does all of this.

Rotate the signing secret

Open the endpoint’s ⋯ menu, select Rotate signing secret and confirm. Darwin shows the new secret once. For the next 24 hours every delivery carries two signatures, one per secret, so your receiver keeps working while you switch it to the new secret. After 24 hours only the new secret signs. With the API: POST /v1/webhook_endpoints/{id}/rotate_secret returns the endpoint with its new secret.