Signature Key Verification
This section provides implementation examples for verifying the authenticity of requests using a signature key, which helps ensure the integrity and security of the received data (e.g., webhook events).
The signature is usually included in the request headers and must be validated by computing a hash using a shared secret key. Below are examples in different languages.
.NET
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Nodes;
var jsonMessage = "[CALLBACK MESSAGE]";
var signatureKey = "[YOUR SIGNATURE KEY]";
var jsonNode = JsonNode.Parse(jsonMessage);
var resultElement = jsonNode!["result"]!;
var keys = new Dictionary<string, string>();
foreach (var property in (JsonObject)resultElement)
{
var valueNode = property.Value;
if (valueNode is null)
continue;
string valueStr = property.Key is "amount" or "commission"
? valueNode.GetValue<decimal>().ToString("F2")
: valueNode.ToString();
if (!string.IsNullOrWhiteSpace(valueStr))
keys.Add(property.Key, valueStr);
}
var orderedKeys = keys.OrderBy(kv => kv.Key, StringComparer.OrdinalIgnoreCase).ToArray();
var additionalString =
string.Join(":", orderedKeys.Select(kv => kv.Value));
var hash = SHA256.HashData(Encoding.UTF8.GetBytes($"{additionalString}:{signatureKey}"));
var result = Convert.ToBase64String(hash);
if (result == jsonNode["signature"]!.ToString())
Console.WriteLine("Signature is valid");
else
Console.WriteLine("INVALID SIGNATURE!");
.PHP
<?php
$jsonMessage = '[CALLBACK MESSAGE]';
$signatureKey = '[YOUR SIGNATURE KEY]';
$jsonNode = json_decode($jsonMessage, true);
$resultElement = $jsonNode['result'] ?? [];
$expectedSignature = $jsonNode['signature'] ?? '';
$keys = [];
foreach ($resultElement as $key => $value) {
if (is_null($value)) {
continue;
}
// Format "amount" and "commission" with 2 decimal places
if ($key === 'amount' || $key === 'commission') {
$valueStr = number_format((float)$value, 2, '.', '');
} else {
$valueStr = (string)$value;
}
if (trim($valueStr) !== '') {
$keys[$key] = $valueStr;
}
}
// Sort keys by key name (case-insensitive)
uksort($keys, 'strcasecmp');
// Build the string to hash
$additionalString = implode(':', $keys);
$hashInput = $additionalString . ':' . $signatureKey;
// Generate SHA256 hash and base64-encode it
$hash = hash('sha256', $hashInput, true);
$result = base64_encode($hash);
// Compare the result with the signature
if ($result === $expectedSignature) {
echo "Signature is valid\n";
} else {
echo "INVALID SIGNATURE!\n";
}
node.js
const crypto = require('crypto');
const jsonMessage = '[CALLBACK MESSAGE]';
const signatureKey = '[YOUR SIGNATURE KEY]';
const jsonNode = JSON.parse(jsonMessage);
const resultElement = jsonNode.result || {};
const expectedSignature = jsonNode.signature || '';
const keys = {};
// Collect and format values
for (const [key, value] of Object.entries(resultElement)) {
if (value === null || value === undefined) continue;
let valueStr;
if (key === 'amount' || key === 'commission') {
valueStr = parseFloat(value).toFixed(2); // Always two decimals
} else {
valueStr = String(value);
}
if (valueStr.trim() !== '') {
keys[key] = valueStr;
}
}
// Sort keys case-insensitively
const orderedKeys = Object.keys(keys).sort((a, b) =>
a.toLowerCase().localeCompare(b.toLowerCase())
);
// Join values with colon
const additionalString = orderedKeys.map(k => keys[k]).join(':');
const hashInput = `${additionalString}:${signatureKey}`;
// Hash and base64 encode
const hash = crypto.createHash('sha256').update(hashInput, 'utf8').digest('base64');
// Compare with expected signature
if (hash === expectedSignature) {
console.log('Signature is valid');
} else {
console.log('INVALID SIGNATURE!');
}
Last updated