Notificări pe Callback URL

Merchant-ul va primi notificări pe Callback URL cu răspunsul final al plății, ce conține starea tranzacției și detalii relevante (ex. qrStatus, payId, amount, etc).

Pe baza acestor notificări, Merchant-ul trebuie să asigure livrarea serviciului sau produsului către Cumpărător.

Se consideră că notificarea a fost recepționată cu succes dacă serverul Merchant-ului răspunde cu codul HTTP 200 OK.


Structura notificării (Exemplu)

{
    "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="
}

Parametrii notificării

Parametru
Tip
Descriere

result

object

Obiect rezultat răspuns

result.qrId

string(guid)

Identificator unic QR

result.extensionId

string(guid)

Identificator extensie QR

result.qrStatus

string(enum)

Stare QR. Valori posibile: Activ, Plătit

result.payId

string(guid)

Identificator unic plată

result.referenceId

string(15)

RRN serviciu plăți instant

result.orderId

string(100)

Identificator comandă partea comerciantului

result.amount

number(decimal)

Sumă plată

result.commission

number(decimal)

Comision plată

result.currency

string(enum)

Moneda plată. Valori posibile: MDL Format: ISO 4217

result.payerName

string(200)

Nume prescurtat plătitor. Ex: „John D.”

result.payerIban

string(200)

IBAN plătitor (Număr internațional cont bancar)

result.executedAt

string(datetime)

Marcă temporală executare plată. Format: ISO 8601-1:2019 (ex., „2029-10-22T10:32:28+03:00”)

result.terminalId

string(100)

Id terminal, furnizat de bancă

signature

string

Semnătură validare notificare


Validarea semnăturii

Pentru a verifica integritatea și autenticitatea datelor primite, semnătura (signature) din obiectul result trebuie validată utilizând următorul algoritm:

  1. Toate câmpurile din obiectul result trebuie sortate în ordine alfabetică, cu excepția câmpului signature. Sortarea trebuie să fie insensibilă la majuscule/minuscule.

  2. Câmpurile care au valoarea null sau șirul gol ("") sunt complet ignorate în procesul de generare a semnăturii, ca și cum nu ar exista.

  3. Câmpurile de tip sumă (amount, commission) se formatează cu exact două zecimale (ex: 0.50, 2.31) înainte de concatenare.

  4. Valorile câmpurilor rămase se concatenează folosind caracterul două puncte (:) ca separator, în ordinea sortată.

  5. La finalul șirului concatenat se adaugă cheia de semnătură (Signature Key), disponibilă în setările proiectului din platforma maibmerchants.

  6. Din șirul rezultat se generează un hash în format binar folosind algoritmul SHA-256.

  7. Hash-ul binar este apoi codificat în format Base64 (sau alt format specificat în documentația oficială QR MIA).

  8. Semnătura generată se compară cu valoarea câmpului signature primit în notificare.

Dacă valorile coincid, semnătura este considerată validă, iar datele sunt autentice și intacte.


Exemplu pentru validarea semnăturii

phpCopyEdit<?php
$key = "signature-key-from-project-settings"; // Signature Key obținută din maibmerchants

// Preluăm conținutul JSON primit pe 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'];

    // Scoatem semnătura din datele de validat
    unset($dataResult['signature']);

    // Sortăm alfabetic câmpurile din obiectul result
    uksort($dataResult, 'strcasecmp');

    // Funcție recursivă de concatenare a valorilor cu separatorul ':'
    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); // eliminăm ultimul separator
    }

    // Construim șirul de semnătură
    $signString = implodeRecursive(':', $dataResult) . ':' . $key;

    // Generăm hash SHA256 binar
    $hash = hash('sha256', $signString, true);

    // Codificăm hash-ul în Base64
    $signatureCalculated = base64_encode($hash);

    // Comparăm semnătura calculată cu cea primită
    if ($signatureCalculated === $signatureReceived) {
        http_response_code(200);
        echo "Signature is valid.";
        // Procesați datele tranzacției aici
    } else {
        http_response_code(400);
        echo "Signature is invalid.";
    }
} else {
    http_response_code(400);
    echo "No signature provided.";
}

Recomandări

  • Asigurați-vă că serverul vostru este accesibil de pe IP-urile maib pentru a primi notificările.

  • Răspundeți cu cod HTTP 200 OK doar după ce ați verificat cu succes semnătura.

  • În caz de erori sau semnătură invalidă, răspundeți cu un cod diferit de 200 pentru a forța retrimiterea notificării.

Last updated