AR

توثيق Merchant API

Base URL: https://snapex.pro/api/v1/merchant

مفتاح API وأول طلب

  1. احصل على مفتاح من لوحة التحكم

    لوحة تحكم الشريك ← Merchant ← «الحصول على مفتاح API». يبدو المفتاح هكذا smk_abcdefghij_plus48chars ويُعرض مرة واحدة فقط. إذا فقدته، فأصدر مفتاحًا جديدًا: يصبح المفتاح السابق غير صالح فورًا.

  2. أضف ترويسة واحدة

    Authorization: Bearer your_key.

  3. تحقق من الوصول

    اطلب الرصيد. إذا وصلتك استجابة JSON تحتوي على data، فقد تم قبول المفتاح.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/balances \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"
الاستجابة
{
  "data": [
    {
      "asset_id": "usdt",               // دائمًا usdt، لا يوجد رصيد آخر
      "available_atomic": "15000000",   // 15 USDT بالوحدات الصغرى (6 خانات عشرية)
      "available": "15",                // القيمة نفسها بالصيغة العشرية
      "held_atomic": "0",               // محجوز لدفعات صرف غير مكتملة
      "held": "0"
    }
  ]
}

إذا فشل الطلب

الاستجابة السبب
401 unauthorized المفتاح مفقود أو يحتوي على مسافة أو مقطوع. يجب أن يلي Bearer المعرّف smk_… كاملًا.
401 key_inactive تم إلغاء المفتاح: صدر مفتاح جديد، لكن الطلب لا يزال يستخدم المفتاح السابق.

خمس قواعد

معظم أخطاء التكامل تنتج عن مخالفة إحدى هذه القواعد.

1. أرسل المبالغ كنصوص (strings)

مرّر إما amount، وهو نص عشري مثل "0.001" أو "15"، أو amount_atomic، وهو عدد صحيح بالوحدات الصغرى: "100000" لـ 0.001 BTC. استخدم حقلًا واحدًا فقط. تتضمن الاستجابات الصيغتين دائمًا: amount بجانب amount_atomic.

مثال
"amount": "0.001"        // valid
"amount_atomic": "100000" // also valid
// both at once — 422

2. خذ asset_id من /assets فقط

الرموز المسموح بها: usdt وbtc وxmr. تُرفض القيم العشوائية ومعرّفات مستكشفات البلوكتشين بالرمز 422.

مثال
"asset_id": "btc"   // correct
"asset_id": "BTC"   // error
"asset_id": "bitcoin" // error

3. Idempotency-Key في كل طلب إنشاء

معرّف فريد للمحاولة. إذا انقطع الاتصال ولم تعرف النتيجة، فكرر الطلب بالمفتاح نفسه: ستُعاد النتيجة الأصلية ولن تُنشأ عملية ثانية. مطلوب في POST /invoices وPOST /payments وPOST /payouts/preview وPOST /payouts.

مثال
Idempotency-Key: order-42-payment   // first attempt → 201, created
Idempotency-Key: order-42-payment   // retry → 200, same resource
Idempotency-Key: order-42-payment   // different amount → 409 conflict

4. الحقول الفارغة تُحذف

لا تُضمَّن قيم null والنصوص الفارغة. الدفعة غير المدفوعة لا تحتوي على actual_amount أو credited_amount أو fee. تحقق من وجود المفتاح، لا من قيمته.

مثال
// unpaid payment:
{ "payment_id": "pay_…", "status": "awaiting_deposit" }
// credited_amount is simply absent

5. لا تغلق الطلب عند expired

لا تعني expired أن التحويل لن يصل أبدًا. يستمر رصد العنوان لنحو 6 ساعة إضافية، ويُقيَّد التحويل المتأخر. الحالات النهائية التي يتم فيها القيد: confirmed وconfirmed_underpaid وconfirmed_overpaid.

السيناريوهات

يغطي كل سيناريو الدورة كاملة: ترتيب الطلبات، وشكل الاستجابة، ومعنى الحقول. التعليقات في أمثلة JSON للتوضيح فقط ولا تظهر في الاستجابات الحقيقية.

استقبال المدفوعات

العميل يدفع بـ BTC مقابل طلب بقيمة 60 دولارًا

الطلب order-42. تحتاج إلى نحو 60 USDT؛ وبسعر BTC يقارب 60,000 يكون المبلغ المتوقع من العميل 0.001 BTC.

1
احصل على قائمة الأصول المتاحة

تُرجع الاستجابة رمز الأصل وdecimals، أي عدد الخانات بعد الفاصلة العشرية.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/assets \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

GET /assets
لا توجد معاملات مطلوبة.
Authorization
الترويسة الوحيدة المطلوبة في الـ API.
الاستجابة
{
  "data": [
    {
      "asset_id": "btc",       // ← استخدمه في الطلبات اللاحقة
      "symbol": "BTC",         // للعرض على المستخدم
      "network": "bitcoin",    // يُستخدم في دفعات الصرف
      "decimals": 8,           // 1 BTC = 100000000 وحدة صغرى
      "price_usd": "60000"     // استرشادي، ليس لحساب عروض الأسعار
    },
    {
      "asset_id": "usdt",
      "symbol": "USDT",
      "network": "TRON",
      "decimals": 6,
      "price_usd": "1.00"
    }
  ]
}
2
ثبّت سعر الصرف لمدة 10 دقائق

يثبّت سعر الصرف بينما يكون العميل في صفحة الدفع. لا تُنشأ دفعة أو عنوان في هذه الخطوة، بل يُحسب عرض السعر فقط. الاستجابة هي مبلغ USDT الذي سيُقيَّد مقابل 0.001 BTC.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payments/credit-preview \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"asset_id":"btc","amount":"0.001"}'

النقاط الأساسية

