Verify Webhook Signatures

Verify that webhook requests originated from Revaly and have not been modified in transit.

Every webhook delivery sent by Revaly includes a cryptographic signature that allows your application to verify that the request originated from Revaly and was not modified in transit.

Signature verification is a critical part of any webhook integration and should be performed before processing the event payload. This guide explains how Revaly signs webhook requests and how to validate those signatures within your application.


Why Signature Verification Matters


Because webhook endpoints are publicly accessible, they can receive requests from any source on the internet. Without signature verification, an attacker could potentially send requests that appear to be legitimate webhook events.

Signature verification helps ensure that:

  • The request originated from Revaly
  • The payload was not modified during transit
  • The webhook has not been replayed outside the accepted time window

Only process webhook events after signature verification succeeds.


Signature Header


Revaly includes a revaly-signature header with every webhook delivery. The header contains both a timestamp and the calculated signature used during verification.

revaly-signature: t=1747958400,v1=5d0d0c7d5c985f0f61f4f8aef7d8e8d5f9d0f7c4d4e6c9b7a31ff1a0e5c7d9b4g

t = Unix timestamp when the signature was generated

v1 = HMAC-SHA-256 signature


Verification Process


Signature verification consists of reconstructing the signed payload, calculating the expected signature using your webhook signing secret, and comparing the result to the value received in the request header.

For each incoming webhook:

  • Read the raw request body before parsing JSON.
  • Extract the t and v1 values from the Revaly-Signature header.
  • Reject the request if the timestamp is more than 5 minutes old.
  • Build the signed payload.
    • {t}.{rawBody}
  • Calculate the expected HMAC-SHA-256 signature using your webhook signing secret.
  • Compare the calculated signature against v1 using a constant-time comparison.
  • Process the webhook only if validation succeeds.

Constructing the Signed Payload


The signature is calculated using a combination of the request timestamp and the exact raw request body.

{t}.{rawBody}

Example:

1747958400.{"id":"test:a6276285fab04c1daa572805cc1e3137","eventType":"transaction.succeeded"...}

This exact string is used when calculating the HMAC-SHA-256 signature.

🚧

Prevent Replay Attacks

The timestamp included in the revaly-signature header helps protect against replay attacks. Requests with timestamps older than five minutes should be rejected, even if the signature itself is valid.

To avoid false failures, ensure that your servers maintain accurate time synchronization using NTP or an equivalent service.


Use the Raw Request Body


Signature verification must be performed against the exact raw request body received from Revaly.

Many web frameworks automatically:

  • Parse JSON
  • Reformat whitespace
  • Reorder properties
  • Modify encoding

These changes can cause signature validation to fail. Always capture the raw request payload before any parsing occurs.


Recommended Processing Flow


We recommend handling webhook deliveries in the following order:

  1. Receive Request
  2. Capture Raw Body
  3. Verify Signature
  4. Parse JSON
  5. Check whether event id was already processed.
  6. Store Event
  7. Return 2xx
  8. Process Asynchronously

This approach improves reliability and helps protect against duplicate deliveries.


Common Verification Issues


If signature verification fails, the issue is often related to request handling, secret management, or payload processing. The following are the most common causes and how to resolve them.

MistakeWhy it causes problemsFix
Verifying parsed JSONFormatting changes break signature validationUse the raw request body
Using normal string comparisonMay expose timing attack riskUse constant-time comparison
Server clock is wrongValid requests may be rejectedSync server clock using NTP
Wrong signing secretSignature will never matchConfirm the secret for the correct endpoint
Processing before verificationInvalid requests may be acceptedVerify first, process second


Secret rotation


If a signing secret is rotated, there may be a period where previously generated webhook deliveries are still being retried using the old secret. During this transition, your application should be prepared to validate signatures generated with either secret.

  1. Generate a new signing secret in Revaly.
  2. Deploy the new secret to your application.
  3. Temporarily accept signatures generated using either the old or new secret.
  4. Remove the old secret after the transition period.

We recommend a transition window of 24 hours to accommodate any in-flight webhook retry attempts.