الانتقال إلى المحتوى الرئيسي
تتيح حزم Didit SDK إرسال المعاملات المراقَبة مباشرةً من جهاز المستخدم النهائي، بما في ذلك تحويلات Travel Rule وفحص العملات المشفرة. يُصدر خادمك الخلفي token قصير الأجل محدد النطاق، وتتولى حزمة SDK باقي العملية. تُرفق الحزمة ذكاء الجهاز تلقائياً، وعندما تحتاج تحويلة Travel Rule إلى إثبات السيطرة على المحفظة، تفتح مسار الإثبات فوراً تلقائياً. لا تُشغَّل جلسة التحقق المطلوبة تلقائياً أبداً، بل تعود في الاستجابة ليشغّلها تطبيقك باستخدام تكامل التحقق الخاص بـ Didit؛ راجع الإجراءات المطلوبة من المستخدم أدناه.

نظرة عامة

يقوم الإرسال من جهة العميل على ثلاثة ضمانات:
  • ربط هوية مقاوم للانتحال. يُحدَّد الـtoken عند الإصدار بقيمة vendor_data واحدة (معرّف المستخدم لديك). تُفرض هوية الموضوع لكل معاملة تُرسل بهذا الـtoken من الخادم استناداً إلى هذا الربط، فلا يستطيع عميل تم العبث به تقديم معاملات نيابةً عن مستخدم آخر، ولا تحتاج الـpayload إلى حمل أي بيانات اعتماد.
  • ذكاء جهاز تلقائي. تجمع الحزمة بصمة الجهاز وترسلها مع الإرسال، ويستخلص Didit عنوان IP ووكيل المستخدم من الخادم. يُرفق سياق الجهاز المجمّع بموضوع المعاملة دون أي مكتبة إضافية، أو رمز جهاز منفصل، أو أي ربط برمجي من جانبك. ويدعم هذا السياق القواعد المبنية على الجهاز، والربط بين الجلسات والمعاملات حسب الجهاز.
  • إثبات السيطرة على المحفظة الذي يُفتح تلقائياً. عندما تتطلب المعاملة التي أُنشئت أن يُثبت المستخدم النهائي سيطرته على محفظة، تتضمن الاستجابة كتلة action_required من النوع wallet_ownership، فتفتح الحزمة هذا المسار فوراً، ثم تحدّث المعاملة عند انتهائه، دون الحاجة إلى حلقات استعلام متكررة أو إلى بناء آلية لإرسال الروابط بنفسك. يختلف إجراء verification_session المطلوب عن ذلك: فهو لا يُشغَّل تلقائياً أبداً، ويعود في الكتلة نفسها ليشغّله تطبيقك باستخدام تكامل التحقق الخاص به.
يبقى POST /v3/transactions/ على الخادم الخيار الصحيح عندما لا يكون مستخدم نهائي حاضراً، مثل التحويلات الإدارية، واستيراد الدفعات، أو الأحداث التي تبلغ بها أنظمتك الداخلية. يُنشئ المساران سجلات المعاملات نفسها، ويطبّقان القواعد نفسها، ويصدران أحداث webhook نفسها.

التدفق

1

إصدار رمز المعاملة

يستدعي خادمك الخلفي POST /v3/transactions/sdk-token/ باستخدام مفتاح API الخاص بك وقيمة vendor_data للمستخدم، ويمرر sdk_token المُعاد إلى تطبيقك.
2

الإرسال من الجهاز

يستدعي التطبيق submitTransaction في SDK، فترسل الحزمة الـpayload إلى POST /v1/transactions/ مع الرأس X-Transaction-Token مع الإثراء التلقائي لبيانات الجهاز.
3

معالجة أي إجراء مطلوب

إذا كانت قيمة action_required.type هي wallet_ownership، فإن الحزمة تفتح الواجهة تلقائياً، ثم تحدّث المعاملة عبر GET /v1/transactions/{transaction_id}/. وإذا كانت verification_session، فلن تشغّل الحزمة أي شيء؛ اقرأ action_required وابدأ مسار التحقق الخاص بك باستخدام session_token (أو url على الويب).

إصدار رمز المعاملة

