Sign in
Giriş/Webhook bildirimleri

Webhook Bildirimleri

HMAC ile imzalanmış webhook'lar üzerinden gerçek zamanlı ödeme ve çekim durumu güncellemeleri alın.

2328.io sistemi, bir ödeme durumu her değiştiğinde url_callback adresinize bir webhook gönderir. Başarılı ödemeler hakkında bildirim almanın önerilen yolu budur.

İstek formatı

  • Method: POST
  • Content-Type: application/json
  • İmza: istek gövdesindeki sign alanı

Payload

Webhook gövdesi, /v1/payment/info yanıtıyla aynıdır, ek olarak imza doğrulaması için kullanılan bir sign alanı içerir.

Başarılı ödeme

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

İptal edilmiş / başarısız ödeme

Ödeme terminal paid durumunda olmadığında txid, payment_amount ve merchant_amount null'dur:

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

Alan referansı

AlanTipAçıklama
uuidstringÖdeme UUID'si
order_idstringSipariş ID'niz
amountdecimal (8 dp)currency cinsinden fiat tutarı
currencystringMerchant'ın talep ettiği fiat para birimi
urlstringHosted checkout URL'si
expires_atstring (ISO 8601)Ödeme oturumunun ne zaman süresi dolar
created_atstring (ISO 8601)Ödeme oturumunun ne zaman oluşturulduğu
payer_currencystringÖdeyenin ödeme yaptığı kripto
payer_amountdecimal (8 dp)Beklenen kripto tutarı
networkstringBlockchain ağı
addressstringYatırma adresi
payment_statusstringŞunlardan biri: pending, check, paid, underpaid_check, underpaid, overpaid, cancel, aml_lock (bkz. References)
txidstring | nullBlockchain tx hash'i, yalnızca onaylanmış bir ödemeden sonra mevcut
payment_amountdecimal | nullGerçek ödenen tutar, yalnızca ödemeden sonra mevcut
merchant_amountdecimal (18 dp) | nullÜcretler sonrası merchant'a yansıtılan tutar
amount_usddecimal (8 dp)Oluşturma anındaki USD tutarı
exchange_ratedecimalKullanılan kripto / fiat döviz kuru
signstring (hex)Payload'un HMAC-SHA256 imzası

İmzayı doğrulama

Bir webhook imzasını doğrulamak için:

  1. Payload'dan sign alanını çıkarın
  2. Nesneden sign alanını kaldırın
  3. Kalan alanları JSON olarak encode edin
  4. JSON'u Base64 ile encode edin
  5. API_KEY'inizi kullanarak Base64 string'inden HMAC-SHA256 hesaplayın
  6. Hesaplanan imzayı sign değeri ile sabit zamanlı bir karşılaştırma kullanarak karşılaştırın
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);

Bir kullanıcıya herhangi bir fon yansıtmadan önce her zaman imzayı doğrulayın. İmzasız veya yanlış imzalanmış bir webhook, sahte bir istek olabilir.

Çekim webhook'ları

Bir çekimin status'u değiştiğinde, sistem çekim oluşturulurken geçirilen url_callback URL'ine bir POST webhook gönderir. url_callback sağlanmadıysa, o çekim için webhook gönderilmez.

Çekim webhook'ları normal API key ile değil, Payout API key'iniz ile doğrulanmalıdır. İmzalama algoritması ödeme webhook'larıyla aynıdır (sign'i çıkar, JSON'a encode et, base64, HMAC-SHA256), yalnızca anahtar farklıdır.

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

Alan referansı

AlanTipAçıklama
uuidstringÇekim UUID'si
order_idstringSağladıysanız idempotency / referans ID'niz
statusstringpending, completed, failed, cancelled (bkz. References)
currencystringÇekim para birimi
networkstringBlockchain ağı
amountdecimalÇekim tutarı (currency cinsinden)
merchant_amountdecimalMerchant bakiyesinden tahsil edilen tutar
network_amountdecimalZincir üzerinde gerçekten gönderilen tutar
amount_usddecimalÇekim anındaki USD değeri
to_addressstringAlıcı blockchain adresi
memostring | nullMemo / hedef etiketi, kullanıldığında
txidstring | nullBlockchain işlem hash'i, completed durumunda ayarlanır
block_numberinteger | nullZincir üzerindeki işlemin blok yüksekliği
error_typestring | nullstatus = failed olduğunda neden (örn. aml_risk, bkz. References)
created_atstring (ISO 8601)Çekimin oluşturulduğu zaman
updated_atstring (ISO 8601)Durumun en son ne zaman değiştiği
from_currencystringOtomatik dönüştürme kullanıldığında çekimin düşüldüğü kaynak bakiye (örn. BTC çekimi için USDT)
debited_amountdecimalfrom_currency bakiyesinden düşülen tutar
debited_currencystringDüşmenin para birimi
signstring (hex)Payload'un Payout API key ile imzalanmış HMAC-SHA256 imzası

En iyi uygulamalar

  • Idempotency — Ödemenin zaten işlenip işlenmediğini her zaman kontrol edin (order_id veya uuid ile). Webhook'lar birden çok kez gelebilir.
  • Hızlı yanıt — Mümkün olduğunca hızlı HTTP 200 dönün. Ağır işleri arka plan kuyruğuna devredin.
  • Yeniden denemeler — Sistem HTTP 200 alamazsa, webhook 2 dakika sonra yeniden gönderilir. En fazla 5 yeniden deneme.
  • Asenkron işleme — Yanıtı bloke etmemek için webhook olaylarını asenkron işleyin.
  • Güvenlik — Payload'a güvenmeden önce HER ZAMAN sign imzasını doğrulayın.

Webhook'lar sıra dışı gelebilir. Aldığınız ilk webhook'un nihai durum olduğunu varsaymayın — kesinlik istiyorsanız her zaman /v1/payment/info (veya /v1/payout/status/{uuid}) üzerinden yeniden alın.