asset_id: "btc"
الرمز من الخطوة السابقة.
amount: "0.001"
مبلغ BTC المتوقع من العميل. يُرسل كنص، وليس كرقم.
Idempotency-Key
اختياري: لا تُنشأ أي عملية. يمكنك إرساله لإعادة استخدام عرض السعر نفسه.
الاستجابة
{
  "data": {
    "credit_lock_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                                       // ← احفظه للخطوة التالية
    "asset_id": "btc",
    "expected_amount": "0.001",        // المبلغ المتوقع من العميل
    "expected_amount_atomic": "100000",
    "credit_usdt": "59.4",             // ← المبلغ الذي سيُقيَّد
    "credit_usdt_atomic": "59400000",
    "expires_at": "2026-08-11T17:20:00+00:00"
                                       // ← بعد هذا الوقت يصبح credit-preview غير صالح
  }
}

اعرض للعميل expected_amount، أي كمية BTC التي يجب إرسالها.

3
أنشئ الدفعة واحصل على العنوان

تنشئ هذه الخطوة الدفعة وتُرجع عنوان الإيداع. لا ترسل المبلغ في هذا الطلب، فهو محدد مسبقًا في credit-preview في الخطوة 2.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payments \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: order-42-payment" \
  -d '{
    "credit_lock_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "external_id": "order-42"
  }'

النقاط الأساسية

credit_lock_id
المعرّف من استجابة credit-preview. إذا انتهت مدة التثبيت، يُرجع الـ API الرمز 422، فاطلب معاينة جديدة.
external_id: "order-42"
رقم طلبك. يُستخدم للعثور على الدفعة لاحقًا ولتجنب دفعتين لطلب واحد.
Idempotency-Key
مطلوب. استخدم قيمة ثابتة وفريدة، مثل رقم الطلب مع لاحقة.
الاستجابة
{
  "data": {
    "payment_id": "pay_01HZX...",      // ← المعرّف للتحقق من الحالة
    "external_id": "order-42",         // رقم الطلب من الطلب المرسل
    "asset_id": "btc",
    "expected_amount": "0.001",
    "credit_usdt": "59.4",
    "status": "awaiting_deposit",      // بانتظار التحويل
    "channel": "api",
    "deposit_address": "bc1qexampledepositaddress000000000",
                                       // ← العنوان الذي يُعرض للعميل
    "expires_at": "2026-08-11T18:00:00+00:00",
    "created_at": "2026-08-11T17:00:00+00:00"
  }
}

إذا كانت الشبكة تتطلب memo، فستتضمن الاستجابة deposit_memo. التحويل بدون memo لن يُقيَّد، لذا اعرض الحقلين معًا.

4
انتظر الدفع

استعلم عن الدفعة كل 10–30 ثانية. تتسلسل الحالة هكذا: awaiting_deposit → detected → processing → confirmed.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/payments/pay_01HZX... \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

GET /payments/{payment_id}
استخدم payment_id من الاستجابة السابقة.
متى
الفاصل الموصى به 10–30 ثانية. الحد الأقصى 120 طلبًا في الدقيقة لكل مفتاح، فلا تستعلم بوتيرة أسرع.
الاستجابة
{
  "data": {
    "payment_id": "pay_01HZX...",
    "status": "detected",              // التحويل ظاهر على الشبكة،
                                       // لا توجد تأكيدات كافية بعد
    "asset_id": "btc",
    "expected_amount": "0.001",
    "actual_amount": "0.001",          // ← المبلغ الذي وصل فعليًا
    "deposit_address": "bc1qexampledepositaddress000000000",
    "created_at": "2026-08-11T17:00:00+00:00"
  }
}
5
تم تأكيد الدفع

تعني confirmed أن الأموال قُيّدت في الرصيد. يمكن إغلاق الطلب.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/payments/pay_01HZX... \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

status: confirmed
حالة نهائية، لن تتغير.
credited_amount
مبلغ USDT المقيَّد فعليًا. عند الدفع الدقيق يطابق credit_usdt.
الاستجابة
{
  "data": {
    "payment_id": "pay_01HZX...",
    "external_id": "order-42",
    "status": "confirmed",             // ← اكتمل القيد
    "asset_id": "btc",
    "expected_amount": "0.001",
    "actual_amount": "0.001",          // وصل المبلغ المتوقع
    "credit_usdt": "59.4",
    "credited_amount": "59.4",         // ← المبلغ المقيَّد في الرصيد
    "fee": "0.6",                      // العمولة، محتسبة مسبقًا في credited_amount
    "deposit_address": "bc1qexampledepositaddress000000000",
    "created_at": "2026-08-11T17:00:00+00:00"
  }
}

طابِق الحسابات على أساس credited_amount، وليس expected_amount: عند الدفع الناقص تختلف القيمتان.

ملاحظة

  • لا تنشئ الدفعة مسبقًا: تثبيت سعر الصرف يستمر 10 دقائق، والعنوان يُصدر لمبلغ محدد.
  • لا تغلق الطلب عند detected: لم تُقيَّد الأموال بعد.

العميل يدفع بـ USDT

المسار هو نفسه في سيناريو BTC، ولا يتغير سوى asset_id. إليك مثالًا أقصر أدناه.

1
ثبّت المبلغ

لا يوجد تحويل بين العملات، لذا يكون credit_usdt تقريبًا هو المبلغ مطروحًا منه العمولة.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payments/credit-preview \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -d '{"asset_id":"usdt","amount":"100"}'

النقاط الأساسية

asset_id: "usdt"
الاختلاف الوحيد عن سيناريو BTC.
amount: "100"
يرسل العميل 100 USDT على شبكة TRON.
الاستجابة
{
  "data": {
    "credit_lock_id": "b2c3d4e5-...",
    "asset_id": "usdt",
    "expected_amount": "100",
    "credit_usdt": "99",         // ← عمولة 1 USDT
    "expires_at": "2026-08-11T17:20:00+00:00"
  }
}
2
أنشئ الدفعة

الخطوة نفسها كما سبق. العنوان هو عنوان TRON (يبدأ بالحرف T).

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payments \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-43-payment" \
  -d '{"credit_lock_id":"b2c3d4e5-...","external_id":"order-43"}'

النقاط الأساسية

