Sign in
Einführung/Webhook-Benachrichtigungen

Webhook-Benachrichtigungen

Erhalten Sie Statusaktualisierungen für Zahlungen und Auszahlungen in Echtzeit über HMAC-signierte Webhooks.

Das System von 2328.io sendet einen Webhook an Ihre url_callback, sobald sich der Status einer Zahlung ändert. Dies ist die empfohlene Methode, um über erfolgreiche Zahlungen benachrichtigt zu werden.

Anfrageformat

  • Methode: POST
  • Content-Type: application/json
  • Signatur: Feld sign im Anfrage-Body

Payload

Der Webhook-Body ist identisch mit der Antwort von /v1/payment/info, ergänzt um ein sign-Feld zur Signaturprüfung.

Erfolgreiche Zahlung

JSON
{
  "uuid": "db17d490-15b6-47b9-9015-91d1d8b119f2",
  "order_id": "ORDER-12345",
  "amount": "180.00000000",
  "currency": "RUB",
  "url": "https://go.2328.io/db17d490-15b6-47b9-9015-91d1d8b119f2",
  "expires_at": "2026-05-09T16:56:58+03:00",
  "created_at": "2026-05-09T15:56:58+03:00",
  "payer_currency": "TON",
  "payer_amount": "0.95256917",
  "network": "TON",
  "address": "UQA0RevhkCQx-EltyNgPPeG8dqtnCz7ZslOzMdNQlLxVaNBb",
  "payment_status": "paid",
  "txid": "41c2a327323480af8e705d05deb09c238a41779928832abef4bb77c862357b11",
  "payment_amount": "0.95256917",
  "merchant_amount": "0.949711462490000000",
  "amount_usd": "2.41324380",
  "exchange_rate": "0.01340691",
  "sign": "6f8c15b6e53b506d5bfa38ed3fb3b50697af73434262153c02e412541372f04d"
}

Stornierte / fehlgeschlagene Zahlung

Wenn sich die Zahlung nicht im finalen Zustand paid befindet, sind txid, payment_amount und merchant_amount null:

JSON
{
  "uuid": "48edaf2d-2c49-4638-8f86-88636f661c1f",
  "order_id": "ORDER-12345",
  "amount": "2800.00000000",
  "currency": "RUB",
  "url": "https://go.2328.io/48edaf2d-2c49-4638-8f86-88636f661c1f",
  "expires_at": "2026-05-09T06:19:04+03:00",
  "created_at": "2026-05-09T05:19:04+03:00",
  "payer_currency": "ETH",
  "payer_amount": "0.01620968",
  "network": "ETH-ERC20",
  "address": "0x37c20d6d96d130Bc5B33D832e43b8e16aACe0c59",
  "payment_status": "cancel",
  "txid": null,
  "payment_amount": null,
  "merchant_amount": null,
  "amount_usd": "37.53934800",
  "exchange_rate": "0.01340691",
  "sign": "40ce68ad9691ad54e684329d75ab5adaf5b01409a2d18d3e0110b8c1be605342"
}

Feldreferenz

FeldTypBeschreibung
uuidstringZahlungs-UUID
order_idstringIhre Bestell-ID
amountdecimal (8 dp)Fiat-Betrag in currency
currencystringVom Händler angeforderte Fiat-Währung
urlstringURL des gehosteten Checkouts
expires_atstring (ISO 8601)Zeitpunkt, an dem die Zahlungssitzung abläuft
created_atstring (ISO 8601)Zeitpunkt, an dem die Zahlungssitzung erstellt wurde
payer_currencystringKrypto, in der der Zahler bezahlt
payer_amountdecimal (8 dp)Erwarteter Krypto-Betrag
networkstringBlockchain-Netzwerk
addressstringEinzahlungsadresse
payment_statusstringEiner von: pending, check, paid, underpaid_check, underpaid, overpaid, cancel, aml_lock (siehe References)
txidstring | nullHash der Blockchain-Transaktion, nur nach bestätigter Zahlung vorhanden
payment_amountdecimal | nullTatsächlich gezahlter Betrag, nur nach Zahlung vorhanden
merchant_amountdecimal (18 dp) | nullDem Händler nach Gebühren gutgeschriebener Betrag
amount_usddecimal (8 dp)Betrag in USD zum Zeitpunkt der Erstellung
exchange_ratedecimalVerwendeter Krypto-/Fiat-Wechselkurs
signstring (hex)HMAC-SHA256-Signatur des payload

Signatur verifizieren

So verifizieren Sie eine Webhook-Signatur:

  1. Extrahieren Sie das Feld sign aus dem payload
  2. Entfernen Sie das Feld sign aus dem Objekt
  3. Codieren Sie die übrigen Felder als JSON
  4. Codieren Sie das JSON in base64
  5. Berechnen Sie HMAC-SHA256 vom Base64-String unter Verwendung Ihres API_KEY
  6. Vergleichen Sie die berechnete Signatur mit dem Wert sign mittels eines konstantzeitigen Vergleichs
PHP
<?php
function verifyWebhookSign(array $data, string $apiKey): bool {
    $receivedSign = $data['sign'] ?? '';
    unset($data['sign']);

    $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $base64 = base64_encode($json);
    $calculated = hash_hmac('sha256', $base64, $apiKey);

    return hash_equals($calculated, $receivedSign);
}

