API Docs
Webhooks
API ReferenceWebhooksSignature Verification

Signature Verification

Verify webhook authenticity using HMAC signatures.

How It Works

Signed webhook requests include an X-Webhook-Signature-512 header containing an HMAC-SHA512 signature of the raw request body. Verify this signature to ensure the webhook was sent by ReliancePays.

Do not verify against parsed or reserialized JSON, because even harmless formatting changes alter the signature input.

Verification Steps

  1. Extract the X-Webhook-Signature-512 header from the request
  2. Compute an HMAC-SHA512 of the raw request body using your webhook secret
  3. Compare the computed signature with the one in the header
  4. Reject the request if signatures don't match
  5. Process each event_id once
  6. Parse the JSON payload only after signature verification succeeds

Code Examples

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha512', secret)
    .update(payload)
    .digest('hex');

  return signature.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

// In your webhook handler:
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature-512'];

  if (!signature || !verifyWebhookSignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(400).send('Invalid signature');
  }

  // Process the event...
  res.status(200).send('OK');
});
import hmac
import hashlib

def verify_webhook_signature(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha512
    ).hexdigest()

    return hmac.compare_digest(signature, expected)

# In your webhook handler:
@app.route('/webhooks', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-Webhook-Signature-512')

    if not verify_webhook_signature(request.data, signature, WEBHOOK_SECRET):
        return 'Invalid signature', 400

    # Process the event...
    return 'OK', 200
<?php
function verifyWebhookSignature($payload, $signature, $secret) {
    $expected = hash_hmac('sha512', $payload, $secret);
    return hash_equals($expected, $signature);
}

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE_512'] ?? '';

if (!verifyWebhookSignature($payload, $signature, WEBHOOK_SECRET)) {
    http_response_code(400);
    echo 'Invalid signature';
    exit;
}

// Process the event...
http_response_code(200);
echo 'OK';

Always verify webhook signatures in production. Never skip verification, as it protects against forged webhook requests.