Idempotency-Key
استخدم Idempotency-Key جديدًا لكل طلب جديد. لا تُعِد استخدام المفتاح من order-42.
الاستجابة
{
  "data": {
    "payment_id": "pay_01HZY...",
    "external_id": "order-43",
    "asset_id": "usdt",
    "expected_amount": "100",
    "credit_usdt": "99",
    "status": "awaiting_deposit",
    "deposit_address": "TXYZexampletronaddress000000000",
                                 // ← عنوان TRON، TRC20
    "expires_at": "2026-08-11T18:00:00+00:00"
  }
}

أخبر العميل أن الشبكة هي TRC20. لن تُقيَّد USDT المرسلة على شبكة أخرى إلى هذا العنوان.

أرسل العميل مبلغًا أقل من المطلوب

كان المتوقع 0.001 BTC، ووصل 0.0009، مثلًا لأن محفظة العميل خصمت عمولة الشبكة من المبلغ.

1
تحقق من الدفعة

إذا وصل أقل من expected_amount لكن المبلغ يظل كافيًا للقيد، تكون الحالة confirmed_underpaid ويكون credited_amount أقل من عرض السعر. إذا كان المبلغ صغيرًا جدًا، فلا يُقيَّد شيء.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/payments/pay_01HZX... \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

المعنى
قارن credited_amount، وليس credit_usdt. الأول هو ما قُيّد فعلًا، والثاني هو عرض السعر لدفع دقيق.
الاستجابة
{
  "data": {
    "payment_id": "pay_01HZX...",
    "external_id": "order-42",
    "status": "confirmed_underpaid",   // ← دفع ناقص، لكن الأموال قُيّدت
    "asset_id": "btc",
    "expected_amount": "0.001",        // المبلغ المتوقع
    "actual_amount": "0.0009",         // المبلغ الذي وصل فعليًا
    "credit_usdt": "59.4",             // عرض السعر لدفع دقيق
    "credited_amount": "53.4",         // ← المبلغ المقيَّد فعليًا
    "fee": "0.6",
    "created_at": "2026-08-11T17:00:00+00:00"
  }
}

الخطوات التالية بيدك: اطلب استكمال المبلغ، أو نفّذ الطلب جزئيًا، أو ألغِه. يُرجع الـ API المبلغ المقيَّد فعليًا.

ملاحظة

  • لا تحكم بـ «مدفوع أم لا» بمقارنة actual_amount مع expected_amount. قارن credited_amount مع مبلغ USDT الذي تحتاجه.

لم يدفع العميل في الوقت المحدد

انقضى expires_at ولم يصل أي تحويل. تصبح الدفعة expired، ويستمر رصد العنوان.

1
الحالة expired

أُغلقت نافذة الدفع. لا يزال العنوان مرصودًا لنحو 6 ساعة.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/payments/pay_01HZX... \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

status: expired
انتهت نافذة الدفع.
credited_amount
لم تصل أي أموال بعد.
الاستجابة
{
  "data": {
    "payment_id": "pay_01HZX...",
    "status": "expired",               // انتهت النافذة
    "asset_id": "btc",
    "expected_amount": "0.001",
    "deposit_address": "bc1qexampledepositaddress000000000",
    "expires_at": "2026-08-11T18:00:00+00:00"
    // لا يوجد actual_amount ولا credited_amount، فلم يصل أي تحويل
  }
}
2
دفع العميل متأخرًا

إذا وصل التحويل خلال نافذة الرصد الإضافية، تنتقل الدفعة إلى confirmed رغم ذلك. لا تحذف الطلب عند expired: علّمه كمتأخر واستمر في الاستعلام.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/payments/pay_01HZX... \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

expired → confirmed
حالة طبيعية: وصل التحويل بعد expires_at.
الاستجابة
{
  "data": {
    "payment_id": "pay_01HZX...",
    "status": "confirmed",             // ← قُيّد بعد expires_at
    "actual_amount": "0.001",
    "credited_amount": "59.4",
    "created_at": "2026-08-11T17:00:00+00:00"
  }
}

ملاحظة

  • لا تُصدر عنوانًا جديدًا فور expired: فقد يكون العميل يرسل بالفعل إلى العنوان السابق. نواصل انتظار التحويل لمدة 6 ساعة أخرى.

الفواتير

فاتورة بالدولار الأمريكي مع صفحة دفع مستضافة. يختار العميل الشبكة، وتُقيَّد لك المبالغ بـ USDT.

فاتورة بقيمة 15 دولارًا مدفوعة بـ USDT

الطلب order-15. ينشئ التاجر فاتورة بالدولار الأمريكي ويرسل للعميل رابط صفحة الدفع.

1
أنشئ الفاتورة

تثبّت الفاتورة المبلغ بالدولار ومن يتحمّل العمولة، وتُرجع pay_url. لا يوجد عنوان بعد.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/invoices \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: order-15-invoice" \
  -d '{
    "amount_usd": "15.00",
    "fee_on": "merchant",
    "external_id": "order-15"
  }'

النقاط الأساسية

amount_usd
مبلغ الطلب كنص. هذه النقطة تقبل الدولار الأمريكي فقط، وليس amount_atomic.
fee_on
merchant: أنت تدفع العمولة، ويرى العميل 15.00. customer: العميل يدفع العمولة.
Idempotency-Key
مطلوب. إعادة المحاولة بالمفتاح نفسه تُرجع الفاتورة نفسها.
الاستجابة
{
  "data": {
    "invoice_id": "INV-8K2M1Q0P",
    "amount_usd": "15.00",
    "fee_on": "merchant",
    "charge_usd": "15.00",
    "credit_usd": "13.85",
    "status": "open",
    "pay_url": "https://pay.snapex.pro/0123456789abcdef0123456789abcdef",
    "methods": [
      { "asset_id": "usdt.trc20", "symbol": "USDT", "network": "TRC20" },
      { "asset_id": "usdt.erc20", "symbol": "USDT", "network": "ERC20" },
      { "asset_id": "usdt.bep20", "symbol": "USDT", "network": "BEP20" }
    ]
  }
}