أصدِر tokens من خادمك الخلفي باستخدام POST /v3/transactions/sdk-token/، وذلك عبر المصادقة نفسها المعتمدة على مفتاح API في بقية الـendpoint الخاصة بالمعاملات في /v3/.
تُقبل أيضاً الأسماء بصيغة camelCase (vendorData، ttlSeconds، maxUses) كما في بقية واجهات /v3/.
لا تضمّن مفتاح API في أي تطبيق أبداً. يبقى مفتاح API على خادمك الخلفي، ويُستخدم لإصدار الـtokens فقط، ولا ينتقل إلى الجهاز سوى sdk_token القصير الأجل. أصدِر token جديداً لكل جلسة مستخدم بدلاً من إعادة استخدام tokens طويلة الأجل، واجعل max_uses محدوداً عندما يكون عدد عمليات الإرسال المتوقعة معروفاً.

الإرسال من الجهاز

ترسل حزم SDK الطلبات إلى POST /v1/transactions/ مع الـ token في الترويسة X-Transaction-Token. الـ payload بصيغة camelCase، والطرق submitTransaction تبنيه عنك، ولا تحتاج إلى التعامل معه مباشرة إلا عند استدعاء الـ endpoint من عميل HTTP خاص بك:
يُطابق كل حقل من الحقول على المستوى الأعلى نظيره في POST /v3/transactions/: تأتي الاستجابة بتفاصيل المعاملة نفسها بصيغة snake_case التي تستخدمها نقاط /v3/، مضافًا إليها الكتلة action_required:

الإعلان عن محفظة ذاتية الاستضافة

يُعلن المثال أعلاه أن الوجهة هي المحفظة ذاتية الاستضافة للمستخدم: قيمة paymentMethod.type لدى الطرف المقابل هي unhosted_wallet. يغيّر هذا الإعلان طريقة تنفيذ تبادل Travel Rule:
  • تتخطى Didit توجيه الطرف المقابل عبر VASP كليًّا، إذ لا يوجد VASP خلف المحفظة ذاتية الاستضافة، وتُنشئ التحويل مباشرةً بالحالة UNCONFIRMED_OWNERSHIP.
  • عند تفعيل auto_wallet_verification في إعدادات Travel Rule (وهو الإعداد الافتراضي)، تُنشأ تلقائيًّا جلسة أداة إثبات ملكية المحفظة وتُعاد في action_required، تمامًا كما في الاستجابة أعلاه.
  • يُشغّل SDK الأداة تلقائيًّا؛ وبعد أن يُثبت المستخدم سيطرته على المحفظة، تُجرى مطابقة الاسم للتحويل ويتقدم إلى COMPLETED، أو إلى COUNTERPARTY_MISMATCHED_DATA إذا لم يطابق الاسم صاحب المحفظة في دفتر عناوينها.
من دون هذا الإعلان، تجرّب Didit المسارات بالترتيب، ولا تلجأ إلى مسار الملكية إلا إذا تعذّر العثور على VASP طرف مقابل. صرّح بالمحفظة كلما كان منتجك يعلم مسبقًا أن وجهة السحب هي محفظة المستخدم نفسه، فذلك يوفّر مرحلة التوجيه الفاشلة، ويوصل المستخدم إلى مسار الإثبات فورًا.

فرض الجهة المعنية

تُحسم ثلاثة أمور دائمًا بواسطة الـ token، لا بواسطة الـ payload:
  • التطبيق الذي تُنشأ المعاملة ضمنه.
  • هوية الجهة المعنية: القيمة subject.externalUserId في الـ payload تُتجاهل وتُستبدل بالقيمة vendor_data الخاصة بالـ token.
  • سياق الجهاز الخاص بالجهة المعنية (انظر أدناه)؛ القيم المشتقة من الخادم تغلب عند التعارض مع أي قيمة واردة في subject.device.
يعني الرمز 401 من هذا الـ endpoint أن الـ token رُفض: إما لأنه مفقود أو غير معروف أو ملغى أو تجاوز حد max_uses الخاص به أو منتهي الصلاحية. تحتوي ردود الـ token المنتهي دائمًا على الكلمة expired في تفاصيل الخطأ، وبذلك تميّز SDK بين أخطاء expired_token وinvalid_token.

قراءة المعاملة مرة أخرى

يعيد GET /v1/transactions/{transaction_id}/ التفاصيل نفسها، بالمصادقة نفسها عبر X-Transaction-Token. تستدعي SDK هذا الـ endpoint تلقائيًّا بعد اكتمال مسار الإجراء الذي أُطلق أو انتهاء نافذته، فلا تتوقف الحالة النهائية على حدث واحد أو إشعار واحد. استخدمه بنفسك لإعادة التحقق من status وaction_required في أي وقت ما دام الـ token صالحًا؛ ومن الخادم الخاص بك، يعيد GET /v3/transactions/{transaction_id}/ السجل نفسه.

ذكاء الجهاز التلقائي