$apiKey = 'YOUR_API_KEY';
$payload = json_decode(file_get_contents('php://input'), true);

if (!verifyWebhookSign($payload, $apiKey)) {
    http_response_code(401);
    exit;
}

switch ($payload['payment_status']) {
    case 'paid':
    case 'overpaid':
        // Credit the order — check idempotency by order_id first
        break;
    case 'underpaid_check':
    case 'underpaid':
    case 'cancel':
        break;
}

http_response_code(200);

Verifizieren Sie immer die Signatur, bevor Sie einem Nutzer Mittel gutschreiben. Ein nicht oder falsch signierter Webhook könnte eine gefälschte Anfrage sein.

Auszahlungs-Webhooks

Wenn sich der status einer Auszahlung ändert, sendet das System einen POST-Webhook an die url_callback-URL, die bei der Erstellung der Auszahlung übergeben wurde. Wurde keine url_callback angegeben, werden für diese Auszahlung keine Webhooks gesendet.

Auszahlungs-Webhooks müssen mit Ihrem Payout-API-Schlüssel verifiziert werden — nicht mit dem regulären API-Schlüssel. Der Signieralgorithmus ist identisch zu dem für Zahlungs-Webhooks (Feld sign entfernen, JSON-codieren, base64, HMAC-SHA256), nur der Schlüssel ist ein anderer.

Payload

JSON
{
  "uuid": "019dff1f-0dbd-7277-8d45-271e7775388f",
  "order_id": "4dfdcc84402b1185b71cbe399321533e",
  "status": "completed",
  "currency": "TRX",
  "network": "TRX-TRC20",
  "amount": "3.00",
  "merchant_amount": "3.00",
  "network_amount": "3.00",
  "amount_usd": "1.04",
  "to_address": "THauRv5tcucQRohXg8NiyGTk16DX1XQG5x",
  "memo": null,
  "txid": "9242e533703704ef3eaba840f70b4a26333e72c943377ee375fea17badb53def",
  "block_number": null,
  "error_type": null,
  "created_at": "2026-05-07T00:08:38+03:00",
  "updated_at": "2026-05-07T00:08:54+03:00",
  "from_currency": "USDT",
  "debited_amount": "1.050735",
  "debited_currency": "USDT",
  "sign": "925ad7bf3d6841864101f7cc2c7e30652e70a06cdb04dbe07a0129480000ce4a"
}

Feldreferenz

FeldTypBeschreibung
uuidstringAuszahlungs-UUID
order_idstringIhre Idempotenz- / Referenz-ID, sofern angegeben
statusstringpending, completed, failed, cancelled (siehe References)
currencystringAuszahlungswährung
networkstringBlockchain-Netzwerk
amountdecimalAuszahlungsbetrag (in currency)
merchant_amountdecimalVom Händlerguthaben belasteter Betrag
network_amountdecimalTatsächlich on-chain gesendeter Betrag
amount_usddecimalUSD-Wert zum Zeitpunkt der Auszahlung
to_addressstringBlockchain-Adresse des Empfängers
memostring | nullMemo / Destination-Tag, falls verwendet
txidstring | nullHash der Blockchain-Transaktion, gesetzt bei completed
block_numberinteger | nullBlockhöhe der on-chain-Transaktion
error_typestring | nullFehlerursache, wenn status = failed (z. B. aml_risk, siehe References)
created_atstring (ISO 8601)Zeitpunkt, an dem die Auszahlung erstellt wurde
updated_atstring (ISO 8601)Zeitpunkt der letzten Statusänderung
from_currencystringQuell-Guthaben, von dem die Auszahlung bei automatischer Umrechnung abgebucht wurde (z. B. USDT für eine BTC-Auszahlung)
debited_amountdecimalVom from_currency-Guthaben abgebuchter Betrag
debited_currencystringWährung der Abbuchung
signstring (hex)HMAC-SHA256-Signatur des payload, signiert mit dem Payout-API-Schlüssel

Best Practices

  • Idempotenz — Prüfen Sie stets, ob die Zahlung bereits verarbeitet wurde (anhand von order_id oder uuid). Webhooks können mehrfach eintreffen.
  • Schnelle Antwort — Antworten Sie so schnell wie möglich mit HTTP 200. Lagern Sie aufwändige Arbeit in eine Hintergrund-Queue aus.
  • Wiederholungen — Erhält das System keine HTTP-200-Antwort, wird der Webhook nach 2 Minuten erneut gesendet. Maximal 5 Wiederholungsversuche.
  • Asynchrone Verarbeitung — Verarbeiten Sie Webhook-Ereignisse asynchron, um die Antwort nicht zu blockieren.
  • Sicherheit — Verifizieren Sie IMMER die sign-Signatur, bevor Sie dem payload vertrauen.

Webhooks können in beliebiger Reihenfolge eintreffen. Gehen Sie nicht davon aus, dass der erste empfangene Webhook der finale Zustand ist — rufen Sie bei Unsicherheit immer erneut über /v1/payment/info (oder /v1/payout/status/{uuid}) ab.