يحتاج المفتاح إلى invoices.write أو payments.write. بيئة الاختبار: environment=test.

2
العميل يختار الشبكة

تُصدر هذه الخطوة عنوانًا فريدًا. يمكن تغيير الطريقة حتى يصل تحويل.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/invoices/INV-8K2M1Q0P/methods \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-15-trc20" \
  -d '{"asset_id":"usdt.trc20"}'

النقاط الأساسية

asset_id: "usdt.trc20"
رمز من methods: usdt.trc20 أو usdt.erc20 أو usdt.bep20. العملات الأخرى من القائمة نفسها.
payment.address
اعرض هذا العنوان والمبلغ فقط. لا يُستخدم Memo وTag.
الاستجابة
{
  "data": {
    "invoice_id": "INV-8K2M1Q0P",
    "status": "awaiting",
    "selected_asset_id": "usdt.trc20",
    "payment": {
      "asset_id": "usdt.trc20",
      "amount": "15 USDT",
      "address": "TExampleUniqueAddressForThisAttempt",
      "status": "awaiting"
    }
  }
}

يمكنك تخطي هذا الاستدعاء: يختار العميل الشبكة في pay_url.

3
تم دفع الفاتورة

أول تحويل مكتمل يغلق الفاتورة. أي تحويل لاحق إلى عنوان آخر يُقيَّد بشكل منفصل.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/invoices/INV-8K2M1Q0P \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

status: paid
حالة نهائية. يمكنك إغلاق الطلب.
invoice.paid
يصل Webhook invoice.paid إلى عنوان URL المحدد في لوحة التحكم. للتحقق من التوقيع، راجع قسم «Webhooks».
الاستجابة
{
  "data": {
    "invoice_id": "INV-8K2M1Q0P",
    "status": "paid",
    "credit_usd": "13.85",
    "paid_at": "2026-09-25T12:00:10+00:00"
  }
}

الدفع الناقص لا يغلق الفاتورة: تكون الحالة underpaid، وينتظر العنوان نفسه باقي المبلغ (USDT: 24 ساعة). إذا لم يصل الباقي في الوقت المحدد، تنتهي الفاتورة بالحالة partially_paid.

ملاحظة

  • لا تذكر المسارات الداخلية في واجهة العميل. تعرض صفحة الدفع العنوان والمبلغ والشبكة فقط.
  • لا يوجد API للاسترداد. التحويل المكتمل الثاني قيد منفصل، وليس عكسًا للأول.

دفعات الصرف

تحويلات صادرة من رصيدك بـ USDT.

أرسل للعميل 15 USDT على شكل BTC

amount هو ما يُخصم من رصيدك، وليس ما يحصل عليه المستلم. يُرجع preview مبلغ المستلم.

1
تحقق من الرصيد المتاح

استخدم available، وليس available مضافًا إليه held. الرصيد held محجوز لدفعات صرف غير مكتملة ولا يمكن إنفاقه.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/balances \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

available
الرصيد المتاح للخصم.
held
محجوز لدفعات صرف قيد التنفيذ.
الاستجابة
{
  "data": [
    {
      "asset_id": "usdt",
      "available": "74.4",       // ← متاح للإنفاق
      "available_atomic": "74400000",
      "held": "0",               // لا شيء محجوز
      "held_atomic": "0"
    }
  ]
}
2
احصل على عرض سعر للصرف

يُرجع preview كمية BTC التي يحصل عليها المستلم مقابل 15 USDT، والعمولة. لا يُخصم شيء بعد، بل يُثبَّت عرض السعر فقط.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payouts/preview \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: wd-77-preview" \
  -d '{
    "destination_asset_id": "btc",
    "destination_network": "bitcoin",
    "destination_address": "bc1qexampledestinationaddress000000",
    "amount": "15"
  }'

النقاط الأساسية

amount: "15"
الخصم بـ USDT من رصيدك. هذا ليس مبلغ المستلم.
destination_asset_id
أصل المستلم. الرمز من GET /assets.
destination_network
شبكة المستلم. بالنسبة لـ BTC هي bitcoin. خذها من network في GET /assets.
destination_address
عنوان المستلم. تحقق منه قبل الإرسال: لا يمكن إلغاء التحويل.
Idempotency-Key
مطلوب. استخدم مفتاحًا منفصلًا للمعاينة.
الاستجابة
{
  "data": {
    "preview_id": "c3d4e5f6-7890-abcd-ef12-34567890abcd",
                                     // ← المعرّف للخطوة التالية
    "from_asset_id": "usdt",
    "from_amount": "15",             // المبلغ المخصوم
    "to_asset_id": "btc",
    "to_amount": "0.000221",         // ← المبلغ الذي يحصل عليه المستلم
    "fee_amount": "0.000019",        // العمولة بـ BTC، محتسبة مسبقًا
    "expires_at": "2026-08-11T17:20:00+00:00"
                                     // ← نفّذ قبل هذا الوقت
  }
}

اعرض to_amount للمستخدم على أنه المبلغ الذي سيستلمه. إذا لم يكن المبلغ مقبولًا، فلا تنفّذ المعاينة: تنتهي صلاحيتها عند expires_at.

3
نفّذ الصرف

تقوم هذه الخطوة بالخصم والإرسال. كرّر العنوان والشبكة في الطلب، فهذا يمنع الاستبدال بين الخطوات.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payouts \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: wd-77-execute" \
  -d '{
    "preview_id": "c3d4e5f6-7890-abcd-ef12-34567890abcd",
    "destination_network": "bitcoin",
    "destination_address": "bc1qexampledestinationaddress000000",
    "external_id": "wd-77"
  }'

النقاط الأساسية

