Sign in
مقدمة/إشعارات Webhook

إشعارات Webhook

تلقَّ تحديثات حالة المدفوعات والسحوبات في الوقت الفعلي عبر webhooks موقّعة بـ HMAC.

يرسل نظام 2328.io webhook إلى url_callback الخاص بك كلما تغيرت حالة الدفع. هذه هي الطريقة الموصى بها للحصول على إشعار بالمدفوعات الناجحة.

تنسيق الطلب

  • الطريقة: POST
  • Content-Type: application/json
  • التوقيع: حقل sign في محتوى الطلب

المحتوى

يتبع محتوى webhook تنسيق استجابة /v1/payment/info ويضيف tx_explorer_url إلى جانب حقل sign المستخدم للتحقق من التوقيع.

دفعة ناجحة

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",
  "tx_explorer_url": "https://tonviewer.com/transaction/41c2a327323480af8e705d05deb09c238a41779928832abef4bb77c862357b11",
  "payment_amount": "0.95256917",
  "merchant_amount": "0.949711462490000000",
  "amount_usd": "2.41324380",
  "exchange_rate": "0.01340691",
  "sign": "6f8c15b6e53b506d5bfa38ed3fb3b50697af73434262153c02e412541372f04d"
}

دفعة ملغاة / فاشلة

عندما لا تكون الدفعة في حالة paid نهائية، تكون قيم txid، payment_amount، و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,
  "tx_explorer_url": null,
  "payment_amount": null,
  "merchant_amount": null,
  "amount_usd": "37.53934800",
  "exchange_rate": "0.01340691",
  "sign": "40ce68ad9691ad54e684329d75ab5adaf5b01409a2d18d3e0110b8c1be605342"
}

مرجع الحقول

الحقلالنوعالوصف
uuidstringمعرّف الدفعة UUID
order_idstringمعرّف الطلب الخاص بك
amountdecimal (8 dp)المبلغ بالعملة الورقية في currency
currencystringالعملة الورقية التي طلبها التاجر
urlstringعنوان URL لصفحة الدفع المستضافة
expires_atstring (ISO 8601)متى تنتهي صلاحية جلسة الدفع
created_atstring (ISO 8601)متى تم إنشاء جلسة الدفع
payer_currencystringالعملة المشفرة التي يدفع بها الدافع
payer_amountdecimal (8 dp)مبلغ العملة المشفرة المتوقع
networkstringشبكة البلوكتشين
addressstringعنوان الإيداع
payment_statusstringإحدى: pending، check، paid، underpaid_check، underpaid، overpaid، cancel، aml_lock (راجع References)
txidstring | nullهاش معاملة البلوكتشين، يكون موجودًا فقط بعد تأكيد الدفع
tx_explorer_urlstring | nullرابط المعاملة في مستكشف البلوكشين. تكون القيمة null عند عدم وجود txid أو عندما يكون التحويل داخليًا بنظام P2P.
payment_amountdecimal | nullالمبلغ المدفوع فعليًا، يكون موجودًا فقط بعد الدفع
merchant_amountdecimal (18 dp) | nullالمبلغ المُضاف إلى التاجر بعد الرسوم
amount_usddecimal (8 dp)المبلغ بالدولار الأمريكي وقت الإنشاء
exchange_ratedecimalسعر صرف العملة المشفرة / الورقية المستخدم
signstring (hex)توقيع HMAC-SHA256 للمحتوى

التحقق من التوقيع

للتحقق من توقيع webhook:

  1. استخرج حقل sign من المحتوى
  2. أزل حقل sign من الكائن
  3. رمّز الحقول المتبقية كـ JSON
  4. رمّز JSON بـ Base64
  5. احسب HMAC-SHA256 من سلسلة Base64 باستخدام API_KEY الخاص بك
  6. قارن التوقيع المحسوب بقيمة sign باستخدام مقارنة بزمن ثابت
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);

تحقق دائمًا من التوقيع قبل إيداع أي أموال للمستخدم. webhook غير موقّع أو موقّع بشكل غير صحيح قد يكون طلبًا مزيفًا.

webhooks السحب

