Skip to main content

Signature scheme

Every delivery carries the header:
  • t is the Unix time in seconds when this attempt was sent.
  • Each endpoint has two secrets. s1 is computed with the first secret and s2 with the second.
  • Each signature is the lower-case hex HMAC-SHA256 of <raw body>.<t>: the exact request bytes before any JSON parsing, a dot, then the value of t.
Accept the request if either signature matches either of the secrets you stored, using a constant-time comparison. Reject it otherwise (answer 400 or 401). This is what makes rotation safe: AllRide always signs with both live secrets. Replay protection is yours to choose: reject a t more than 5 minutes away from your clock. Deduplicate on the body’s event.id, because retries and replays reuse it with a fresh t. Secrets are shown once, when you create the endpoint and when you rotate a secret.

No library needed

No library is needed: the scheme is an HMAC-SHA256 that every platform has. There are no official SDKs in v1; the samples below are complete verifiers you can copy. They read the secrets from the environment variables WEBHOOK_FIRST_SECRET and WEBHOOK_SECOND_SECRET (during a rotation one of them may be unset) and take an optional now (Unix seconds) so you can run the test vector. Two rules matter in every language:
  • Read the raw body bytes. Re-serialising parsed JSON changes the bytes and breaks the signature.
  • Compare in constant time.

Verify manually

Test vector

Use these documentation values to test your verifier. t is in the past, so pass now = 1792656000 (the vector’s t) when you run it. Raw body (403 bytes, UTF-8, one line, no trailing newline):
Expected header:
Your verifier must accept it with both secrets configured, accept it with only the second secret configured, and reject it when one byte of the body changes.

Secret rotation

Rotate one secret at a time, so every delivery stays verifiable:
  1. Call POST /partner/v1/webhook-endpoints/{webhookEndpointId}:rotate-first-secret (dashboard users need a recent sign-in). The response contains the new firstSecret, once.
  2. Update your receiver to accept the new first secret and the unchanged second secret. Deliveries in between still verify through s2.
  3. Later, rotate the second secret the same way with :rotate-second-secret.
If a secret leaked, rotate it at once and check your delivery log.