Idempotency-Key: wd-77-execute
مفتاح جديد يختلف عن مفتاح المعاينة. إعادة استخدام مفتاح المعاينة تُرجع 409.
destination_network / address
يجب أن يطابق المعاينة تمامًا، وإلا فستحصل على 422.
external_id
معرّف عمليتك للبحث عنها لاحقًا.
الاستجابة
{
  "data": {
    "payout_id": "payout_01HZX...",  // ← المعرّف للتتبع
    "external_id": "wd-77",
    "asset_id": "usdt",
    "debit_amount": "15",            // خُصم من الرصيد
    "destination_asset_id": "btc",
    "destination_network": "bitcoin",
    "destination_address": "bc1qexampledestinationaddress000000",
    "destination_amount": "0.000221",// المبلغ الذي يحصل عليه المستلم
    "fee": "0.000019",
    "status": "reserved",            // الأموال محجوزة، وبدأ الإرسال
    "channel": "api",
    "created_at": "2026-08-11T17:10:00+00:00"
  }
}
4
انتظر حتى الاكتمال

سلسلة الحالات: reserved → submitting → processing → completed. استعلم كل 15–30 ثانية.

الطلب
curl -sS https://snapex.pro/api/v1/merchant/payouts/payout_01HZX... \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

status: completed
وصلت الأموال. حالة نهائية.
status: failed
فشل التحويل، وعادةً ما يُعاد المبلغ المحجوز إلى الرصيد.
status: manual_review
النتيجة غير واضحة. انتظر المراجعة ولا تنشئ دفعة صرف أخرى.
الاستجابة
{
  "data": {
    "payout_id": "payout_01HZX...",
    "external_id": "wd-77",
    "debit_amount": "15",
    "destination_amount": "0.000221",
    "status": "completed",           // ← تم التسليم
    "created_at": "2026-08-11T17:10:00+00:00"
  }
}

ملاحظة

  • amount هو مبلغ الخصم، وليس مبلغ المستلم.
  • لدفعات الصرف حد منفصل: 5 طلبات في الدقيقة و30 في الساعة. لا تستدعِ preview في حلقة.
  • إذا انتهت صلاحية المعاينة (expires_at)، فإن POST /payouts يُرجع 422. اطلب معاينة جديدة.

أرسل USDT إلى محفظة TRON خارجية

الفرق أن destination_asset_id هو أيضًا usdt. العمولة في هذه الحالة في حدها الأدنى.

1
احصل على عرض سعر للصرف

أصل الخصم وأصل الوجهة متطابقان، لذا يكون to_amount تقريبًا هو amount مطروحًا منه عمولة الشبكة.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payouts/preview \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wd-78-preview" \
  -d '{
    "destination_asset_id": "usdt",
    "destination_network": "TRON",
    "destination_address": "TXYZexampletronaddress000000000",
    "amount": "50"
  }'

النقاط الأساسية

destination_network: "TRON"
خذ القيمة من network في GET /assets، مع مراعاة حالة الأحرف.
amount: "50"
سيُخصم 50 USDT.
الاستجابة
{
  "data": {
    "preview_id": "d4e5f6a7-...",
    "from_asset_id": "usdt",
    "from_amount": "50",           // مبلغ الخصم
    "to_asset_id": "usdt",
    "to_amount": "48.9",           // ← المبلغ المستلم (بعد عمولة الشبكة)
    "fee_amount": "1.1",
    "expires_at": "2026-08-11T17:25:00+00:00"
  }
}
2
نفّذ الصرف

التسلسل نفسه كما في السيناريو السابق.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payouts \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wd-78-execute" \
  -d '{
    "preview_id": "d4e5f6a7-...",
    "destination_network": "TRON",
    "destination_address": "TXYZexampletronaddress000000000",
    "external_id": "wd-78"
  }'
الاستجابة
{
  "data": {
    "payout_id": "payout_01HZZ...",
    "debit_amount": "50",
    "destination_asset_id": "usdt",
    "destination_amount": "48.9",
    "status": "reserved",
    "created_at": "2026-08-11T17:26:00+00:00"
  }
}

ملاحظة

  • تأكد من أن عنوان المستلم على شبكة TRON. التحويل إلى شبكة أخرى لا يُنفَّذ: إما أن يُرفض الطلب أو لن تصل الأموال.

رصيد غير كافٍ للصرف

الرصيد 10 USDT، والمطلوب صرف 15.

1
المعاينة ترفض الطلب

يُفحص الرصيد عند حساب عرض السعر، قبل أي خصم. يمكن عرض الخطأ للمستخدم فورًا.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payouts/preview \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wd-79-preview" \
  -d '{
    "destination_asset_id": "btc",
    "destination_network": "bitcoin",
    "destination_address": "bc1q…",
    "amount": "15"
  }'

النقاط الأساسية

HTTP 422
رفض لأسباب تجارية. الغلاف مطابق لأخطاء التحقق.
details.amount
الخطأ مرتبط بحقل ويمكن عرضه في النموذج.
الاستجابة
{
  "error": {
    "code": "validation_error",
    "message": "The request is invalid.",
    "details": {
      "amount": ["الرصيد غير كافٍ."]
                              // ← سبب الرفض مرتبط بـ amount
    }
  }
}

لا يُحجز شيء. إعادة المحاولة بـ Idempotency-Key نفسه آمنة، لكن اشحن الرصيد أولًا.

ملاحظة

  • ضع held في الحسبان: إذا كان جزء من الأموال محجوزًا لدفعة صرف أخرى، فسيكون available أقل من المتوقع.

العمليات

سجل المدفوعات

الـ ledger هو سجل العمليات: تُخزَّن القيود الدائنة والخصومات والحجوزات كقيود منفصلة.

1
اجلب السجل صفحة بصفحة

تُرجع القيود من الأحدث إلى الأقدم. حتى 100 سجل لكل طلب، والصفحة التالية تستخدم cursor.

الطلب
curl -sS "https://snapex.pro/api/v1/merchant/transactions?limit=50" \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