تتضمن كل عملية إرسال بيانات ذكاء الجهاز دون الحاجة إلى أي عمل تكامل من جانبك:
  • يجمع SDK بصمة جهاز تحافظ على الخصوصية (مخطط didit-fp-v2: إشارات المنصة والمتصفح، ومعرّف جهاز دائم، ودرجة الروبوتية، وتجزئة مركّبة)، ويرسلها مع الطلب.
  • تستنتج Didit عنوان IP ووكيل المستخدم (user agent) ورأس accept-language من جهة الخادم، انطلاقًا من الاتصال نفسه، لذلك لا يمكن تزويرها عبر الـ payload.
تُطبَّع النتيجة المدمجة في سياق جهاز المشارك subject في المعاملة، ثم تُضاف إلى مخطط الأجهزة أو تُحدَّث فيه، وهو المخطط نفسه الذي تغذّيه جلسات KYC. وبذلك تصبح المعاملات قابلة للربط حسب الجهاز عبر قاعدة مستخدميك بأكملها (“مرتبطة بالجهاز”)، وتزوّد القواعد بإشارات الجهاز والشبكة، وإثراء IP، وتظهر في تفاصيل المعاملة داخل Console. يمكن للمعاملات المرسلة من الخادم عبر /v3/ أن تواصل تمرير كائنات device_context صريحة لكل مشارك؛ أما عبر مسار SDK فتحصل على نسخة أقوى من البيانات نفسها دون أي جهد إضافي.

الإجراءات المطلوبة من المستخدم

قد تتطلب بعض المعاملات أن يقوم المستخدم النهائي بإجراء قبل أن تُسوّى: يمكن لقاعدة أن تشترط جلسة تحقق، ويمكن لتحويل وفق Travel Rule أن يشترط إثباتاً بأن المحفظة الوجهة تعود فعلاً للمستخدم. تظهر الحالتان في المكان نفسه: كتلة action_required في استجابة الإرسال (وفي كل قراءة لاحقة للمعاملة):
إذا انطبق الاحتمالان على المعاملة نفسها، يكون لـwallet_ownership الأولوية، لأن غياب إثبات الملكية يمنع تبادل Travel Rule نفسه. يصبح action_required بقيمة null بعد حلّ الإجراء المعلّق. يُبقى الحقل remediation الموجود للتوافق مع الإصدارات السابقة؛ وaction_required هو الكتلة المعتمدة.

عقد التشغيل التلقائي

autoLaunchAction (القيمة الافتراضية true) يشغّل تلقائياً الإجراء wallet_ownership فقط:
  • الويب - يُفتح في النافذة المنبثقة الخاصة بـ SDK، ويُكتشف الإكمال عبر المراسلة المتحقَّق من مصدرها إضافةً إلى استطلاع محدود للمعاملة (ولا يعتمد أبداً على حدث واحد).
  • iOS / Android (وغلافا React Native وFlutter، اللذان يفوّضان إلى SDK الأصلية) - يُعرض كـتجربة إثبات ملكية المحفظة الأصلية لدى SDK (SwiftUI / Jetpack Compose) عندما تكون useNativeWalletOwnership قيمتها true (وهي الافتراضية)، مع الرجوع إلى SFSafariViewController / Chrome Custom Tab، وأخيراً إلى المتصفح الافتراضي. بعد إغلاق التدفق أو عودة التطبيق إلى المقدمة، يعيد SDK قراءة المعاملة تلقائياً.
لا يُشغَّل إجراء verification_session تلقائياً أبداً: يعود دائماً في action_required، ليبدأه تطبيقك بتكامل التحقق الخاص بـ Didit.
لا يجوز عرض أداة إثبات ملكية المحفظة أبداً داخل عرض ويب مضمّن في تطبيق جوال، لأن روابط المحافظ العميقة لا تستطيع الخروج منه، ويتوقف تدفق الإثبات عند طريق مسدود. تستخدم SDKs بالفعل سطح المتصفح الصحيح عند التشغيل التلقائي؛ احتفظ بهذه القاعدة إذا تعاملت مع url بنفسك. راجع دليل أداة إثبات ملكية المحفظة للتفاصيل.
بعد أن يكتمل تدفق إثبات ملكية المحفظة الذي يشغّله SDK تلقائياً أو يُغلق، يعيد SDK قراءة المعاملة ويمرّر النتيجة المحدَّثة إلى دالة الاستدعاء onActionCompleted لديك. لا يُعدّ إجراء verification_session جزءاً من هذه الدورة، لأن تطبيقك هو من يشغّله - راجع القسم التالي.

تشغيل جلسة التحقق

