Notifications on Callback URL
The merchant will receive notifications on the Callback URL with the final payment response, which contains the transaction status and relevant details (e.g., qrStatus
, payId
, amount
, etc).
Based on these notifications, the merchant must ensure the delivery of the service or product to the buyer.
A notification is considered successfully received if the merchant’s server responds with HTTP status code 200 OK.
Notification structure (Example)
{
"result": {
"qrId": "789e0123-f456-7890-a123-456789012345",
"extensionId": "40e6ba44-7dff-48cc-91ec-386a38318c68",
"qrStatus": "Paid",
"payId": "123e4567-e89b-12d3-a456-426614174000",
"referenceId": "QR000123456789",
"orderId": "789e0123-e89b-45d6-b789-426614174111",
"amount": 100.50,
"commission": 2.50,
"currency": "MDL",
"payerName": "John D.",
"payerIban": "MD24AG000225100013104168",
"executedAt": "2029-10-22T10:32:28+03:00",
"terminalId": "P011111"
},
"signature": "5wHkZvm9lFeXxSeFF0ui2CnAp7pCEFSNmuHYFYJlC0s="
}
Notification parameters
result
object
Response result object.
result.qrId
string(guid)
QR unique identifier.
result.extensionId
string(guid)
QR extension identifier.
result.qrStatus
string(enum)
QR status.
Possible values: Active, Paid.
result.payId
string(guid)
Payment unique identifier.
result.referenceId
string(15)
Instant payments servicer RRN.
result.orderId
string(100)
Merchant-side order identifier.
result.amount
number(decimal)
Payment amount.
result.commission
number(decimal)
Payment commission.
result.currency
string(enum)
Payment currency.
Possible values: MDL.
Format: ISO 4217.
result.payerName
string(200)
Payer abbreviated name.
Eg: "John D."
result.payerIban
string(200)
Payer IBAN (International Bank Account Number).
result.executedAt
string(datetime)
Timestamp of the payment execution.
Format: ISO 8601-1:2019.
(e.g., "2029-10-22T10:32:28+03:00")
result.terminalId
string(100)
Terminal id, provided by bank
signature
string
Notification validation signature
Signature validation
To verify the integrity and authenticity of the received data, the Merchant must validate the signature
field from the result
object using the following algorithm:
All fields in the
result
object shall be sorted in alphabetical order, excluding thesignature
field. Sorting must be case-insensitive.Ignore fields that have a
null
value or an empty string (""
). These fields should be excluded entirely from the signature generation process, as if they do not exist.Format amount fields (
amount
,commission
) using exactly two decimal places (e.g.,0.50
,2.31
) before concatenation.Concatenate the remaining parameter values using a colon (
:
) as a separator, in the sorted order.Append the Signature Key (available in the project settings in maibmerchants) to the end of the concatenated string.
Generate a SHA-256 hash in binary format from the resulting string.
Encode the binary hash using Base64 (or another format as specified in the official QR MIA documentation).
Compare the resulting encoded signature with the
signature
value received in the notification.
Signature validation example
<?php
$key = "signature-key-from-project-settings"; // Signature Key obtained
// Get the JSON content received on the Callback URL
$json = file_get_contents('php://input');
$data = json_decode($json, true);
if (isset($data['result']['signature'])) {
$signatureReceived = $data['result']['signature'];
$dataResult = $data['result'];
// Remove the signature from the data to be validated
unset($dataResult['signature']);
// Alphabetically sort the fields in the result object
uksort($dataResult, 'strcasecmp');
// Recursive function to concatenate values with ':' separator
function implodeRecursive($separator, $array) {
$result = '';
foreach ($array as $item) {
if (is_array($item)) {
$result .= implodeRecursive($separator, $item) . $separator;
} else {
$result .= (string)$item . $separator;
}
}
return substr($result, 0, -1); // remove the last separator
}
// Build the signature string
$signString = implodeRecursive(':', $dataResult) . ':' . $key;
// Generate binary SHA256 hash
$hash = hash('sha256', $signString, true);
// Encode the hash in Base64
$signatureCalculated = base64_encode($hash);
// Compare the calculated signature with the received one
if ($signatureCalculated === $signatureReceived) {
http_response_code(200);
echo "Signature is valid.";
// Process the transaction data here
} else {
http_response_code(400);
echo "Signature is invalid.";
}
} else {
http_response_code(400);
echo "No signature provided.";
}
Recommendations
Ensure that your server is accessible from maib IPs to receive the notifications.
Respond with HTTP status 200 OK only after successfully verifying the signature.
In case of errors or invalid signature, respond with a status code different from 200 to force the notification to be resent.
Last updated