limit=50
عدد السجلات في كل استجابة: من 1 إلى 100، والافتراضي 25.
status=payment
تصفية اختيارية حسب نوع القيد.
الاستجابة
{
  "data": [
    {
      "id": "124",
      "direction": "credit",          // قيد دائن
      "type": "payment",              // المصدر: إيداع
      "amount": "59.4",
      "asset_id": "usdt",
      "channel": "api",
      "occurred_at": "2026-08-11T17:05:00+00:00"
    },
    {
      "id": "125",
      "direction": "reserve",         // حجز لدفعة صرف
      "type": "payout",
      "amount": "15",
      "asset_id": "usdt",
      "occurred_at": "2026-08-11T17:10:00+00:00"
    }
  ],
  "meta": {
    "next_cursor": "eyJpZCI6MTI1fQ",  // ← القيمة لمعامل cursor
    "per_page": 50
  }
}
2
الصفحة التالية

عندما يكون next_cursor مساويًا لـ null، لا توجد سجلات أخرى.

الطلب
curl -sS "https://snapex.pro/api/v1/merchant/transactions?limit=50&cursor=eyJpZCI6MTI1fQ" \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Accept: application/json"

النقاط الأساسية

cursor
قيمة meta.next_cursor من الاستجابة السابقة. لا تُقبل قيمة عشوائية.
الاستجابة
{
  "data": [ /* توجد سجلات أخرى */ ],
  "meta": {
    "next_cursor": null,              // ← الصفحة الأخيرة
    "per_page": 50
  }
}

ملاحظة

  • قيمتا direction وهما reserve وrelease تعنيان حجزًا وتحريرًا للحجز، وليستا تحويلًا صادرًا. لا تعتبرهما إنفاقًا.

لا توجد استجابة؟ كرّر الطلب نفسه

1
كرّر الطلب نفسه

استخدم Idempotency-Key نفسه والمعاملات نفسها. يعامل الخادم ذلك على أنه العملية نفسها.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payouts \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wd-77-execute" \
  -d '{
    "preview_id": "c3d4e5f6-...",
    "destination_network": "bitcoin",
    "destination_address": "bc1qexampledestinationaddress000000",
    "external_id": "wd-77"
  }'

النقاط الأساسية

Idempotency-Key
المفتاح الجديد ينشئ دفعة صرف جديدة.
HTTP 200 / 201
العملية موجودة مسبقًا، ويُعاد الكائن الأصلي.
الاستجابة
{
  "data": {
    "payout_id": "payout_01HZX...",   // ← المعرّف نفسه كما في الاستجابة الأولى
    "external_id": "wd-77",
    "debit_amount": "15",
    "status": "processing",           // ربما تغيّرت الحالة أثناء الانتظار
    "created_at": "2026-08-11T17:10:00+00:00"
  }
}

HTTP 201: أُنشئت العملية في هذا الطلب. HTTP 200: كانت موجودة مسبقًا. كلا الرمزين يعني النجاح.

2
إذا تغيّرت المعاملات

يُرفض تكرار المفتاح نفسه بمبلغ أو عنوان مختلف. هذا يمنع عدم تطابق المعاملات.

الطلب
curl -sS -X POST https://snapex.pro/api/v1/merchant/payouts \
  -H "Authorization: Bearer smk_abcdefghij_yourkey" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wd-77-execute" \
  -d '{
    "preview_id": "another-preview",
    "destination_network": "bitcoin",
    "destination_address": "bc1qanotheraddress"
  }'

النقاط الأساسية

HTTP 409
تعارض: المفتاح مرتبط بالفعل بعملية أخرى.
ما الذي تفعله
إذا كانت هذه دفعة صرف جديدة، فاستخدم Idempotency-Key جديدًا.
الاستجابة
{
  "error": {
    "code": "conflict",
    "message": "Idempotency-Key was used with different parameters."
  }
}

ملاحظة

  • أنشئ المفتاح مرة واحدة واحفظه مع الطلب. إنشاء مفتاح جديد قبل كل إرسال يُعطّل الحماية من التكرار.
  • عند HTTP 429، أعد المحاولة بالمفتاح نفسه بعد بضع ثوانٍ.

Webhooks

عندما تتغير فاتورة أو إيداع أو دفعة صرف أو تحويل أو الرصيد، ترسل SnapEX طلب POST إلى عنوان URL الخاص بك. الـ Webhook إشارة وليس مصدر الحقيقة: تحقق من التوقيع، وللقرارات المهمة أعد قراءة الكائن عبر الـ API.

الإعداد

  1. حدّد عنوان URL في لوحة التحكم

    لوحة تحكم الشريك ← الفواتير ← بطاقة «Webhook»: أدخل عنوان URL واضغط «حفظ». عنوان URL واحد لكل حساب، ويستقبل جميع أنواع الأحداث الواردة في الجدول أدناه.

  2. احفظ مفتاح التوقيع السري

    عند الحفظ الأول تعرض لوحة التحكم المفتاح السري whsec_… مرة واحدة فقط. احتفظ به على خادمك فقط. تغيير عنوان URL لاحقًا يُبقي على المفتاح السري نفسه.

  3. متطلبات عنوان URL

    عنوان URL مطلق يبدأ بـ https:// مع مضيف عام: بدون login:password في العنوان، وبدون localhost، ويجب ألا يُحلّ المضيف إلى عنوان IP خاص أو محجوز. يُفحص عنوان URL عند الحفظ ومرة أخرى قبل كل محاولة تسليم.

ما الذي يصل

الترويسة المعنى
Webhook-Id معرّف فريد للحدث (UUID)، يساوي id في الـ body. لا يتغير عند إعادة المحاولة أو الإرسال اليدوي، فاستخدمه لإزالة التكرار.
Webhook-Timestamp وقت Unix بالثواني لحظة إرسال هذه المحاولة. كل إعادة محاولة تحمل قيمة جديدة وتوقيعًا جديدًا.
Webhook-Signature v1= متبوعًا بقيمة HMAC-SHA256 بصيغة hex وأحرف صغيرة للنص «{Webhook-Timestamp}.{raw body}». المفتاح هو المفتاح السري كاملًا، بما في ذلك البادئة whsec_.
Content-Type دائمًا application/json. الـ body بصيغة UTF-8 JSON.
الطلب
POST /hooks/snapex HTTP/1.1
Content-Type: application/json
Webhook-Id: 6f1c2a8e-3b4d-4f5a-9c7e-1a2b3c4d5e6f
Webhook-Timestamp: 1790337610
Webhook-Signature: v1=2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881
body
{
  "id": "6f1c2a8e-3b4d-4f5a-9c7e-1a2b3c4d5e6f",   // = Webhook-Id
  "type": "invoice.paid",                          // نوع الحدث، انظر الجدول أدناه
  "created_at": "2026-09-25T12:00:10+00:00",       // وقت وقوع الحدث
  "data": {                                        // الكائن لحظة وقوع الحدث
    "invoice_id": "INV-8K2M1Q0P",
    "environment": "live",
    "amount_usd": "15.00",
    "charge_usd": "15.00",
    "credit_usd": "13.85",
    "status": "paid",
    "external_id": "order-15",
    "paid_at": "2026-09-25T12:00:10+00:00"
  }
}

