> For the complete documentation index, see [llms.txt](https://docs.maibmerchants.md/mia-qr-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.maibmerchants.md/mia-qr-api/en/examples/signature-key-verification.md).

# 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.

<mark style="color:purple;">**.NET**</mark>

```csharp
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!");
```

<mark style="color:purple;">**.PHP**</mark>

```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";
}
```

<mark style="color:purple;">**node.js**</mark>

```csharp
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!');
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.maibmerchants.md/mia-qr-api/en/examples/signature-key-verification.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