عندما يكون action_required.type هو verification_session، اقرأ الكتلة من result.actionRequired وسلّمها إلى تكامل التحقق القائم لديك من Didit:
بعد أن ينتهي تدفق التحقق لديك، استدعِ GET /v1/transactions/{transaction_id}/ (أو انتظر webhook المعاملة) للحصول على الحالة المحدَّثة للمعاملة.

مثال: التحقق البيومتري الإضافي لسحب عالي القيمة

هذا هو التدفق في أفضل صوره: أخضِع المعاملات عالية المخاطر - المبالغ الكبيرة، والمستفيدون الجدد، والأجهزة الجديدة - لإعادة تحقق بيومتري من الشخص نفسه الذي تحققت منه عند التسجيل. الاستيلاء على الحساب يبدو تماماً هكذا: كلمة مرور صحيحة، ورمز 2FA صحيح (تم الحصول عليه بالتصيّد أو عبر تبديل بطاقة SIM)، وسحب إلى محفظة لم تراها من قبل. كل دفاع يعتمد على بيانات الاعتماد يكون قد فشل بحلول تلك اللحظة. أما الوجه فلا يزال صامداً: لا يستطيع المهاجم اجتياز صورة سيلفي خضعت لكشف الحيوية يجب أن تطابق الوجه الملتقط أثناء تسجيل KYC للمالك الشرعي.
1

أنشئ القاعدة مرة واحدة، في الكونسول

Transactions → Rules → Create Rule: الشرط amount gte 5000، والإجراء Change status → AWAITING_USER، واختر سير العمل المصادقة البيومترية على الإجراء. أضف أي شروط مخاطر أخرى تريدها - طرفاً مقابلاً لأول مرة، وبصمة جهاز جديدة، وتغيّر دولة عنوان IP - كشروط إضافية أو كقواعد إضافية.
2

أرسل السحب كالمعتاد

لا يتغير شيء في كود الإرسال لديك. عندما تُطبَّق القاعدة، تعود الاستجابة بـ status: "AWAITING_USER" وكتلة action_required من النوع verification_session:
3

شغّل إعادة التحقق

سلّم session_token (أو url) إلى تكامل التحقق القائم لديك من Didit، تماماً كما في تشغيل جلسة التحقق. بما أن الجلسة تُنشأ بالـ vendor_data نفسه الخاص بموضوع المعاملة، فإن Didit يحتفظ بالفعل بالوجه المرجعي المتحقَّق منه للمستخدم من التسجيل - صورة السيلفي المعتمدة مع كشف الحيوية، أو الصورة الموجودة على شريحة جواز السفر، أو الصورة الشخصية الموجودة على المستند. يلتقط المستخدم صورة سيلفي حية واحدة؛ يُجري Didit كشف الحيوية ومطابقة الوجه بنسبة 1:1 مع ذلك المرجع المخزّن. لا إعادة لمسح المستند ولا إعادة تسجيل - عبء لا يتجاوز بضع ثوانٍ، فقط على المعاملات التي تستحقه.
4

احسم المعاملة بحسب النتيجة

عند اكتمال الجلسة، يُعاد تقييم المعاملة تلقائياً: APPROVED إذا نجحت إعادة التحقق، وDECLINED إذا فشلت، مع إرسال webhook بالحدث transaction.status.updated في الحالتين (reason: remediation_completed في الجدول الزمني للمعاملة). يستلم تطبيقك النتيجة عبر دوال الاستدعاء على نمط onActionCompleted، أو عبر GET /v1/transactions/{transaction_id}/، أو عبر الـ webhook.
هذا يعمل لأن التسجيل عبر KYC وإعادة فحص القياسات الحيوية وقرار المعاملة تعمل كلها على منصة واحدة. الوجه الملتقط أثناء التسجيل هو المرجع لخطوة التحقق المعزَّز، ومخطط الجهاز يربط الجلسة بالمعاملة، ومحرك القواعد يجمع بينهما، فلا حاجة إلى وسيط من مزوّد خارجي، ولا إلى تصدير صور الوجه، ولا إلى عقد منفصل للقياسات الحيوية. تُحتسب إعادة الفحص كميزة قياسية للمصادقة البيومترية ($0.10) فقط عندما تُنفَّذ فعلاً.

Web SDK

submitTransaction متاحة اليوم في كائن Web SDK الفريد (المفرد):
النتيجة هي { transactionId, status, travelRuleStatus?, actionRequired? }. في حمولة مستوى SDK تكتب category وdetails وcustomProperties، ويتولى SDK تحويلها إلى الأسماء المستخدمة في الشبكة (type وinfo وprops) نيابةً عنك. تُصنَّف الأخطاء عبر DiditTransactionError:

SDKs الأصلية

تأتي واجهة submitTransaction الأصلية مع iOS وAndroid SDK 4.1.0 (وكذلك إصدارات React Native وFlutter التي تثبّتها). على عكس Web SDK، تستخدم الحمولات الأصلية أسماء الحقول الشبكية مباشرة: type وinfo وprops.
يعرض كل SDK أيضًا getTransaction(transactionToken, transactionId) لإعادة قراءة المعاملة بالـ token نفسه. تستدعيها الـSDKs نيابةً عنك بعد تشغيل مسار إجراء، ويمكنك استدعاءها بنفسك في أي وقت. على الأجهزة المحمولة، يُطبَّق نقل بصمة الجهاز بالفعل على جميع استدعاءات الشبكة في SDK، لذلك تحمل طلبات إرسال المعاملات بيانات ذكاء الجهاز نفسها تلقائيًا.

بدون SDKs

كل ما تفعله SDKs هو HTTPS عادي، ولا يتطلب أيٌّ من ذلك استخدامها. هناك شكلان متكافئان للتكامل: من جانب الخادم فقط (دون أي token). أرسل المعاملة عبر POST /v3/transactions/ من الخادم الخلفي باستخدام مفتاح API الخاص بك. تحمل الاستجابة، وكذلك كل قراءة لاحقة عبر GET /v3/transactions/{transaction_id}/، كتلة action_required نفسها. يمكنك أيضًا تمرير سياق device صريح لكل مشارك، لأنه لا يوجد SDK يجمعه نيابةً عنك. من جانب العميل باستخدام مكدس HTTP الخاص بك. أنشئ token عبر POST /v3/transactions/sdk-token/، ثم استدعِ POST /v1/transactions/ وGET /v1/transactions/{transaction_id}/ من الجهاز مع الرأس X-Transaction-Token. تنطبق الآلية نفسها لربط الموضوع نفسه واشتقاق عنوان IP ووكيل المستخدم من جهة الخادم. ثم تعامل مع action_required بنفسك: ثم اكتشف الإتمام دون أي استدعاء من العميل:
  • webhook (موصى به). يُطلَق transaction.status.updated عندما يحسم الإجراء المعلّق المعاملة، ويُطلَق travel_rule.status.updated عند كل انتقال في التبادل. يتضمن كلاهما ما يكفي لتحديث سجلاتك دون أي استطلاع.
  • الاستطلاع. أعد قراءة المعاملة (/v3/ من خادمك الخلفي، أو /v1/ مع token ما دام صالحًا). تعود action_required إلى null بعد الحسم، وتحمل status وtravel_rule.status النتيجة.
لا توجد تبعيات لمرة واحدة في هذا التصميم: تلتقي الأداة وجلسة التحقق وخادمك الخلفي كلها عند حالة المعاملة الدائمة نفسها، لذلك يمكن دائمًا استعادة الحالة بعد إغلاق تبويب أو فوات webhook بإعادة قراءة المعاملة.

الإشعارات عبر webhook

لا يحتاج خادمك الخلفي إلى أن يعيد التطبيق الإبلاغ. عندما تتطلب معاملة مُرسلة إجراءً من المستخدم، يتضمن webhook المعاملة، أي transaction.created أو transaction.status.updated، كتلة action_required نفسها، فتُطلِع أنظمتك على الإجراء المعلّق حتى لو أُغلق التطبيق قبل انتهاء المسار. يأتي إجراء verification_session مع الحالة AWAITING_USER، لكن إجراء wallet_ownership لا يغيّر حالة المعاملة وحده، لذلك اقرأ action_required بدلاً من الحالة. تصدر انتقالات Travel Rule أيضًا travel_rule.status.updated.

الخطوات التالية

إرسال المعاملات

واجهة إنشاء المعاملة من جهة الخادم ومرجع الحمولة الكامل.

Travel Rule

التبادل المُدار بين المُرسِل والمستفيد، والإعدادات، ودورة الحياة.

أداة ملكية المحفظة

مسار إثبات التحكم المستضاف الذي يقف وراء إجراءات wallet_ownership.

webhook

transaction.created وtransaction.status.updated، والتحقق من التوقيع.

القواعد

إجراءات القواعد، بما فيها الإجراءات التي تنشئ جلسات التحقق.

الحالات

ما معنى AWAITING_USER في دورة حياة المعاملة.
آخر تعديل في ٧ نوفمبر ٢٠٢٦