Verifying Webhook Requests

To ensure the authenticity and integrity of the webhook requests you receive from our service, we include an HMAC signature and timestamp in the request headers. Here's how you can verify the requests in your preferred programming language:

  1. Extract the X-Signature and X-Timestamp headers from the incoming request.

  2. Prepare the payload by:

    • If the webhook indicates additional data, concatenating the additionalData and timestamp separated by a dot (.),

    • If the webhook does not indicate any additional data, the timestamp itself can be used as the payload

  3. Generate an HMAC signature using the SHA256 algorithm and the shared secret key.

  4. Compare the generated signature with the received X-Signature. If they match, the request is authentic.

  5. Check if the timestamp is within an acceptable time window (e.g., 5 minutes) to prevent replay attacks.

circle-info

You can find the additional data indications for each webhook in its documentation page.

Here are code samples for verifying webhook requests in different programming languages:

JS

const crypto = require('crypto');

const webhookSecret = "your-shared-secret";

const verifyOrderWebhook = (req, res, next) => {
  const signature = req.headers['x-signature'];
  const timestamp = parseInt(req.headers['x-timestamp'], 10);
  const orderId = req.body.orderId;

  const currentTimestamp = Math.floor(Date.now() / 1000);
  if (Math.abs(currentTimestamp - timestamp) > 300) {
    return res.status(401).json({ error: 'Webhook request is too old' });
  }

  const payload = orderId + '.' + timestamp;
  const hmac = crypto.createHmac('sha256', webhookSecret);
  hmac.update(payload);
  const computedSignature = hmac.digest('hex');

  if (computedSignature !== signature) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  next();
};

const verifyWebhook = (req, res, next) => {
  const signature = req.headers['x-signature'];
  const timestamp = parseInt(req.headers['x-timestamp'], 10);

  const currentTimestamp = Math.floor(Date.now() / 1000);
  if (Math.abs(currentTimestamp - timestamp) > 300) {
    return res.status(401).json({ error: 'Webhook request is too old' });
  }

  const payload = timestamp;
  const hmac = crypto.createHmac('sha256', webhookSecret);
  hmac.update(payload);
  const computedSignature = hmac.digest('hex');

  if (computedSignature !== signature) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  next();
};

Java

PHP

C#

Go

Last updated