payout / developers
Guide

Checkout verification webhook

On this page

Payout sends the checkout.verification webhook when a bank payment is matched to a checkout during statement reconciliation. It carries the payer's name and IBAN from the bank statement, encrypted, so that you can verify the payer's identity.

The webhook is sent only for bank payment methods: bank transfer, bank button and PIS.

Note

To receive this webhook, ask support to enable the webhook_verification feature for your account.

Webhook payload

checkout.verification payload:

JSON
{
    "external_id": "order-5001",
    "object": "webhook",
    "type": "checkout.verification",
    "data": {
        "object": "checkout",
        "id": 141801,
        "external_id": "order-5001",
        "amount": 300,
        "currency": "EUR",
        "redirect_url": "https://eshop.example.com/payment/redirect",
        "customer": {
            "first_name": "John",
            "last_name": "Doe",
            "email": "[email protected]",
            "iban": null
        },
        "account_details": {
            "name": "H24qnEt9A+haL5xh1Ljgc1gmpo22ULK5W+OIaKskz5w=",
            "iban": "jD1ef5obLE1ujwobPF1+n0RKaiEIcFXcRgJZrCrUNz60s7X2m1SQ9OWLTm3suiRA"
        },
        "payment": {
            "object": "payment",
            "status": "successful",
            "payment_method": "bank_transfer",
            "failure_reason": "",
            "created_at": 1759744800,
            "fee": 8,
            "net": 292
        },
        "metadata": {},
        "status": "succeeded",
        "is_status_final": true
    },
    "nonce": "Sk9RR2EycmIxOUZsWTBtRw",
    "signature": "79be670c341f6acfb04cc1c8ac8f3a94ba296261b72a50c0770e658d82b78013"
}

account_details.name and account_details.iban hold the payer's name and IBAN, encrypted with AES-256-CBC. See Decrypting account details.

Signature verification

Verify signature as for every other webhook, see Simple payment:

TEXT
Pattern: external_id|type|nonce|client_secret
Input:   order-5001|checkout.verification|Sk9RR2EycmIxOUZsWTBtRw|q3dpHpYtDrH-KmGD4HMn5OTEx6IsZPBokQ8CqMONWqMSEePWy9bXd3Ua3KvO7f6C
SHA-256: 79be670c341f6acfb04cc1c8ac8f3a94ba296261b72a50c0770e658d82b78013

Note

The hash is in lowercase hex. Some libraries return uppercase hex; convert it to lowercase before you compare it.

Decrypting account details

Each encrypted value is decrypted with a key derived from the client_id of your API key:

  1. Derive the key

    Hash client_id with SHA-512, encode the hash as lowercase hex and take the first 32 characters. Use these 32 characters as the 32-byte key, as they are; don't hex-decode them.

  2. Split the value

    Base64-decode the value. The first 16 bytes are the IV, the rest is the ciphertext.

  3. Decrypt

    Decrypt the ciphertext with AES-256-CBC and remove the PKCS#7 padding.

In Node.js:

JavaScript
const crypto = require("crypto");

function decryptAccountDetail(clientId, value) {
    const key = crypto.createHash("sha512").update(clientId).digest("hex").slice(0, 32);
    const data = Buffer.from(value, "base64");
    const decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(key, "utf8"), data.subarray(0, 16));
    return Buffer.concat([decipher.update(data.subarray(16)), decipher.final()]).toString("utf8");
}

decryptAccountDetail("DC995618-7ED8-4070-9DA0-48B6F86551C3", "H24qnEt9A+haL5xh1Ljgc1gmpo22ULK5W+OIaKskz5w=");
// "John Doe"

With the client_id from the examples, DC995618-7ED8-4070-9DA0-48B6F86551C3, the key is 7d47c1ea4bafb442ea5a1ecf114b871c, and the payload above decrypts to John Doe and SK3112000000198742637541.

Retrieve checkout encrypts the payer details of bank payments the same way.

Was this page helpful?