عند تغيّر status لعملية سحب، يرسل النظام webhook بطريقة POST إلى عنوان url_callback الذي تم تمريره عند إنشاء السحب. إذا لم يتم توفير url_callback، فلن يتم إرسال أي webhooks لتلك العملية.

يجب التحقق من webhooks السحب باستخدام Payout API key الخاص بك — وليس API key العادي. خوارزمية التوقيع متطابقة مع webhooks المدفوعات (إزالة sign، ترميز JSON، base64، HMAC-SHA256)، يختلف فقط المفتاح.

المحتوى

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",
  "tx_explorer_url": "https://tronscan.org/#/transaction/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"
}

مرجع الحقول

الحقلالنوعالوصف
uuidstringمعرّف السحب UUID
order_idstringمعرّف idempotency / المرجع الخاص بك، إذا قمت بتوفيره
statusstringpending، completed، failed، cancelled (راجع References)
currencystringعملة السحب
networkstringشبكة البلوكتشين
amountdecimalمبلغ السحب (بـ currency)
merchant_amountdecimalالمبلغ المخصوم من رصيد التاجر
network_amountdecimalالمبلغ المُرسل فعليًا على البلوكتشين
amount_usddecimalالقيمة بالدولار الأمريكي وقت السحب
to_addressstringعنوان البلوكتشين للمستلم
memostring | nullmemo / تاج الوجهة، إن استُخدم
txidstring | nullهاش معاملة البلوكتشين، يُحدد عند completed
tx_explorer_urlstring | nullرابط المعاملة في مستكشف البلوكشين. تكون القيمة null عند عدم وجود txid أو عندما يكون التحويل داخليًا بنظام P2P.
block_numberinteger | nullارتفاع البلوك للمعاملة على البلوكتشين
error_typestring | nullالسبب عند status = failed (مثل aml_risk، راجع References)
created_atstring (ISO 8601)متى تم إنشاء عملية السحب
updated_atstring (ISO 8601)متى تغيرت الحالة آخر مرة
from_currencystringالرصيد المصدري الذي خُصم منه السحب عند استخدام التحويل التلقائي (مثلًا USDT لسحب بـ BTC)
debited_amountdecimalالمبلغ المخصوم من رصيد from_currency
debited_currencystringعملة الخصم
signstring (hex)توقيع HMAC-SHA256 للمحتوى، موقّع باستخدام Payout API key

أفضل الممارسات

  • Idempotency — تحقق دائمًا مما إذا كانت الدفعة قد عولجت بالفعل (بواسطة order_id أو uuid). قد تصل webhooks عدة مرات.
  • استجابة سريعة — أعد HTTP 200 بأسرع وقت ممكن. أنقل العمل الثقيل إلى طابور خلفي.
  • إعادة المحاولة — إذا لم يتلقَّ النظام HTTP 200، تتم إعادة إرسال webhook بعد دقيقتين. الحد الأقصى 5 محاولات.
  • معالجة غير متزامنة — تعامل مع أحداث webhook بشكل غير متزامن لتجنب حجب الاستجابة.
  • الأمان — تحقق دائمًا من توقيع sign قبل الوثوق بالمحتوى.

قد تصل webhooks خارج الترتيب. لا تفترض أن أول webhook تستلمه هو الحالة النهائية — أعد الجلب دائمًا عبر /v1/payment/info (أو /v1/payout/status/{uuid}) إذا كنت بحاجة إلى يقين.

عقد التسليم والمعالجة

استخدم الطلب التالي داخل نقطة نهاية الويب هوك الخاصة بك:

  1. اقرأ محتوى الطلب دون تسجيل الأسرار أو التوقيع الكامل.
  2. حدد ما إذا كان حدث دفع/محفظة ثابتة أو حدث سحب حتى تختار مفتاح API الصحيح.
  3. قم بإزالة sign، وأعد إنتاج بايتات JSON الموثقة، واحسب HMAC-SHA256، وقارن في وقت ثابت.
  4. تحقق من صحة المعرفات المطلوبة، والسلاسل العشرية، وقيم الحالة.
  5. أدرج سجل صندوق البريد/التكرار بطريقة ذرية. إذا كان موجودًا بالفعل، أعد HTTP 200 دون تكرار التأثيرات الجانبية.
  6. التزم بتغيير الطلب/دفتر الحسابات وضع البريد الإلكتروني غير الحرج أو التحليلات أو الإشعارات في قائمة الانتظار.
  7. أرجع HTTP 200 بسرعة.