يعتمد data على النوع: invoice.* هي الفاتورة بالشكل نفسه كما في GET /invoices/{id} (يكون attempts فارغًا، والمحاولة الحالية في payment)؛ payment.* هو الإيداع (payment_id، external_id، status، المبالغ)؛ payout.* هي دفعة الصرف (payout_id، external_id، status، المبالغ)؛ conversion.* هو التحويل (conversion_id، status، المبالغ)؛ balance.changed يتضمن asset_id وentry_type وavailable_atomic وheld_atomic بعد التغيير.

أنواع الأحداث

الحدث المعنى
invoice.created أُنشئت الفاتورة، ولم تُختر طريقة دفع بعد (open).
invoice.awaiting اختيرت طريقة الدفع وصدر العنوان (awaiting).
invoice.underpaid وصل جزء من المبلغ، وينتظر العنوان نفسه الباقي (underpaid).
invoice.paid دُفع المبلغ كاملًا وقُيّد (paid، نهائية). الإشارة الوحيدة لشحن الطلب.
invoice.partially_paid دفع العميل جزءًا فقط، وانتهت نافذة الاستكمال، وقُيّد الجزء المستلم لك (partially_paid، نهائية).
invoice.expired انتهت نافذة الفاتورة دون دفع (expired، نهائية).
invoice.extra_payment وصل تحويل آخر بعد دفع الفاتورة، ويُقيَّد بشكل منفصل.
payment.created أُنشئ إيداع.
payment.detected ظهر التحويل على الشبكة لكنه لم يُقيَّد بعد.
payment.credited قُيّد الإيداع (إحدى حالات confirmed*).
payment.expired انتهت نافذة الإيداع.
payout.created أُنشئت دفعة صرف وحُجزت الأموال.
payout.processing دفعة الصرف قيد الإرسال.
payout.completed وصلت الأموال إلى المستلم.
payout.failed فشلت دفعة الصرف.
conversion.completed اكتمل التحويل.
conversion.failed فشل التحويل كليًا أو جزئيًا.
balance.changed سُجّل قيد في الرصيد: قيد دائن أو حجز أو خصم.

اشحن الطلب فقط عند invoice.paid، فهو يُرسل فقط عند دفع المبلغ كاملًا. أما invoice.underpaid وinvoice.partially_paid فيعنيان أن المبلغ غير مكتمل.

الفواتير المنشأة مع environment=test محاكاة: تمر بالحالات نفسها وترسل الـ Webhooks نفسها (data.environment = "test")، لكنها لا تغيّر الرصيد الحقيقي أبدًا.

التسليم وإعادة المحاولة

  • النجاح هو أي استجابة 2xx. أي رمز آخر أو انتهاء مهلة أو خطأ في الشبكة يُعد فشلًا. لا يُفسَّر body الاستجابة.
  • المهل: 5 ثوانٍ للاتصال، و15 ثانية للطلب بأكمله.
  • لا تُتبع عمليات إعادة التوجيه: 301/302 يُعد فشلًا. حدّد عنوان URL النهائي.
  • حتى 5 محاولات لكل حدث: المحاولة الأولى، ثم إعادة المحاولة بعد نحو 10 ثوانٍ، ودقيقة، و5 دقائق، و15 دقيقة من كل فشل. بعد الفشل الخامس يتوقف التسليم التلقائي.
  • تعرض البطاقة نفسها «آخر عمليات التسليم»: الحدث، ورمز HTTP أو الخطأ، والوقت، ورقم المحاولة. زر «إعادة المحاولة» يرسل الحدث مجددًا بـ Webhook-Id نفسه.
  • التسليم من نوع at-least-once: قد يصل الحدث الواحد عدة مرات، وقد تصل الأحداث بغير ترتيبها (قد يصل حدث أُعيدت محاولته بعد حدث أحدث).

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

  1. اقرأ body الطلب الخام كبايتات، قبل تحليل JSON. لن يطابق JSON المُعاد تسلسله التوقيع.
  2. احسب HMAC-SHA256 على «{Webhook-Timestamp}.{raw body}» باستخدام مفتاحك السري whsec_… كمفتاح، ثم رمّزه بصيغة hex.
  3. قارن «v1=» + hex مع ترويسة Webhook-Signature باستخدام دالة ثابتة الزمن: hash_equals أو crypto.timingSafeEqual أو hmac.compare_digest.
  4. ارفض أي Webhook-Timestamp يختلف عن ساعتك بأكثر من 5 دقائق (موصى به). تحمل إعادات المحاولة طابعًا زمنيًا جديدًا، لذا لن يؤثر ذلك عليها.
PHP
<?php
$secret = getenv('SNAPEX_WEBHOOK_SECRET'); // whsec_… من لوحة التحكم
$body = file_get_contents('php://input');  // الـ body الخام، قبل تحليل JSON
$timestamp = $_SERVER['HTTP_WEBHOOK_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_WEBHOOK_SIGNATURE'] ?? '';

$expected = 'v1='.hash_hmac('sha256', $timestamp.'.'.$body, $secret);
if (! ctype_digit($timestamp)
    || abs(time() - (int) $timestamp) > 300
    || ! hash_equals($expected, $signature)) {
    http_response_code(400);
    exit;
}

