دليل واجهة برمجة تطبيقات نظام الدفع OmniCRM
نظرة عامة
يوفر نظام الدفع OmniCRM بنية تحتية شاملة لمعالجة المدفوعات غير مرتبطة بالبائع. يدعم اليوم كل من Stripe وPayPal، ولكن الهيكلية المودولية تسمح بالتكامل مع أي مزود دفع (Square، Adyen، Braintree، إلخ) دون الحاجة لتغيير كود التطبيق.
يغطي هذا المستند جميع واجهات برمجة التطبيقات الخاصة بالدفع وسير العمل المتاحة في النظام.
🔧 تكامل كتاب أنسيبل: لتنفيذ واجهات برمجة التطبيقات الخاصة بالدفع هذه في كتب التشغيل، راجع التحصيل والمدفوعات من كتب التشغيل
جدول المحتويات
- الهيكلية المودولية
- المفاهيم الأساسية
- المستندات المالية
- واجهات برمجة تطبيقات طرق الدفع
- واجهات برمجة تطبيقات تدفق الدفع
- ��اجهات برمجة تطبيقات المحفظة
- ملخص مرجع واجهة برمجة التطبيقات
- حالات الاستخدام الشائعة
الهيكلية المودولية
لماذا غير مرتبطة بالبائع؟
يستخدم النظام طبقات التجريد لفصل منطق الأعمال عن تفاصيل مزود الدفع. هذا يعني:
- ✅ إضافة مزودي دفع جدد دون لمس كود التطبيق
- ✅ تبديل البائعين دون الحاجة لترحيل قواعد البيانات
- ✅ دعم عدة بائعين في نفس الوقت
- ✅ واجهة برمجة تطبيقات متسقة بغض النظر عن مزود الخلفية
طبقات الهيكلية
إضافة مزود دفع جديد
لإضافة مزود جديد (مثل Square، Adyen، Braintree)، اتصل بفريق OmniCRM الفني لديك.
للحصول على تفاصيل التكوين حول المزودين الحاليين (Stripe، PayPal)، راجع تكوين المزود.
نظرة عامة على العملية:
الخطوات:
- تنفيذ فئة المعالج مع
PaymentVendorInterfaceالقياسية (تفويض، التقاط، شحن، استرداد، تحرير) - تسجيل المعالج ف�� VendorFactory مع اسم المزود
- اختبار التكامل مع بيئة الاختبار الخاصة بالمزود
- نشر - تدعم جميع واجهات برمجة التطبيقات الحالية المزود الجديد تلقائيًا
النتيجة: بمجرد النشر، يعمل المزود الجديد بسلاسة:
# إضافة طريقة دفع Square
curl -X POST /api/payments/methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"vendor": "square",
"payment_token": "sq_xxxxx"
}'
تدعم جميع واجهات برمجة التطبيقات الخاصة بالدفع المزود الجديد تلقائيًا دون الحاجة لتغييرات في كود التطبيق.
وقت التكامل: عادةً ما يستغرق 1-2 يومًا لمعالج مزود جديد.
تكوين المزود
تمكين مزودي الدفع
تتحكم واجهة المستخدم في مزودي الدفع المتاحين للعملاء. يتم تعيين ذلك عبر المتغير VITE_PAYMENT_VENDORS في ملف .env الخاص بواجهة المستخدم:
# تمكين Stripe فقط (افتراضي)
VITE_PAYMENT_VENDORS="stripe"
# تمكين كل من Stripe وPayPal
VITE_PAYMENT_VENDORS="stripe,paypal"
# تمكين PayPal فقط
VITE_PAYMENT_VENDORS="paypal"
مهم: VITE_PAYMENT_VENDORS هو متغير وقت البناء. يتطلب تغييره إعادة بناء وإعادة تشغيل واجهة المستخدم.
تكوين Stripe
Stripe هو المزود الأساسي للدفع، ويقدم معالجة بطاقات مع دعم 3D Secure.
1. الحصول على مفاتيح API من Stripe
- قم بالتسجيل في https://stripe.com
- انتقل إلى المطورين → مفاتيح API
- انسخ المفتاح القابل للنشر الخاص بك (pk_live_... أو pk_test_...)
- انسخ المفتاح السري الخاص بك (sk_live_... أو sk_test_...)
مهم:
- استخدم المفاتيح التجريبية (pk_test_/sk_test_) للتطوير
- استخدم المفاتيح الحية (pk_live_/sk_live_) للإنتاج فقط
- لا تقم أبدًا بتسجيل مفاتيح API في التحكم في النسخ
2. تكوين الخلفية
أضف إلى crm_config.yaml (مستوى الجذر، وليس تحت payment_vendors):
stripe:
secret_key: 'sk_live_YOUR_SECRET_KEY_HERE'
publishable_key: 'pk_live_YOUR_PUBLISHABLE_KEY_HERE'
currency: 'aud'
statement_descriptor_suffix: 'YOUR_COMPANY'
تقرأ واجهة برمجة التطبيقات بيانات اعتماد Stripe من crm_config.yaml عند بدء التشغيل. يتطلب تغيير هذه القيم إعادة تشغيل واجهة برمجة التطبيقات.
3. تكوين الواجهة الأمامية
أضف إلى ملف .env الخاص بواجهة المستخدم:
VITE_STRIPE_PUBLISHABLE_KEY=pk_live_YOUR_PUBLISHABLE_KEY_HERE
ملاحظة أمان: يجب أن يذهب المفتاح القابل للنشر فقط في الواجهة الأمامية. يجب ألا يتم الكشف عن المفتاح السري في المتصفح.
تكوين PayPal
تقدم PayPal تخزين بطاقات المدفوعات ومدفوعات حساب PayPal.
1. الحصول على بيانات اعتماد API من PayPal
- أنشئ تطبيق API REST في https://developer.paypal.com/dashboard/
- انسخ معرف العميل والمفتاح السري
- للاختبار، استخدم بيانات اعتماد Sandbox؛ للإنتاج، استخدم بيانات اعتماد Live
2. تكوين الخلفية
أضف إلى crm_config.yaml (مستوى الجذر):
paypal:
client_id: 'YOUR_PAYPAL_CLIENT_ID'
client_secret: 'YOUR_PAYPAL_CLIENT_SECRET'
mode: 'sandbox' # 'sandbox' للاختبار، 'live' للإنتاج
تقرأ واجهة برمجة التطبيقات بيانات اعتماد PayPal من crm_config.yaml عند بدء التشغيل. يتطلب تغيير هذه القيم إعادة تشغيل واجهة برمجة التطبيقات.
3. تكوين الواجهة الأمامية
أضف إلى ملف .env الخاص بواجهة المستخدم:
VITE_PAYMENT_VENDORS="stripe,paypal"
VITE_PAYPAL_CLIENT_ID=YOUR_PAYPAL_CLIENT_ID
يجب أن يتطابق VITE_PAYPAL_CLIENT_ID مع قيمة paypal.client_id في crm_config.yaml.
Sandbox مقابل Live
| Sandbox | Live | |
|---|---|---|
| واجهة برمجة تطبيقات Stripe | sk_test_ / pk_test_ | sk_live_ / pk_live_ |
| واجهة برمجة تطبيقات PayPal | api-m.sandbox.paypal.com | api-m.paypal.com |
| وضع PayPal | sandbox | live |
| المال | مزيف | حقيقي |
عند الانتقال من sandbox إلى live، قم بتحديث كلا crm_config.yaml (بيانات الاعتماد والوضع) وملف .env (المفتاح القابل للنشر / معرف العميل)، ثم أعد بناء واجهة المستخدم وأعد تشغيل واجهة برمجة التطبيقات.
الامتثال لمعايير PCI
كيف يحافظ OmniCRM على الامتثال لمعايير PCI:
- يتم إدخال بيانات البطاقة مباشرة في iframes مستضافة من قبل المزود (Stripe Elements، حقول بطاقة PayPal)
- OmniCRM لا ترى أو تخزن أرقام البطاقة الكاملة
- يتم تخزين طرق الدفع المرمزة فقط في قاعدة البيانات
- تم تقليل نطاق الامتثال لمعايير PCI لعملك
مقاييس معالجة الدفع
يوفر OmniCRM مقاييس شاملة لمراقبة عمليات معالجة الدفع. للحصول على تفاصيل كاملة حول مقاييس دفع Stripe بما في ذلك تتبع استدعاءات واجهة برمجة التطبيقات، أحجام الدفع، معدلات الفشل، وأوقات الاستجابة، راجع المراقبة والمقاييس.
مخطط قاعدة ا��بيانات غير مرتبط بالبائع
يدعم مخطط قاعدة البيانات أي مزود دفع دون الحاجة لترحيل:
مثال - حفظ بطاقة Square:
{
"vendor": "square",
"vendor_payment_method_id": "sq_card_abc123",
"payment_type": "card"
}
لا تغييرات في الكود. لا ترحيل. يعمل ببساطة.
المفاهيم الأساسية
نماذج البيانات
PaymentMethod
تخزين غير مرتبط بالبائع لطرق الدفع الخاصة بالعميل.
{
"payment_method_id": 789,
"customer_id": 123,
"vendor": "stripe", // 'stripe', 'paypal', or any added vendor
"vendor_payment_method_id": "pm_xxx", // Vendor's internal ID
"payment_type": "card", // 'card', 'paypal', 'ach', etc.
"is_default": true,
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2025,
"card_nickname": "My Visa Card",
"status": "active"
}
PaymentAuthorization
سجلات تفويض الالتزام من مرحلتين (احتجاز الأموال).
{
"authorization_id": 301,
"customer_id": 123,
"payment_method_id": 789,
"vendor": "stripe", // Which vendor authorized
"vendor_authorization_id": "auth_xxx", // Vendor's authorization ID
"amount": 200.00,
"currency": "USD",
"status": "authorized", // 'authorized', 'captured', 'released'
"authorized_at": "2025-12-27T10:00:00Z",
"expires_at": "2026-01-03T10:00:00Z",
"meta": {}
}
PaymentCapture
المدفوعات الملتقطة/المكتملة.
{
"capture_id": 103,
"authorization_id": 301,
"customer_id": 123,
"payment_method_id": 789,
"vendor": "stripe",
"vendor_transaction_id": "ch_xxx", // Vendor's transaction ID
"amount": 200.00,
"currency": "USD",
"status": "succeeded", // 'succeeded', 'failed', 'refunded'
"captured_at": "2025-12-27T10:30:00Z",
"vendor_response": {}, // Full vendor response
"meta": {}
}
WalletAccount
محفظة العميل مع تتبع الرصيد (1 إلى 1 مع العميل).
{
"wallet_account_id": 456,
"customer_id": 123,
"balance": 150.50,
"currency": "USD",
"auto_recharge_enabled": true,
"auto_recharge_amount": 100.00,
"auto_recharge_threshold": 10.00,
"low_balance_warning_threshold": 10.00
}
WalletLedger
سجل تدقيق كامل لجميع معاملات المحفظة.
{
"ledger_id": 501,
"customer_id": 123,
"wallet_account_id": 456,
"transaction_type": "credit", // 'credit', 'debit', 'refund', 'adjustment'
"amount": 100.00,
"balance_before": 150.50,
"balance_after": 250.50,
"currency": "USD",
"description": "Card top-up",
"reference_type": "payment_capture", // Links to related object
"reference_id": 103,
"meta": {},
"created_at": "2025-12-27T10:35:00Z"
}
المستندات المالية
للتخصيص وتوليد الفواتير، راجع فواتير العملاء.
الفواتير
التعريف: الفاتورة هي مستند يحتوي على قائمة من معاملات الخصم (الرسوم). عند استدعاء واجهة برمجة التطبيقات لإنشاء فاتورة، يجب تقديم مصفوفة من معرفات معاملات الخصم. يتم "ربط" تلك المعاملات بالفاتورة عن طريق تعيين حقل invoice_id الخاص بها.
للحصول على تفاصيل إدارة المعاملات، راجع المعاملات.
الحقول الرئيسية:
{
"invoice_id": 12345,
"invoice_number": "INV-2025-000001", // تم إنشاؤه تلقائيًا: INV-YYYY-NNNNNN
"customer_id": 123,
"title": "فاتورة خدمات شهرية",
"paid": true, // حالة الدفع
"void": false, // حالة الإلغاء
"payment_reference": "ch_xxxxx", // آخر/معرف الدفع الرئيسي
"payment_type": "stripe_capture", // نوع الدفع الأخير
"payment_time": "2025-12-27T10:30:00",
"start_date": "2025-12-01",
"end_date": "2025-12-31",
"due_date": "2026-01-15",
"retail_cost": 500.00, // إجمالي مبلغ الفاتورة
"wholesale_cost": 250.00
}
توليد الفواتير: يتم إنشاء أرقام الفواتير تلقائيًا بتنسيق INV-YYYY-NNNNNN، بالتسلسل ضمن السنة الميلادية، ويتم إعادة تعيينها في كل 1 يناير.
المدفوعات على الفواتير
كيف تعمل المدفوعات: بمجرد إنشاء فاتورة من معاملات الخصم، يمكن تطبيق الدفع عن طريق إنشاء معاملة ائتمانية (تكلفة تجزئة سلبية) مرتبطة بالفاتورة.
يجب أن:
- يتم إدراجها في الفاتورة مع وضع علامة واضحة كـ "مدفوعات"
- تظهر تاريخ الدفع المعني (الذي يمكن أن يختلف عن تاريخ إنشاء الفاتورة)
- تدعم عدة مدفوعات لكل فاتورة
- يتم صافيها ضد الخصومات لحساب رصيد الفاتورة
حالة الفاتورة:
- مدفوعة: إجمالي المدفوعات (الائتمانات) يساوي أو يتجاوز إجمالي الخصومات
- مدفوعة جزئيًا: تم تطبيق بعض المدفوعات ولكن لا يزال هناك رصيد
- مدفوعة زائدة: لا يتم ا��تعامل معها حاليًا - تتطلب تقسيم الائتمان (ميزة مستقبلية)
المحاسبة ذات القيد المزدوج: ينفذ النظام محاسبة صحيحة حيث كل رسوم لها دفعة معاكسة:
// 1. معاملة خصم (رسوم)
{
"transaction_id": 7001,
"invoice_id": 12345,
"retail_cost": 100.00, // إيجابي = العميل مدين
"title": "رسوم الخدمة"
}
// 2. معاملة ائتمانية (دفع)
{
"transaction_id": 7002,
"invoice_id": 12345,
"retail_cost": -100.00, // سالب = تم استلام الدفع
"title": "دفع للفاتورة: رسوم الخدمة (12345)",
"payment_type": "stripe_capture",
"payment_reference": "ch_xxxxx"
}
// النتيجة الصافية: رصيد $0 → الفاتورة تم وضع علامة عليها كمدفوعة
بيانات التعريف الإضافية للفاتورة: بالإضافة إلى المعاملات الائتمانية، تخزن الفاتورة أيضًا حقول ملخص (payment_reference، payment_type، payment_time) لعمليات البحث السريعة. ومع ذلك:
- الطريقة الأساسية: المعاملات الائتمانية مرتبطة عبر
invoice_id(مواصفات هايدن) - البيانات الوصفية الثانوية: تخزن حقول الفاتورة ملخصًا لآخر/الدفع الرئيسي
- لعدة مدفوعات: استعلام عن المعاملات الائتمانية للحصول على التاريخ الكامل
البيانات المالية
التعريف: تُظهر البيانات المالية جميع الخصومات والائتمانات من معاملات العميل على مدى فترة محددة. هذا هو نوع المستند الوحيد حيث يتم عرض كل من الخصومات والائتمانات كعناصر سطر معًا، مثل بيان البنك.
ملاحظات الائتمان
الغرض: يتم تطبيقها فقط على الفواتير التي تم تطبيق المدفوعات عليها بالفعل. يجب أن يتم ذلك كجزء من عملية إلغاء الفاتورة.
العملية:
- يتم إلغاء فاتورة (مع المعاملات الخصمية المرتبطة بها)
- يتم ربط أي مدفوعات تم تطبيقها بالفعل بملاحظة الائتمان التي تم إنشاؤها
- يدخل رصيد العميل في الائتمان بمقدار المبلغ المعادل
- يمكن بعد ذلك:
- تطبيق ملاحظة الائتمان على فاتورة أخرى كمدفوعات، أو
- استردادها للعميل
منطق الاسترداد: إذا تم اختيار الاسترداد، يتم استدعاؤه بناءً على المعاملات الائتمانية المرتبطة وكيف تم دفعها في الأصل (على سبيل المثال، استرداد Stripe إذا كان نوع المعاملة الائتمانية هو Stripe).
واجهات برمجة تطبيقات طرق الدفع
تستخدم جميع نقاط النهاية عنوان URL الأساسي: /api/payments/
لإدارة طرق الدفع بالتفصيل والتعامل مع البطاقات، راجع طرق الدفع.
إضافة طريقة دفع
احفظ طريقة دفع جديدة لعميل.
نقطة النهاية: POST /api/payments/methods
الطلب:
curl -X POST https://your-domain.com/api/payments/methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"is_default": false,
"card_nickname": "My Visa Card"
}'
جسم الطلب:
{
"customer_id": 123,
"vendor": "stripe", // 'stripe', 'paypal', or any added vendor
"payment_token": "pm_xxxxx", // رمز لمرة واحدة من SDK الواجهة الأمامية
"is_default": false, // تعيين كطريقة دفع افتراضية؟
"card_nickname": "My Visa Card" // اسم ودي اختياري
}
الاستجابة (201 تم الإنشاء):
{
"success": true,
"message": "تمت إضافة طريقة الدفع بنجاح",
"data": {
"payment_method_id": 789,
"customer_id": 123,
"vendor": "stripe",
"payment_type": "card",
"card_brand": "visa",
"card_last4": "4242",
"card_exp_month": 12,
"card_exp_year": 2025,
"card_nickname": "My Visa Card",
"is_default": false,
"status": "active"
}
}
الحصول على طرق الدفع
استرجع جميع طرق الدفع لعميل.
نقطة النهاية: GET /api/payments/methods?customer_id={id}
الطلب:
curl -X GET "https://your-domain.com/api/payments/methods?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
الاستجابة (200 حسنًا):
{
"success": true,
"data": [
{
"payment_method_id": 789,
"customer_id": 123,
"vendor": "stripe",
"payment_type": "card",
"card_brand": "visa",
"card_last4": "4242",
"is_default": true
},
{
"payment_method_id": 790,
"customer_id": 123,
"vendor": "paypal",
"payment_type": "paypal",
"paypal_email": "user@example.com",
"is_default": false
}
]
}
الحصول على طريقة الدفع الافتراضية
احصل على طريقة الدفع الافتراضية لعميل.
نقطة النهاية: GET /api/payments/methods/default?customer_id={id}
الطلب:
curl -X GET "https://your-domain.com/api/payments/methods/default?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
الاستجابة (200 حسنًا):
{
"success": true,
"data": {
"payment_method_id": 789,
"vendor": "stripe",
"payment_type": "card",
"card_brand": "visa",
"card_last4": "4242",
"is_default": true
}
}
تعيين طريقة الدفع الافتراضية
قم بتعيين طريقة الدفع كافتراضية.
نقطة النهاية: PUT /api/payments/methods/set-default
الطلب:
curl -X PUT https://your-domain.com/api/payments/methods/set-default \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"payment_method_id": 790
}'
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تم تحديث طريقة الدفع الافتراضية",
"data": {
"payment_method_id": 790,
"is_default": true
}
}
حذف طريقة الدفع
احذف طريقة دفع محفوظة.
نقطة النهاية: DELETE /api/payments/methods/{payment_method_id}?customer_id={id}
الطلب:
curl -X DELETE "https://your-domain.com/api/payments/methods/789?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تم حذف طريقة الدفع بنجاح"
}
واجهات برمجة تطبيقات تدفق الدفع
يدعم النظام عدة تدفقات دفع اعتمادًا على حالة الاستخدام الخاصة بك.
1. الدفع المباشر (رسوم بسيطة)
حالة الاستخدام: دفع بسيط من خطوة واحدة دون توفير الخدمة.
نقطة النهاية: POST /api/payments/charge
الطلب:
curl -X POST https://your-domain.com/api/payments/charge \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 50.00,
"currency": "USD",
"payment_method_id": 789,
"metadata": {
"order_id": "12345"
}
}'
جسم الطلب:
{
"customer_id": 123,
"amount": 50.00,
"currency": "USD", // الافتراضي: USD
"payment_method_id": 789, // اختياري - يستخدم الافتراضي إذا تم حذفه
"vendor": "stripe", // مطلوب إذا كنت تستخدم payment_token
"payment_token": "pm_xxxxx", // اختياري - رمز لمرة واحدة
"save_method": false, // حفظ طريقة الدفع للاستخدام المستقبلي؟
"metadata": {
"order_id": "12345"
}
}
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تم الدفع بنجاح",
"data": {
"transaction_id": "ch_xxxxx",
"capture_id": 101,
"amount": 50.00,
"currency": "USD",
"status": "succeeded"
}
}
2. ��فع الفاتورة (توجيه المحفظة أولاً)
حالة الاستخدام: دفع فاتورة باستخدام رصيد المحفظة أولاً، ثم البطاقة للباقي.
نقطة النهاية: POST /api/payments/invoice
التدفق:
- تحقق من رصيد المحفظة
- استخدم أموال المحفظة أولاً
- شحن البطاقة للقصور (إذا كان هناك أي)
- ائتمان المحفظة بمبلغ البطاقة
- خصم المحفظة للمبلغ الكامل للفاتورة
الطلب:
curl -X POST https://your-domain.com/api/payments/invoice \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 200.00,
"payment_method_id": 789,
"metadata": {
"invoice_id": 12345,
"description": "دفع الفاتورة"
}
}'
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تم معالجة دفع الفاتورة",
"data": {
"customer_id": 123,
"service_amount": 200.00,
"routing_mode": "hybrid",
"initial_balance": 150.00,
"wallet_portion_used": 150.00, // غطت المحفظة هذا المقدار
"card_portion_used": 50.00, // تم شحن البطاقة للباقي
"charged_amount": 50.00,
"wallet_credited": 50.00,
"wallet_debited": 200.00,
"final_balance": 0.00,
"payment_method_used": true
}
}
3. احتجاز التفويض (احتياطي الأموال)
حالة الاستخدام: احتجاز الأموال للاستخدام لاحقًا (مثل حجوزات الفنادق، الإيجارات).
🔧 تنفيذ الكتاب: لأمثلة كتب أنسيبل لتدفقات الدفع ذات المرحلتين، راجع نمط الالتزام ذو المرحلتين
الخطوة 1: إنشاء احتجاز التفويض
نقطة النهاية: POST /api/payments/authorize/hold
تدفق المحفظة أولاً:
- تحقق من رصيد المحفظة
- احسب القصور (المبلغ - wallet_balance)
- تفويض البطاقة للقصور فقط
- يتم خصم المحفظة في وقت الالتقاط، وليس هنا
الطلب:
curl -X POST https://your-domain.com/api/payments/authorize/hold \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 200.00,
"payment_method_id": 789,
"use_wallet": true,
"metadata": {
"reservation_id": "RES-001"
}
}'
جسم الطلب:
{
"customer_id": 123,
"amount": 200.00,
"currency": "USD",
"payment_method_id": 789, // اختياري - يستخدم الافتراضي إذا تم حذفه
"vendor": "stripe", // مطلوب إذا كنت تستخدم payment_token
"payment_token": "pm_xxxxx", // اختياري - رمز لمرة واحدة
"save_method": false,
"use_wallet": true, // تمكين توجيه المحفظة أولاً (الافتراضي: true)
"metadata": {
"reservation_id": "RES-001"
}
}
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تم تفويض الدفع (تم إنشاء الاحتجاز)",
"data": {
"authorization_id": 301,
"vendor_authorization_id": "auth_xxxxx",
"amount": 200.00,
"currency": "USD",
"status": "authorized",
"wallet_balance": 150.00,
"wallet_to_use": 150.00, // ستغطي المحفظة هذا المقدار
"card_amount": 50.00, // تم تفويض البطاقة لهذا المقدار
"message": "تم تفويض البطاقة بمبلغ 50 دولار (تعبئة المحفظة). سيتم خصم المحفظة بمبلغ 200 دولار عند الالتقاط."
}
}
الخطوة 2: التقاط التفويض
نقطة النهاية: POST /api/payments/capture/{authorization_id}
تدفق الالتقاط أولاً للمحفظة:
- التقاط البطاقة (إذا تم تفويضها) - تعبئة المحفظة
- ائتمان المحفظة بمبلغ البطاقة الملتقطة
- خصم المحفظة للمبلغ الكامل للخدمة
- إنشاء الفواتير/المعاملات (إذا تم الطلب)
الطلب:
curl -X POST https://your-domain.com/api/payments/capture/301 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"amount": 200.00,
"metadata": {
"invoice": true,
"title": "حجز الفندق",
"description": "إقامة لمدة 3 ليال",
"wholesale_cost": 100.00,
"contract_days": 3,
"send_email": true
}
}'
جسم الطلب:
{
"amount": 200.00, // اختياري - يتم التقاط المبلغ الكامل إذا تم حذفه
"metadata": {
"invoice": true, // إنشاء فاتورة ومعاملات؟
"create_transaction": true, // إنشاء سجل المعاملة؟
"title": "حجز الفندق",
"description": "إقامة لمدة 3 ليال",
"wholesale_cost": 100.00,
"contract_days": 3,
"send_email": true // إرسال بريد إلكتروني للفاتورة؟
}
}
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تم التقاط التفويض",
"data": {
"capture_id": 103,
"transaction_id": "ch_xxxxx",
"authorization_id": 301,
"amount": 200.00,
"currency": "USD",
"status": "succeeded",
"wallet_credit": { // تم تعبئة المحفظة بالبطاقة
"ledger_id": 401,
"amount": 50.00
},
"wallet_debit": { // تم شحن الخدمة من المحفظة
"ledger_id": 402,
"amount": 200.00
},
"transaction": { // تم إنشاؤه إذا كانت الفاتورة=true
"transaction_id": 7001
},
"invoice": { // تم إنشاؤه إذا كانت الفاتورة=true
"invoice_id": 12345,
"invoice_number": "INV-2025-000001"
}
}
}
الخطوة 3: تحرير التفويض (إلغاء)
نقطة النهاية: POST /api/payments/release/{authorization_id}
حالة الاستخدام: إلغاء الحجز، فشل التوفير، أو تغيير رأي العميل.
الطلب:
curl -X POST https://your-domain.com/api/payments/release/301 \
-H "Authorization: Bearer YOUR_API_KEY"
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تم تحرير التفويض",
"data": {
"authorization_id": 301,
"vendor_authorization_id": "auth_xxxxx",
"status": "released",
"released_at": "2025-12-27T10:45:00Z"
}
}
ملاحظة: مع تدفق المحفظة أولاً، لا حاجة لاسترداد المحفظة حيث لم يتم خصمها حتى وقت الالتقاط.
4. دفع التعبئة (ذو مرحلتين مع توفير)
حالة الاستخدام: معالجة الدفع لتعبئة الخدمة التي تتطلب توفيرًا (مثل تفعيل نقطة الاتصال/الدونجل). إذا فشل التوفير، يتم تحرير التفويض.
نقطة النهاية: POST /api/payments/topup
التدفق: تفويض → توفير الخدمة → التقاط
الطلب:
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 30.00,
"payment_method_id": 789,
"service_uuid": "svc-uuid-123",
"imsi": "123456789012345",
"days": 30,
"metadata": {
"is_rental": false
}
}'
لإيجار/نقطة اتصال مجهولة (طريقة الدفع غير محفوظة):
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 1,
"amount": 5.00,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"service_uuid": "hotspot-uuid",
"imsi": "123456789012345",
"days": 1,
"metadata": {
"is_rental": true,
"billing_email": "user@example.com"
}
}'
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تمت معالجة دفع التعبئة بنجاح",
"data": {
"transaction_id": "ch_xxxxx",
"authorization_id": 302,
"capture_id": 104,
"amount": 30.00,
"status": "succeeded",
"provision_result": {
"success": true,
"topup_result": {...},
"service_uuid": "svc-uuid-123",
"imsi": "123456789012345",
"days": 30
},
"payment_method_saved": false // خطأ للإيجار/النقطة الساخنة
}
}
5. دفع الإيجار (طرف ثالث)
حالة الاستخدام: شحن بطاقة عميل واحد لدفع خدمة عميل آخر.
نقطة النهاية: POST /api/payments/rental
الطلب:
curl -X POST https://your-domain.com/api/payments/rental \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"beneficiary_customer_id": 456,
"charge_customer_id": 123,
"amount": 75.00,
"payment_method_id": 789,
"service_description": "دفع خدمة الإيجار",
"metadata": {
"rental_agreement_id": "RA-001"
}
}'
لإيجار مجهول (بطاقة المستأجر غير محفوظة):
curl -X POST https://your-domain.com/api/payments/rental \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"beneficiary_customer_id": 456,
"amount": 75.00,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"service_description": "دفع إيجار مجهول",
"metadata": {
"billing_email": "renter@example.com"
}
}'
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تمت معالجة دفع الإيجار",
"data": {
"transaction_id": "ch_xxxxx",
"amount": 75.00,
"payment_method_saved": false // مجهول: لا توجد طريقة محفوظة
}
}
6. استرداد الدفع
نقطة النهاية: POST /api/payments/refund
الطلب:
curl -X POST https://your-domain.com/api/payments/refund \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"transaction_id": "ch_xxxxx",
"vendor": "stripe",
"amount": 50.00,
"reason": "customer_request"
}'
جسم الطلب:
{
"transaction_id": "ch_xxxxx", // معرف المعاملة الخاصة بالمزود
"vendor": "stripe", // 'stripe', 'paypal', إلخ.
"amount": 50.00, // اختياري - استرداد كامل إذا تم حذفه
"reason": "customer_request" // سبب الا��ترداد اختياري
}
الاستجابة (200 حسنًا):
{
"success": true,
"message": "تمت معالجة الاسترداد",
"data": {
"refund_id": "re_xxxxx",
"amount": 50.00,
"status": "succeeded"
}
}
واجهات برمجة تطبيقات المحفظة
تستخدم جميع نقاط النهاية الخاصة بالمحفظة عنوان URL الأساسي: /api/wallet/
الحصول على رصيد المحفظة
نقطة النهاية: GET /api/wallet/balance?customer_id={id}
الطلب:
curl -X GET "https://your-domain.com/api/wallet/balance?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
الاستجابة (200 حسنًا):
{
"customer_id": 123,
"balance": 150.50,
"currency": "USD"
}
الحصول على معلومات المحفظة
احصل على معلومات كاملة عن المحفظة والائتمان بما في ذلك إعدادات إعادة الشحن التلقائي.
نقطة النهاية: GET /api/wallet/info?customer_id={id}
الطلب:
curl -X GET "https://your-domain.com/api/wallet/info?customer_id=123" \
-H "Authorization: Bearer YOUR_API_KEY"
الاستجابة (200 حسنًا):
{
"customer_id": 123,
"wallet": {
"wallet_account_id": 456,
"balance": 150.50,
"currency": "USD",
"auto_recharge_enabled": true,
"auto_recharge_amount": 100.00,
"auto_recharge_threshold": 10.00,
"low_balance_warning_threshold": 10.00
}
}
تعبئة المحفظة
قم بتعبئة المحفظة عن طريق شحن طريقة الدفع.
نقطة النهاية: POST /api/wallet/topup
التدفق: شحن البطاقة/PayPal → ائتمان المحفظة
الطلب:
curl -X POST https://your-domain.com/api/wallet/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 100.00,
"payment_method_id": 789
}'
جسم الطلب:
{
"customer_id": 123,
"amount": 100.00,
"currency": "USD", // الافتراضي: USD
"payment_method_id": 789 // اختياري - يستخدم الافتراضي إذا تم حذفه
}
الاستجابة (200 حسنًا):
{
"success": true,
"payment": {
"transaction_id": "ch_xxxxx",
"amount": 100.00
},
"wallet": {
"ledger_id": 503,
"balance_after": 250.50
},
"message": "تم تعبئة المحفظة بمبلغ 100.00 دولار أمريكي"
}
الحصول على معاملات المحفظة
احصل على تاريخ معاملات المحفظة (دفتر الأستاذ).
نقطة النهاية: GET /api/wallet/transactions?customer_id={id}&limit={n}&offset={n}&type={type}
الطلب:
curl -X GET "https://your-domain.com/api/wallet/transactions?customer_id=123&limit=50&offset=0&type=credit" \
-H "Authorization: Bearer YOUR_API_KEY"
معلمات الاستعلام:
customer_id(مطلوب): معرف العميلlimit(اختياري): عدد السجلات (الافتراضي: 50)offset(اختياري): إزاحة الصفحات (الافتراضي: 0)type(اختياري): تصفية حسب نوع المعاملة ('credit'، 'debit'، 'refund'، 'adjustment')
الاستجابة (200 حسنًا):
{
"customer_id": 123,
"count": 2,
"transactions": [
{
"ledger_id": 501,
"transaction_type": "credit",
"amount": 100.00,
"balance_before": 150.50,
"balance_after": 250.50,
"currency": "USD",
"description": "تعبئة البطاقة",
"reference_type": "payment_capture",
"reference_id": 103,
"created_at": "2025-12-27T10:35:00Z"
},
{
"ledger_id": 502,
"transaction_type": "debit",
"amount": 50.00,
"balance_before": 250.50,
"balance_after": 200.50,
"currency": "USD",
"description": "رسوم الخدمة",
"reference_type": "service_charge",
"reference_id": 789,
"created_at": "2025-12-27T11:00:00Z"
}
]
}
ملخص مرجع واجهة برمجة التطبيقات
نقاط نهاية طريقة الدفع
| الطريقة | نقطة النهاية | الوصف |
|---|---|---|
| POST | /api/payments/methods | إضافة طريقة الدفع |
| GET | /api/payments/methods?customer_id={id} | الحصول على جميع طرق الدفع |
| GET | /api/payments/methods/default?customer_id={id} | الحصول على طريقة الدفع الافتراضية |
| PUT | /api/payments/methods/set-default | تعيين طريقة الدفع الافتراضية |
| DELETE | /api/payments/methods/{id}?customer_id={id} | حذف طريقة الدفع |
نقاط نهاية تدفق الدفع
| الطريقة | نقطة النهاية | الوصف |
|---|---|---|
| POST | /api/payments/charge | دفع مباشر (خطوة واحدة) |
| POST | /api/payments/invoice | دفع فاتورة (المحفظة أولاً) |
| POST | /api/payments/topup | تعبئة مع توفير |
| POST | /api/payments/authorize/hold | إنشاء احتجاز التفويض |
| POST | /api/payments/capture/{id} | التقاط التفويض |
| POST | /api/payments/release/{id} | تحرير التفويض |
| POST | /api/payments/rental | دفع الإيجار/طرف ثالث |
| POST | /api/payments/refund | استرداد الدفع |
نقاط نهاية المحفظة
| الطريقة | نقطة النهاية | الوصف |
|---|---|---|
| GET | /api/wallet/balance?customer_id={id} | الحصول على رصيد المحفظة |
| GET | /api/wallet/info?customer_id={id} | الحصول على معلومات المحفظة + الإعدادات |
| POST | /api/wallet/topup | تعبئة المحفظة عبر طريقة الدفع |
| GET | /api/wallet/transactions?customer_id={id} | الحصول على تاريخ المعاملات |
نقاط نهاية محددة لـ PayPal
| الطريقة | نقطة النهاية | الوصف |
|---|---|---|
| POST | /api/payments/paypal/vault/setup-token | إنشاء رمز إعداد PayPal لـ Card Fields SDK |
| POST | /api/payments/paypal/vault/finalize | إنهاء خزينة PayPal وحفظ طريقة الدفع |
| POST | /api/payments/paypal/vault/update-setup-token | تحديث رمز الإعداد لمعالجة 3DS/SCA |
حالات الاستخدام الشائعة
حالة الاستخدام 1: شحن العميل مقابل الخدمة (مدفوع مسبقًا)
السيناريو: عميل يدفع مقابل 30 يومًا من الخدمة باستخدام توجيه المحفظة أولاً.
# دفع الفاتورة (المحفظة أولاً، البطاقة للباقي)
curl -X POST https://your-domain.com/api/payments/invoice \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 99.99,
"metadata": {
"service_id": 456,
"contract_days": 30,
"description": "خدمة متميزة لمدة 30 يومًا"
}
}'
الاستجابة:
{
"success": true,
"message": "تمت معالجة دفع الفاتورة",
"data": {
"service_amount": 99.99,
"wallet_portion_used": 50.00, // كانت المحفظة تحتوي على 50 دولار
"card_portion_used": 49.99, // تم شحن البطاقة بمبلغ 49.99 دولار
"final_balance": 0.00
}
}
حالة الاستخدام 2: دفع ذو مرحلتين مع توفير الخدمة
السيناريو: توفير خدمة فقط بعد تفويض الدفع. إذا فشل التوفير، لا يتم فرض أي رسوم.
# دفع تعبئة مع توفير تلقائي
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 149.99,
"payment_method_id": 789,
"service_uuid": "fiber-svc-uuid",
"imsi": "123456789012345",
"days": 30,
"metadata": {
"service_type": "fiber_internet"
}
}'
التدفق:
- تفويض 149.99 دولار على البطاقة
- توفير خدمة الإنترنت بالألياف
- إذا نجح التوفير → التقاط الدفع
- إذا فشل التوفير → تحرير التفويض (لا رسوم)
حالة الاستخدام 3: دفع مجهول لنقطة الاتصال
السيناريو: مستخدم مجهول يدفع مقابل الوصول إلى واي فاي نقطة الاتصال. لا سجل للعميل، لا طريقة دفع محفوظة.
# د��ع نقطة اتصال مجهول
curl -X POST https://your-domain.com/api/payments/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 1,
"amount": 5.00,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"service_uuid": "hotspot-downtown",
"imsi": "999999999999999",
"days": 1,
"metadata": {
"is_rental": true,
"billing_email": "user@example.com",
"hotspot_location": "Cafe Downtown"
}
}'
النتيجة:
- تم معالجة الدفع ✅
- تم تفعيل نقطة الاتصال ✅
- لم يتم حفظ طريقة الدفع ✅
- لم يتم إنشاء سجل للعميل ✅
حالة الاستخدام 4: حجز فندق (احتجاز + التقاط)
السيناريو: احتجاز الأموال لحجز فندق، التقاط عند تسجيل الوصول، تحرير إذا تم الإلغاء.
# الخطوة 1: تسجيل الوصول - احتجاز الأموال
curl -X POST https://your-domain.com/api/payments/authorize/hold \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 500.00,
"use_wallet": true,
"metadata": {
"reservation_id": "RES-2025-001"
}
}'
# الاستجابة: {"authorization_id": 301, "status": "authorized"}
# الخطوة 2أ: تسجيل الوصول - التقاط
curl -X POST https://your-domain.com/api/payments/capture/301 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"metadata": {
"invoice": true,
"title": "إقامة الفندق - 3 ليال",
"description": "غرفة 302، 27-30 ديسمبر",
"send_email": true
}
}'
# الخطوة 2ب: إلغاء العميل - تحرير
curl -X POST https://your-domain.com/api/payments/release/301 \
-H "Authorization: Bearer YOUR_API_KEY"
حالة الاستخدام 5: إضافة طريقة دفع (Stripe)
السيناريو: عميل يضيف بطاقة فيزا جديدة إلى حسابه.
# الخطوة 1: الواجهة الأمامية تنشئ رمز Stripe عبر Stripe.js
# const {token} = await stripe.createToken(cardElement);
# الخطوة 2: الواجهة الخلفية تحفظ طريقة الدفع
curl -X POST https://your-domain.com/api/payments/methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"vendor": "stripe",
"payment_token": "pm_xxxxx",
"is_default": true,
"card_nickname": "Visa العمل"
}'
حالة الاستخدام 6: تعبئة المحفظة
السيناريو: عميل يقوم بتعبئة محفظته بمبلغ 100 دولار باستخدام طريقة الدفع المحفوظة.
curl -X POST https://your-domain.com/api/wallet/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 100.00
}'
الاستجابة:
{
"success": true,
"payment": {
"transaction_id": "ch_xxxxx",
"amount": 100.00
},
"wallet": {
"balance_after": 250.50
},
"message": "تم تعبئة المحفظة بمبلغ 100.00 دولار أمريكي"
}
معالجة الأخطاء
استجابات الأخطاء الشائعة
أموال غير كافية (400 طلب خاطئ):
{
"error": "رصيد المحفظة غير كافٍ. المتاح: 50.00، المطلوب: 200.00"
}
فشل الدفع (400 طلب خاطئ):
{
"error": "فشل الدفع. يرجى المحاولة مرة أخرى."
}
خطأ في التحقق (400 طلب خاطئ):
{
"error": "customer_id و amount مطلوبان"
}
غير موجود (404 غير موجود):
{
"error": "التفويض 999 غير موجود"
}
خطأ في الخادم (500 خطأ داخلي في الخادم):
{
"error": "حدث خطأ أثناء معالجة الدفع الخاص بك"
}
الاستردادات وتوجيه المحفظة أولاً
خيارات الاسترداد
يدعم النظام نوعين من الاستردادات اعتمادًا على احتياجات عملك:
1. استرداد إلى مصدر الدفع (Stripe/PayPal)
حالة الاستخدام: يطلب العميل استردادًا كاملًا للخدمة الملغاة أو المنتج المعيب.
التدفق: يعود المال إلى طريقة الدفع الأصلية (البطاقة، حساب PayPal، إلخ.)
نقطة النهاية: POST /api/payments/refund
المثال:
curl -X POST https://your-domain.com/api/payments/refund \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"transaction_id": "ch_xxxxx",
"vendor": "stripe",
"amount": 100.00,
"reason": "customer_request"
}'
النتيجة:
- تعالج Stripe/PayPal الاسترداد إلى طريقة الدفع الأصلية
- يرى العميل الائتمان على بطاقته/حساب PayPal خلال 5-10 أيام عمل
- لا يذهب المال إلى المحفظة
- يتم الحفاظ على سجل تدقيق كامل في جدول
PaymentCapture
متى يجب استخدامه:
- ✅ ألغى العميل الطلب
- ✅ لم يتم تسليم الخدمة
- ✅ خطأ في الفوترة
- ✅ يطلب العميل صراحةً استردادًا إلى البطاقة
2. ائتمان إلى المحفظة
حالة الاستخدام: استرداد جزئي، ائتمان الخدمة، أو الاحتفاظ بالأموال للشراء في المستقبل.
التدفق: يتم ائتمان المال إلى رصيد المحفظة للعميل للاستخدام الفوري.
ملاحظة: يتم عادةً التعامل مع ائتمانات المحفظة داخليًا بواسطة النظام خلال سيناريوهات الخطأ. للحصول على ائتمانات المحفظة اليدوية، اتصل بالدعم أو استخدم أدوات الإدارة.
النتيجة:
- الأموال متاحة على الفور في المحفظة
- لا فترة انتظار
- يمكن استخدامها للشراء في المستقبل
- يتم الحفاظ على سجل تدقيق كامل في جدول
WalletLedger
متى يجب استخدامه:
- ✅ ائتمانات الخدمة (مثل التعويض عن التوقف)
- ✅ استردادات جزئية حيث سيعيد العميل الشراء
- ✅ تعويض عن الخطأ (فشل التوفير)
- ✅ ائتمانات ترويجية
استراتيجية الاسترداد الهجينة
أفضل الممارسات: في سيناريوهات الخطأ خلال تدفق الدفع، يقوم النظام تلقائيًا بائتمان المحفظة بدلاً من استرداد البطاقة.
استرداد الخطأ التلقائي:
سيناريو المثال:
- يدفع العميل 100 دولار مقابل الخدمة
- يتم شحن البطاقة بنجاح
- يفشل التوفير
- بدلاً من استرداد 100 دولار إلى البطاقة (5-10 أيام + رسوم الاسترداد):
- ائتمان 100 دولار إلى المحفظة على الفور
- يمكن للعميل إعادة المحاولة للشراء على الفور
- لا رسوم استرداد
- تجربة مستخدم أفضل
توجيه المحفظة أولاً: شحنات البطاقة المحسّنة
يقوم النظام بشحن بطاقتك فقط للقصور، وليس المبلغ الكامل، عندما يكون لديك رصيد في المحفظة.
المثال 1: رصيد المحفظة 1 دولار + شراء 10 دولارات
السيناريو: لديك 1 دولار في محفظتك وترغب في شراء إضافة بقيمة 10 دولارات.
تدفق الدفع التقليدي (ليس كيف يعمل هذا النظام):
تدفق OmniCRM المحفظة أولاً:
طلب واجهة برمجة التطبيقات:
curl -X POST https://your-domain.com/api/payments/invoice \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 10.00,
"metadata": {
"addon_id": 456
}
}'
استجابة واجهة برمجة التطبيقات:
{
"success": true,
"message": "تمت معالجة دفع الفاتورة",
"data": {
"customer_id": 123,
"service_amount": 10.00,
"routing_mode": "hybrid",
"initial_balance": 1.00,
"wallet_portion_used": 1.00, // استخدم 1 دولار الموجود
"card_portion_used": 9.00, // تم شحن 9 دولارات فقط
"charged_amount": 9.00, // ← شحن البطاقة
"wallet_credited": 9.00, // ← تعبئة المحفظة
"wallet_debited": 10.00, // ← رسوم الخدمة
"final_balance": 0.00
}
}
المثال 2: رصيد المحفظة 50 دولار + شراء 30 دولار
السيناريو: لديك 50 دولار في المحفظة وشراء يكلف 30 دولار.
تدفق المحفظة أولاً:
استجابة واجهة برمجة التطبيقات:
{
"success": true,
"data": {
"service_amount": 30.00,
"initial_balance": 50.00,
"charged_amount": 0, // ← لا يوجد شحن للبطاقة
"wallet_debited": 30.00,
"final_balance": 20.00,
"payment_method_used": false // ← لم يتم استخدام البطاقة
}
}
المثال 3: احتجاز التفويض مع رصيد المحفظة
السيناريو: احتجاز 500 دولار لتفويض حجز فندق مع رصيد محفظة 150 دولار.
الخطوة 1: التفويض (POST /api/payments/authorize/hold):
استجابة واجهة برمجة التطبيقات:
{
"authorization_id": 301,
"amount": 500.00,
"status": "authorized",
"wallet_balance": 150.00,
"wallet_to_use": 150.00,
"card_amount": 350.00,
"message": "تم تفويض البطاقة بمبلغ 350 دولار (تعبئة المحفظة). سيتم خصم المحفظة بمبلغ 500 دولار عند الالتقاط."
}
الخطوة 2: الالتقاط (POST /api/payments/capture/301):
لماذا يهم هذا:
- ✅ يتم احتجاز 350 دولار فقط على البطاقة، وليس 500 دولار
- ✅ يقلل من تأثير الائتمان المتاح للعميل
- ✅ مبالغ التفويض أكثر دقة
- ✅ تجربة أفضل للعميل
تفاصيل التنفيذ
منطق توجيه المحفظة أولاً:
كيف يعمل:
- يتحقق النظام من الرصيد الحالي في المحفظة
- يحسب القصور:
amount - wallet_balance - إذا كان القصور > 0، يشحن البطاقة للقصور فقط
- يئتم المحفظة بمبلغ الدفع من البطاقة
- يخصم المحفظة للمبلغ الكامل للخدمة
- النتيجة: يتم شحن العميل فقط بما لم تتمكن المحفظة من تغطيته
تجاوز وضع التوجيه
يمكنك تجاوز سلوك المحفظة أولاً إذا لزم الأمر:
وضع التجاوز - شحن البطاقة دائمًا حتى لو كان لدى المحفظة أموال:
curl -X POST https://your-domain.com/api/payments/charge \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"customer_id": 123,
"amount": 100.00,
"metadata": {
"routing_mode": "bypass"
}
}'
النتيجة: تم شحن البطاقة بمبلغ 100 دولار، وتم ائتمان المحفظة بمبلغ 100 دولار، وتم خصم المحفظة بمبلغ 100 دولار (صافي: 0 دولار)
حالة الاستخدام: يرغب العميل في استخدام البطاقة للحصول على مكافآت/نقاط حتى مع وجود رصيد في المحفظة.
أفضل الممارسات
- استخدم دائمًا توجيه المحفظة أولاً لمدفوعات العملاء لتمكين الوظائف المدفوعة مسبقًا
- استخدم المدفوعات ذات المرحلتين (نقطة النهاية للتعبئة) عند توفير الخدمات لتجنب الشحن إذا فشل التوفير
- قم بتعيين البيانات الوصفية لجميع المدفوعات للحفاظ على سجل التدقيق
- استخدم المدفوعات المجهولة فقط للمستخدمين المجهولين حقًا (نقاط الاتصال، الإيجارات)
- تعامل مع الأخطاء بشكل جيد وقدم ملاحظات واضحة للمستخدم
- اختبر تدفقات الدفع في كل من السيناريوهات الناجحة والفاشلة
- راقب انتهاء صلاحية التفويضات (عادةً 7 أيام للبطاقات)
- نفذ إعادة الشحن التلقائي للخدمات المتكررة لتحسين تجربة العميل
أفضل الممارسات الخاصة بالكتب
عند تنفيذ تدفقات الدفع في كتب أنسيبل:
- استخدم دائمًا نمط الكتلة/الإنقاذ - لف لف توفير في try/catch للعودة التلقائية
- قم بتخزين authorization_id - احفظه لعمليات الالتقاط/الإفراج
- تحقق من استجابات واجهة برمجة التطبيقات - أكد النجاح قبل المتابعة
- قم بتدوير قيم العملة - استخدم دائمًا مكانين عشريين
- تحقق من طرق الدفع - تحقق من أن العميل لديه طريقة دفع افتراضية قبل التفويض
راجع أفضل الممارسات للكتب للحصول على تفاصيل وأمثلة كاملة.
المصادقة
تتطلب جميع نقاط النهاية لواجهة برمجة التطبيقات المصادقة عبر مفتاح API في رأس Authorization:
Authorization: Bearer YOUR_API_KEY
اتصل بمدير النظام لديك لتوفير مفتاح API.
دعم البائع
المدعوم حاليًا
- Stripe - دعم كامل (البطاقات، ACH)
- PayPal - دعم كامل (حسابات PayPal، البطاقات عبر Card Fields SDK)
إضافة بائعين جدد
تجعل الهيكلية المودولية من السهل إضافة بائعين جدد. راجع قسم الهيكلية المودولية للحصول على التفاصيل.
الوثائق ذات الصلة
أدلة التنفيذ
- التحصيل والمدفوعات من كتب التشغيل - تنفيذ كتاب أنسيبل
أدلة محددة للميزات
- فواتير العملاء - توليد الفواتير، التخصيص، والتخصيص
- طرق الدفع - إدارة طرق الدفع الخاصة بالعملاء، البطاقات، وحسابات PayPal
- المعاملات - إدارة المعاملات، الرسوم اليدوية، والائتمانات
- معالجة الدفع - تدفقات معالجة الدفع
- أساسيات الفوترة - أساسيات فوترة العملاء
التنقل السريع
- هل تضيف بائعين؟ → راجع الهيكلية المودولية
- تكوين Stripe/PayPal؟ → راجع تكوين المزود
- تخصيص الفواتير؟ → راجع فواتير العملاء
- توفير الخدمات؟ → راجع تكامل الكتاب