Skip to content

Checking webhook signatures

Verify the data CryptoSwift sends to your webhook endpoint

CryptoSwift signs each webhook request it sends to your webhook URL by including a signature in the CryptoSwift-Signature header. This allows you to verify that the request was made by CryptoSwift and not someone claiming to be CryptoSwift.

To verify signatures, you need to retrieve your webhook secret. You can access your webhook secret using the API.

Please note that the webhook secret is generated automatically each time after you register you webhook URL. After the webhook URL has been set up, CryptoSwift starts signing each webhook request it sends to the endpoint.


Verifying signatures

The CryptoSwift-Signature header included in each signed request contains a timestamp the signature:

  • The timestamp is prefixed by t=
  • The signature is prefixed by s=
cryptoswift-signature: t=1676540660052,s=a18b9a8c30b896374efa6d5f3026b0e36f249561e649fc94b5e500a7ef24d10d

Signatures are generated using a hash-based message authentication code (HMAC) with SHA-256.

1. Extract the timestamp and signature from the header

Split the header using the , character as the separator to separate the timestamp and signature. Then split both elements using the = character as the separator to get the corresponding values.

2. Prepare the signed payload

The signed payload string is created by concatenating:

  • The timestamp part from the custom header
  • The character .
  • The actual request JSON payload that you received in the request body

It will look something like:

const payload = `1676540660052.{"id":"418fec4a-8ba6-4b35-9c05-a9aa80de31c4","status":"NEW","asset":"BTC","amount":69,"blockchainInfo":{"transactionHash":"6146ccf6a66d994f7c363db875e31ca35581450a4bf6d3be6cc9ac79233a69d0","origin":"0xb794f5ea0ba39494ce839613fffba74279579268","destination":"0x71C7656EC7ab88b098defB751B7401B5f6d8976E","destinationType":"CUSTODIAL"},"vaspInfo":{"beneficiaryVaspName":"SwiftCryptoExchange","beneficiaryVaspEmail":"info@SwiftCryptoExchange.domain","beneficiaryVaspExtraInfo":"Tel +372 1234 5678"},"originator":{"type":"NATURAL","name":"Guy Hillar","accountNumber":"04143282398","address":"Alexanderplatz 25, Berlin","country":"Germany","nationalIdentificatorType":"IDC","nationalIdentificator":"DE123456789","customerNumber":"A5433634","dateOfBirth":"1991","placeOfBirth":"Germany"},"beneficiary":{"type":"LEGAL","name":"Maria LLC","accountNumber":"AB54234232","country":"Estonia","nationalIdentificatorType":"IDC","nationalIdentificator":"EE11234566"}}`

3. Compute the expected signature

Compute an HMAC with the SHA256 hash function: use your webhook secret as the key, and use the payload string as the message.

const crypto = require('crypto');

const signature = crypto.createHmac('sha256', webhookSecret)
    // Data to be encoded
    .update(payload)
    // Defining encoding type
    .digest('hex');

4. Compare signatures

Compare the expected signature to the signature from the header.

You can also compare the difference between the current timestamp and the timestamp from the webhook request header to protect yourself from replay attacks. As the webhook request timestamp is part of the signed payload, it is also verified by the signature. This means that possible attackers can not change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.

We recommend a tolerance of five minutes between the header timestamp and the current time.

Next steps