ربط API الدفع بالعملات الرقمية: الفواتير والتواقيع والـ Webhooks
شرح عملي للمطورين: طلب واحد موقّع لإنشاء فاتورة، ونقطة webhook واحدة لاستقبال الحالة، وتفاصيل الأمان التي تجعل التكامل جديرًا بالثقة.

يحتاج ربط API الدفع بالعملات الرقمية إلى جزأين: طلب من جهة الخادم ينشئ فاتورة لكل طلب شراء ويعيد رابط صفحة الدفع، ونقطة webhook تستقبل تحديثات حالة موقّعة عندما تُرصد الدفعة وتتأكد على البلوكشين. في mistKET كلاهما مجرد HTTPS وJSON، موقّعان بـ HMAC-SHA256، دون الحاجة إلى أي SDK.
يشرح هذا الدليل المسار الكامل مع أمثلة كود، ثم يتناول تفاصيل الأمان والموثوقية التي تفصل بين نسخة تجريبية ونظام جاهز للإنتاج.
البنية في صورة واحدة
كل عملية ربط لـ API الدفع بالعملات الرقمية تتبع الحلقة نفسها المكوّنة من خمس خطوات:
- إنشاء الطلب — يستدعي الخادم الخلفي لديك
POST /api/v1/invoicesمع المبلغ والعملة ورقم الطلب ورابط الـ callback. - التحويل — توجّه العميل إلى
checkout_urlالمُعاد. - الدفع — يختار العميل الشبكة ويدفع في الصفحة المستضافة؛ ويُثبَّت سعر الصرف طوال مدة صلاحية الفاتورة.
- الـ Webhook — يرسل mistKET طلب POST يحمل
invoice.paidأوinvoice.confirmedأو حدثًا استثنائيًا إلى رابط الـ callback لديك. - التنفيذ — تتحقق من التوقيع، وتعلّم الطلب بأنه مدفوع، وتسلّم المنتج.
يُصدر مفتاح الـ API وسرّ الـ API وسرّ الـ webhook في لوحة التاجر بعد الموافقة على حسابك. والمرجع الكامل موجود في اللوحة ضمن قسم API.
الخطوة 1: وقّع طلب الفاتورة وأرسله
يحمل كل طلب API ثلاث ترويسات (headers). التوقيع هو HMAC-SHA256 بصيغة hex للسلسلة {timestamp}.{raw body} باستخدام سرّ الـ API لديك:
POST /api/v1/invoices
X-Api-Key: mp_live_…
X-Api-Timestamp: 1760000000
X-Api-Signature: hex(hmac_sha256("{ts}.{body}", secret))
{
"amount": "184.50",
"currency": "USD",
"order_id": "2041",
"callback_url": "https://yourstore.com/webhooks/mistket"
} هكذا تبدو نسخة PHP مختصرة:
$body = json_encode([
'amount' => '184.50', 'currency' => 'USD',
'order_id' => '2041',
'callback_url' => 'https://yourstore.com/webhooks/mistket',
]);
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . '.' . $body, $apiSecret);
// send $body with X-Api-Key, X-Api-Timestamp, X-Api-Signature وقّع البايتات نفسها تمامًا التي ترسلها. إعادة ترميز JSON بعد التوقيع (بمسافات مختلفة أو ترتيب مفاتيح مختلف) هي السبب الأول لأخطاء التوقيع.
الخطوة 2: التحويل إلى صفحة الدفع المستضافة
عند نجاح الاستدعاء تحصل على 201 Created مع معرّف UUID للفاتورة وحالتها (new) ورابط checkout_url. خزّن الـ UUID مع طلبك ثم وجّه العميل. تعرض الصفحة المستضافة المبلغ الدقيق ورمز QR وعدّادًا تنازليًا والحالة المباشرة، وتعمل على الهاتف. يختار العملاء الشبكة هناك — USDT على TRON أو BNB Smart Chain أو Ethereum أو Arbitrum، إضافة إلى TRX وBNB وETH — ما لم تثبّت الشبكة في استدعاء الـ API.
إلى جانب إنشاء الفواتير، يتيح لك الـ API عرض قائمتها وجلب تفاصيلها وإلغاءها، وهذا مفيد عندما تتغير سلة الشراء أو يتخلى العميل عن الطلب.
الخطوة 3: استقبال الـ Webhooks والتحقق منها
عندما تتغير الحالة، يرسل mistKET طلب POST يحمل JSON إلى رابط الـ callback لديك مع هذه الترويسات:
| الترويسة | الغرض |
|---|---|
X-Mistket-Event | اسم الحدث، مثل invoice.confirmed |
X-Mistket-Timestamp | وقت Unix المستخدم في التوقيع |
X-Mistket-Signature | sha256= + توقيع HMAC-SHA256 للسلسلة {timestamp}.{raw body} باستخدام سرّ الـ webhook |
X-Mistket-Delivery | معرّف التسليم، مفيد للتسجيل في السجلات |
التحقق بلغة PHP:
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_MISTKET_TIMESTAMP'] ?? '';
$got = $_SERVER['HTTP_X_MISTKET_SIGNATURE'] ?? '';
$exp = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $webhookSecret);
if (!hash_equals($exp, $got) || abs(time() - (int) $ts) > 300) {
http_response_code(401); exit;
}
$event = json_decode($raw, true); استخدم مقارنة ثابتة الزمن (hash_equals في PHP، وhmac.compare_digest في Python، وcrypto.timingSafeEqual في Node.js)، وارفض الطوابع الزمنية القديمة لمنع هجمات إعادة الإرسال. وللاطلاع على خلفية هذه الآلية، راجع RFC 2104 (HMAC).
مثال على محتوى الـ Webhook
تصل الدفعة المؤكدة كمستند JSON مختصر. الحقول التي ستستخدمها أكثر من غيرها هي الحدث ورقم طلبك والحالة والمبلغان المتوقع والمستلم:
POST https://yourstore.com/webhooks/mistket
X-Mistket-Event: invoice.confirmed
X-Mistket-Signature: sha256=…
{ "event": "invoice.confirmed", "data": {
"order_id": "2041", "status": "confirmed",
"pay_amount": "184.5", "paid_amount": "184.5",
"pay_currency": "USDT", "network": "TRC20" } } خزّن pay_currency وnetwork مع الطلب، فهما مفيدان للمحاسبة ولمحادثات الدعم لاحقًا.
التحقق في Node.js وPython
الفحص نفسه بلغتين شائعتين أخريين:
// Node.js (Express with express.raw for this route)
const exp = 'sha256=' + crypto.createHmac('sha256', secret)
.update(ts + '.' + rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(exp), Buffer.from(sig));
# Python
exp = 'sha256=' + hmac.new(secret.encode(), f'{ts}.{raw}'.encode(),
hashlib.sha256).hexdigest()
ok = hmac.compare_digest(exp, sig) في الحالتين، تأكد من قراءة جسم الطلب الخام. كثير من أطر العمل تحلّل JSON تلقائيًا، وبعد التحليل وإعادة التسلسل لا تعود البايتات مطابقة للتوقيع.
الاختبار محليًا
تحتاج الـ webhooks إلى رابط HTTPS عام، لذلك لا يستطيع حاسوبك المحمول استقبالها مباشرة. هناك خياران عمليان: انشر المعالج على خادم تجريبي (staging) مبكرًا، أو اكشف المنفذ المحلي مؤقتًا عبر أداة أنفاق (tunnelling). أنشئ فواتير صغيرة تشير إلى رابط الـ callback التجريبي، ثم افحص سجلات التسليم في لوحة التاجر لترى بالضبط ما الذي أُرسل وبماذا ردّ خادمك.
حاول تفعيل كل نوع من الأحداث مرة واحدة على الأقل أثناء الاختبار: paid وconfirmed وunderpaid وexpired. عندما يعمل كل فرع من فروع المعالج مع webhook حقيقي، لا يتبقى إلا القليل مما قد يفاجئك في بيئة الإنتاج، وستعرف بالضبط كيف تبدو سجلات التسليم عندما يحدث خطأ ما.
الخطوة 4: معالجة كل حالة من حالات الدفع
يتضمن محتوى الـ webhook رقم الطلب والحالة والمبلغ المتوقع (pay_amount) والمبلغ المستلم (paid_amount) والعملة والشبكة. اربط كل حدث بإجراء:
| الحدث | المعنى | الإجراء المعتاد |
|---|---|---|
invoice.paid | رُصد التحويل والتأكيدات قيد الانتظار | اعرض «تم استلام الدفعة، جارٍ التأكيد» |
invoice.confirmed | اكتمل عدد التأكيدات المطلوب | علّم الطلب مدفوعًا ونفّذه |
invoice.underpaid | المبلغ أقل من هامش التسامح | انتظر إكمال الدفع أو تواصل مع العميل |
invoice.overpaid | المبلغ أكثر من المتوقع | نفّذ الطلب وقرّر بشأن الفرق |
invoice.expired | لم تصل دفعة صالحة في الوقت المحدد | حرّر المخزون واترك الطلب غير مدفوع |
يتولى mistKET هامش التسامح للدفع الناقص، والدفعات الجزئية التي تُجمع حتى الإجمالي، والدفعات المتأخرة ضمن مهلة السماح؛ أما الكود لديك فيتفاعل فقط مع النتيجة النهائية.
الموثوقية: إعادة المحاولة وعدم التكرار
إذا كانت نقطة الاستقبال لديك متوقفة أو أعادت خطأ، تُعاد محاولة إرسال الـ webhooks مع فواصل متزايدة لساعات. هذا يعني أنك قد تستقبل الحدث نفسه مرتين أحيانًا. اجعل المعالج عديم التكرار (idempotent) بالاعتماد على رقم الطلب:
- ردّ برمز 2xx بسرعة، ثم عالج المهام الثقيلة في طابور (queue).
- قبل التنفيذ، تحقّق مما إذا كان الطلب معلَّمًا بأنه مدفوع مسبقًا.
- سجّل معرّف التسليم والحدث لتتمكن من تتبع المشكلات؛ كما تعرض اللوحة سجلات تسليم الـ webhooks.
قائمة التحقق الأمنية لـ API الدفع
ربط API الدفع بالعملات الرقمية يتعامل مع المال، فتعامل معه كما تتعامل مع أي كود دفع آخر:
- أبقِ سرّ الـ API وسرّ الـ webhook على الخادم فقط، ولا تضعهما أبدًا في كود الواجهة الأمامية أو تطبيقات الهاتف.
- قيّد الوصول إلى الـ API عبر قائمة عناوين IP المسموح بها في اللوحة.
- ارفض الطلبات التي تقع خارج نافذة زمنية قصيرة للطابع الزمني.
- اضبط مدة صلاحية الفاتورة بما يتوافق مع منطق حجز المخزون لديك.
- تعامل مع المبالغ كسلاسل نصية أو أعداد عشرية دقيقة (decimal)، لا كأعداد عائمة (float).
إلى أين بعد ذلك
هذا هو ربط API الدفع بالعملات الرقمية كاملًا: طلب واحد موقّع، وwebhook واحد موثّق، وخريطة للحالات. وللاطلاع على المسار نفسه من منظور غير المطورين، اقرأ كيفية قبول الدفع بالعملات الرقمية على موقعك. هل تبني بوتًا بدلًا من موقع؟ راجع قبول الدفع بالعملات الرقمية في بوت تيليجرام. اطلب مفاتيح الـ API بتقديم طلبك عبر Telegram @mistnetwork، واطّلع على المثال في قسم المطورين، وأدِر مفاتيحك عبر تسجيل دخول التاجر.