$event = json_decode($body, true);
// تخطَّ إذا كان Webhook-Id هذا قد عولج سابقًا؛ ونفّذ العمل الثقيل في طابور
http_response_code(200);

قائمة التحقق للمعالج

  • تحقق من التوقيع على الـ body الخام بمقارنة ثابتة الزمن، وأجب بـ 400 إذا لم يتطابق.
  • ارفض الطلبات التي يكون Webhook-Timestamp فيها أقدم من 5 دقائق.
  • احفظ قيم Webhook-Id التي عولجت وتجاهل التكرارات. لا تعتمد على الترتيب: قارن الحالة في الحدث بما لديك بالفعل.
  • أجب بـ 2xx بسرعة، وقبل 15 ثانية بوقت كافٍ، ونفّذ العمل الثقيل بشكل غير متزامن.
  • بعد وصول Webhook يمكنك إعادة قراءة الكائن عبر الـ API للتأكد: GET /invoices/{id} أو GET /payments/{id} أو GET /payouts/{id}.

الحالات

شارة «نهائية» تعني أن الحالة لن تتغير. الاستثناء الوحيد هو الإيداعات منتهية الصلاحية (expired): فقد يصل تحويل متأخر.

الإيداعات

الحالة المعنى ما الذي تفعله
awaiting_deposit صدر العنوان، بانتظار التحويل اعرض للعميل العنوان والمبلغ
detected التحويل ظاهر على الشبكة، ولم يُقيَّد بعد انتظر. لا تغلق الطلب
processing جارٍ التحويل إلى USDT انتظر
confirmed وصل المبلغ المتوقع وقُيّدت الأموال أغلق الطلب نهائية
confirmed_underpaid وصل أقل من المتوقع، ضمن النطاق المسموح تحقق من credited_amount وقرّر إن كان كافيًا نهائية
confirmed_overpaid وصل أكثر من المتوقع، وقُيّد وفق credit-preview أغلق الطلب. تواصل مع الدعم بشأن المبلغ الزائد نهائية
confirmed_mismatch محفوظة للتوافق لا تُستخدم في الدفعات الجديدة نهائية
manual_review مطلوب مراجعة يدوية انتظر المراجعة؛ لا تنشئ دفعة ثانية
expired انتهت نافذة الدفع، ويُرصد العنوان لنحو 6 ساعة إضافية لا تحذف الطلب؛ استمر في الاستعلام
failed فشل من جهة المزوّد أنشئ دفعة جديدة نهائية
cancelled أُلغيت الدفعة أنشئ دفعة جديدة نهائية
refunded استردها المزوّد طابِق الرصيد؛ وتواصل مع الدعم إذا لم يتطابق نهائية

الفواتير

الحالة المعنى ما الذي تفعله
open أُنشئت الفاتورة، ولم تُختر طريقة الدفع أعطِ العميل pay_url أو اختر asset_id بنفسك
awaiting صدر العنوان، بانتظار التحويل اعرض العنوان والمبلغ؛ واستعلم عن الحالة
underpaid وصل جزء من المبلغ؛ العنوان نفسه اطلب من العميل إرسال الباقي إلى هذا العنوان
paid قُيّد أول تحويل كامل أغلق الطلب نهائية
partially_paid دفع العميل جزءًا فقط، وانتهت نافذة الاستكمال، وقُيّد الجزء المستلم لك لا تشحنه كطلب مدفوع؛ سوِّ الباقي مع العميل نهائية
expired انتهت نافذة الفاتورة أنشئ فاتورة جديدة نهائية

دفعات الصرف

الحالة المعنى ما الذي تفعله
reserved حُجزت الأموال لدفعة الصرف انتظر
submitting أُرسلت إلى المزوّد انتظر
processing المزوّد يرسل على البلوكتشين انتظر
completed وصلت الأموال إلى المستلم تم نهائية
manual_review النتيجة غير واضحة لا تنشئ دفعة صرف أخرى؛ انتظر المراجعة
failed فشل التحويل، وعادةً ما يُحرَّر المبلغ المحجوز تحقق من الرصيد؛ وأعد المحاولة بـ Idempotency-Key جديد عند الحاجة نهائية

الأخطاء

الاستجابة الناجحة تكون دائمًا في data، والخطأ يكون دائمًا في error. لا توجد أغلفة أخرى.

شكل الخطأ
{
  "error": {
    "code": "validation_error",     // رمز قابل للقراءة آليًا، انظر الجدول أدناه
    "message": "The request is invalid.",
    "details": {                    // غير موجود دائمًا
      "destination_address": ["The destination address field is required."]
                                    // المفتاح هو الحقل الذي فشل في التحقق
    }
  }
}
HTTP code متى ما الذي تفعله
401 unauthorized المفتاح مفقود أو غير صالح تحقق من ترويسة Authorization: Bearer smk_… كاملة، دون مسافات أو فواصل أسطر
401 key_inactive المفتاح ملغى أُلغي المفتاح السابق. استخدم المفتاح الحالي من لوحة التحكم
401 key_expired انتهت صلاحية المفتاح أصدر مفتاحًا جديدًا
404 not_found المعرّف غير موجود أو يخص تاجرًا آخر استخدم payment_id أو payout_id من استجابتك أنت
409 conflict Idempotency-Key مرتبط بعملية أخرى، أو external_id مستخدم بالفعل للعملية الجديدة استخدم مفتاحًا جديدًا. ولإعادة المحاولة استخدم المفتاح نفسه والمعاملات نفسها
422 validation_error حقول غير صالحة، أو credit-preview منتهي الصلاحية، أو رصيد غير كافٍ، أو Idempotency-Key مفقود راجع details لمعرفة الحقل والسبب
429 rate_limited تم تجاوز حد الطلبات أعد المحاولة لاحقًا بـ Idempotency-Key نفسه
500 internal_error خطأ داخلي في الخادم أعد المحاولة لاحقًا بـ Idempotency-Key نفسه. إذا استمر الخطأ، فتواصل مع الدعم وأرفق X-Request-Id