# Verify the payload signature

Follow these steps to verify the [signature for the webhook's request payload](/docs/guides/manage-accounts/webhooks/about-webhooks#security).

## 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](/docs/guides/manage-accounts/webhooks/about-webhooks#security) of the signature-generating algorithm (`v1`)
2. The [`Revolut-Request-Timestamp` header](/docs/guides/manage-accounts/webhooks/about-webhooks#security)
3. The [raw webhook payload](/docs/guides/manage-accounts/webhooks/about-webhooks#webhook-examples) without whitespaces

```shell
payload_to_sign = {version}.{timestamp}.{raw_payload}
```

An example of `payload_to_sign` might look like this:

```shell
v1.1683650202360.{"data":{"id":"645a7696-1234-aa47-1234-cbae0449cc46","new_state":"completed","old_state":"pending","request_id":"app_charges-9f5d5eb3-1234-1234-1234-3914763e0bcb"},"event":"TransactionStateChanged","timestamp":"2023-05-09T16:36:38.028960Z"}
```

:::warning
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:

- The [signing secret for the webhook](/docs/guides/manage-accounts/webhooks/about-webhooks#webhook-signing-secret) as the key
- The payload to sign (prepared in the [previous step](#1-prepare-the-payload-to-sign)) as the message

You can use the following Python implementation for reference:

```python [Computation of the expected signature in Python] {10}
import hmac
import hashlib

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

raw_payload = '{"data":{"id":"645a7696-22f3-aa47-9c74-cbae0449cc46","new_state":"completed","old_state":"pending","request_id":"app_charges-9f5d5eb3-1e06-46c5-b1c0-3914763e0bcb"},"event":"TransactionStateChanged","timestamp":"2023-05-09T16:36:38.028960Z"}'
timestamp = '1683650202360'
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 (or one of the [multiple signatures](/docs/guides/manage-accounts/webhooks/about-webhooks#security)) sent in that header.

:::tip
To ensure the accuracy of your implementation, you can validate it by checking against the test data that we prepared:

- **Revolut-Signature** header: `v1=bca326fb378d0da7f7c490ad584a8106bab9723d8d9cdd0d50b4c5b3be3837c0`
- **Revolut-Request-Timestamp** header: `1683650202360`
- **payload_to_sign**: ```v1.1683650202360.{"data":{"id":"645a7696-22f3-aa47-9c74-cbae0449cc46","new_state":"completed","old_state":"pending","request_id":"app_charges-9f5d5eb3-1e06-46c5-b1c0-3914763e0bcb"},"event":"TransactionStateChanged","timestamp":"2023-05-09T16:36:38.028960Z"}```
- **signing_secret**: `wsk_r59a4HfWVAKycbCaNO1RvgCJec02gRd8`
:::

:::warning
We recommend that you test your implementation of webhook signature validation in the Sandbox environment before implementing it in production.
:::