لا تستدعِ خدمات الطرف الثالث البطيئة أثناء الاحتفاظ بمعاملة التكرار. قد يؤدي انتهاء المهلة بعد الالتزام ولكن قبل الإرجاع إلى محاولة إعادة؛ يجب أن يلاحظ التكرار المفتاح المستلم الملتزم ويصبح بلا عملية.

الحدثالهوية الأساسيةملاحظات
جلسة الدفعuuid + دليل الحالة/الإصداريمكن للفاتورة نفسها إصدار تغييرات حالة مشروعة متعددة.
إعادة شحن بدفع جزئيفاتورة uuid + txidيمكن أن ينتمي أكثر من تحويل إلى نفس الفاتورة الناقصة الدفع.
إيداع المحفظة الثابتةالشبكة + txidorder_id يُعاد استخدامه بواسطة كل إيداع لتلك المحفظة.
الدفعدفع uuid + الحالةلا تُنشئ دفعًا ثانيًا من منطق إعادة المحاولة عبر الويب هوك.

إذا لم يكن لدى مخططك معرف حدث، خزّن تجزئة التحميل المؤكدة كدليل تدقيق إضافي، ولكن لا تستبدل الهويات التجارية أعلاه بالطابع الزمني.

الترتيب والمطابقة

التسليم يتم على الأقل مرة واحدة ورسائل الحالة يمكن أن تأتي بتسلسل غير متوقع. نفذ قواعد أعمال أحادية الاتجاه بدلاً من "يفوز الطلب الأخير":

  • لا تحرك الطلب المكتمل أبدًا إلى check لأن حدثًا أقدم وصل متأخرًا؛
  • السماح لـ underpaid_check بتلقي معرفات معاملات إضافية دون تكرار الاعتمادات السابقة؛
  • اعتبر paid و overpaid حالات تسوية ناجحة، مع الحفاظ على مبالغها المختلفة؛
  • احتفظ بـ underpaid كنتيجة نهائية للمدفوعات الجزئية ما لم يبلغ API الموثوق عنه لاحقًا بحالة أخرى؛
  • وجه aml_lock للمراجعة ولا تدع عامل إعادة المحاولة العامة ينفذه؛
  • استعلام معلومات الدفع/السحب كلما تعذر الانتقال، أو كان السياق مفقودًا، أو غير واضح ماليًا.

قم بتشغيل التسوية المجدولة حتى عندما يبدو توصيل الويب هوك صحيًا. قارن بين حالة جهازك المحلي والمبلغ المعتمد مع /v1/payment/info، /v1/static-wallet/transactions، أو /v1/payout/status/{uuid} وابلغ عن الفروقات بدلاً من الكتابة الصامتة على سجل الدفعات.

أمان نقطة نهاية الويب هوك

  • تطلب HTTPS والحفاظ على إمكانية الوصول العام للنداء العكسي؛ تُرفض أهداف النداء العكسي الخاصة/المحلية أثناء إنشاء الدفع.
  • فرض حد صغير لحجم جسم الطلب ونوع محتوى JSON.
  • تحديد معدل قبل العمل المكلف، ولكن اترك مساحة كافية للزيادة المشروعة وإعادة المحاولة.
  • لا تفوض أبدًا ويب هوك بواسطة عنوان IP المصدر فقط. قوائم السماح على الشبكة هي دفاع متعدد الطبقات؛ التحقق من HMAC إلزامي.
  • قم بحجب sign ومفاتيح API والعناوين عند الحاجة طبقًا للسياسة، وبيانات التعريف الشخصية من سجلات التطبيق.
  • احتفظ بكل من المفاتيح الحالية والمفاتيح البديلة المجدولة صراحة خلال نافذة التدوير المسيطر عليها؛ لا تحزر أبدًا أي مفتاح وقع الحدث.
  • أعد جسم خطأ عام عند وجود توقيعات غير صالحة حتى لا تصبح نقطة النهاية مرجعًا للمفاتيح أو الحسابات.