Guides • Crypto Ramp
Verify the payload signature
doc

Webhook signature verification

Webhook security

Each webhook notification contains the following headers:

Header parameterDescriptionFormat
Revolut-Request-TimestampUNIX timestamp of the webhook event. Example value: 1715269527223.String
Revolut-SignatureSignature of the request payload. Contains the current version of the signature-generating algorithm and the hexadecimal-encoded signature. Example value: v1=d913b5305c6b975e50ed7c5dbb5826d31d39a488f47dc0a935692b7558eb6b23.String

Webhook signing secret

To ensure that a webhook request originates from Ramp and not a third party, we recommend that you verify the request's signature using a signing secret.

Ramp uses the HMAC SHA-256 algorithm to sign its webhooks. The secret is generated on webhook creation. After you've created a webhook, you can retrieve the signing secret when you retrieve a specific webhook's details.

Timestamp validation

You can mitigate replay attacks in your webhooks by applying timestamp validation.

For each webhook event, Ramp sends a Revolut-Request-Timestamp header with the exact date-time when it was delivered.

To validate the event, make sure that the Revolut-Request-Timestamp date-time is within a 5-minute time tolerance of the current universal time (UTC).

Verify the payload signature

Follow these steps to verify the signature for the webhook's request payload.

1. Prepare the payload to sign

To compute payload_to_sign, concatenate the following data, separating each item with a full stop (.):

  1. The version of the signature-generating algorithm (v1)
  2. The Revolut-Request-Timestamp header
  3. The raw webhook payload without whitespaces
payload_to_sign = {version}.{Revolut-Request-Timestamp}.{raw-payload}

An example of payload_to_sign might look like this:

v1.1715269527223.{"order_id":"19218d6e-5f55-4a0d-b7c5-6e333881c1c9","wallet":"0x96e2B7Bf479f84e7A0a94f0620290B7D3E08f5EF","event":"ORDER_CREATED"}
caution

The signature is sensitive to any modifications, meaning even a small change in the body will result in a completely different signature. Therefore, it is crucial not to alter the body, especially before the verification.

2. Compute the expected signature

To compute the expected signature, you need to concatenate the version of the signature-generating algorithm (v1) with the hash-based message authentication code (HMAC). Separate them with the equals character (=).

To compute the HMAC, use the SHA256 hash function and:

You can use the following Python implementation for reference:

Computation of the expected signature in Python
import hmac
import hashlib

signing_secret = 'wsk_8fT55z3C5hCr41l6B0b057D85s2043x4' #Obtained on webhook creation/details retrieval

raw_payload = '{"order_id":"19218d6e-5f55-4a0d-b7c5-6e333881c1c9","wallet":"0x96e2B7Bf479f84e7A0a94f0620290B7D3E08f5EF","event":"ORDER_CREATED"}'
timestamp = '1715269527223'
payload_to_sign = 'v1.' + timestamp + '.' + raw_payload #Prepared in Step 1

signature = 'v1=' + hmac.new(bytes(signing_secret , 'utf-8'), msg = bytes(payload_to_sign , 'utf-8'), digestmod = hashlib.sha256).hexdigest()

print(signature)

3. Compare signatures

Once you've computed the expected signature, compare it with the signature obtained in the Revolut-Signature header of the webhook notification.

The computed signature must match exactly the signature sent in that header.

Was this page helpful?