Sign in
Pengantar/Notifikasi Webhook

Notifikasi Webhook

Terima pembaruan status pembayaran dan penarikan secara real-time melalui webhook yang ditandatangani HMAC.

Sistem 2328.io mengirim webhook ke url_callback Anda setiap kali status pembayaran berubah. Ini adalah cara yang direkomendasikan untuk mendapatkan notifikasi tentang pembayaran sukses.

Format permintaan

  • Method: POST
  • Content-Type: application/json
  • Tanda tangan: field sign di body permintaan

Payload

Body webhook identik dengan respon /v1/payment/info, ditambah field sign yang digunakan untuk verifikasi tanda tangan.

Pembayaran sukses

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

Pembayaran dibatalkan / gagal

Saat pembayaran tidak dalam status terminal paid, txid, payment_amount, dan merchant_amount adalah 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"
}

Referensi field

FieldTipeDeskripsi
uuidstringUUID pembayaran
order_idstringID pesanan Anda
amountdecimal (8 dp)Jumlah fiat dalam currency
currencystringMata uang fiat yang diminta merchant
urlstringURL checkout terhosting
expires_atstring (ISO 8601)Saat sesi pembayaran kedaluwarsa
created_atstring (ISO 8601)Saat sesi pembayaran dibuat
payer_currencystringKripto yang dibayarkan oleh pembayar
payer_amountdecimal (8 dp)Jumlah kripto yang diharapkan
networkstringJaringan blockchain
addressstringAlamat deposit
payment_statusstringSalah satu dari: pending, check, paid, underpaid_check, underpaid, overpaid, cancel, aml_lock (lihat References)
txidstring | nullHash tx blockchain, hadir hanya setelah pembayaran terkonfirmasi
payment_amountdecimal | nullJumlah aktual yang dibayar, hadir hanya setelah pembayaran
merchant_amountdecimal (18 dp) | nullJumlah yang dikreditkan ke merchant setelah biaya
amount_usddecimal (8 dp)Jumlah dalam USD pada saat pembuatan
exchange_ratedecimalNilai tukar Kripto / fiat yang digunakan
signstring (hex)Tanda tangan HMAC-SHA256 dari payload

Memverifikasi tanda tangan

Untuk memverifikasi tanda tangan webhook:

  1. Ekstrak field sign dari payload
  2. Hapus field sign dari objek
  3. Encode field yang tersisa sebagai JSON
  4. Encode JSON tersebut ke Base64
  5. Hitung HMAC-SHA256 dari string Base64 menggunakan API_KEY Anda
  6. Bandingkan tanda tangan yang dihitung dengan nilai sign menggunakan perbandingan constant-time
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);

Selalu verifikasi tanda tangan sebelum mengkreditkan dana apa pun ke pengguna. Webhook yang tidak ditandatangani atau ditandatangani secara tidak benar dapat menjadi permintaan palsu.

Webhook penarikan

Saat status sebuah penarikan berubah, sistem mengirim webhook POST ke URL url_callback yang diteruskan saat penarikan dibuat. Jika url_callback tidak disediakan, tidak ada webhook yang dikirim untuk penarikan tersebut.

Webhook penarikan harus diverifikasi dengan Payout API key Anda — bukan API key biasa. Algoritma penandatanganan identik dengan webhook pembayaran (hapus sign, encode JSON, base64, HMAC-SHA256), hanya key yang berbeda.

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

Referensi field

FieldTipeDeskripsi
uuidstringUUID penarikan
order_idstringID idempotensi / referensi Anda, jika Anda menyediakannya
statusstringpending, completed, failed, cancelled (lihat References)
currencystringMata uang penarikan
networkstringJaringan blockchain
amountdecimalJumlah penarikan (dalam currency)
merchant_amountdecimalJumlah yang dibebankan dari saldo merchant
network_amountdecimalJumlah yang sebenarnya dikirim on-chain
amount_usddecimalNilai USD pada saat penarikan
to_addressstringAlamat blockchain penerima
memostring | nullMemo / destination tag, jika digunakan
txidstring | nullHash transaksi blockchain, ditetapkan saat completed
block_numberinteger | nullTinggi blok dari transaksi on-chain
error_typestring | nullAlasan saat status = failed (mis. aml_risk, lihat References)
created_atstring (ISO 8601)Saat penarikan dibuat
updated_atstring (ISO 8601)Saat status terakhir berubah
from_currencystringSaldo sumber yang didebet untuk penarikan ketika konversi otomatis digunakan (mis. USDT untuk penarikan BTC)
debited_amountdecimalJumlah yang didebit dari saldo from_currency
debited_currencystringMata uang dari debit
signstring (hex)Tanda tangan HMAC-SHA256 dari payload, ditandatangani dengan Payout API key

Praktik terbaik

  • Idempotensi — Selalu periksa apakah pembayaran sudah diproses (berdasarkan order_id atau uuid). Webhook bisa tiba beberapa kali.
  • Respon cepat — Kembalikan HTTP 200 secepat mungkin. Pindahkan pekerjaan berat ke antrean latar belakang.
  • Retry — Jika sistem tidak menerima HTTP 200, webhook dikirim ulang setelah 2 menit. Maksimum 5 kali percobaan retry.
  • Pemrosesan async — Tangani event webhook secara asinkron untuk menghindari pemblokiran respon.
  • Keamanan — SELALU verifikasi tanda tangan sign sebelum mempercayai payload.

Webhook bisa tiba dengan urutan yang tidak sesuai. Jangan asumsikan webhook pertama yang Anda terima adalah status final — selalu ambil ulang melalui /v1/payment/info (atau /v1/payout/status/{uuid}) jika Anda perlu kepastian.