Khaled Ahmed
الرئيسية المدوّنة المنصات والمنتجات
المنصات والمنتجات

ربط Tabby و Tamara و Mada و PayTabs في متجر إلكتروني مخصص

Khaled Ahmed 19 min read

إذا كنت تبني متجراً مخصصاً للسعودية أو الخليج، فإن اختيار وسائل الدفع ليس قراراً بإضافة جاهزة، بل قرار معماري، وخطؤه يكلفك موعد الإطلاق نفسه. هنا المسار الحقيقي لربط Tabby و Tamara و mada و PayTabs: ما الذي يطلبه كل مزوّد قبل أن تكتب سطراً واحداً، وكيف تتصرف الـ webhooks فعلياً تحت الضغط، وماذا يحدث لأموالك بعد أن يضغط العميل على زر الدفع.

أطلقت صفحات دفع خليجية على Laravel وعلى Node وفوق أكواد نصف مكتملة كتبها غيري. النمط يتكرر دائماً. المؤسس يفترض أن الدفع هو الجزء السهل لأن هناك إضافة جاهزة. ثم يستغرق التسجيل التجاري ثلاثة أسابيع، وتتصرف بيئة الـ sandbox بشكل مختلف تماماً عن بيئة الإنتاج، ويصل إشعار مرتين، ويُشحن طلب لم يُحصَّل مبلغه أصلاً.

لا شيء من هذا مكتوب في وثائق المزوّدين. هو مكتوب هنا.

1. الخلاصة قبل التفاصيل

إن لم تقرأ سوى قسم واحد، فليكن هذا.

أطلق ببوابة بطاقات واحدة، لا بثلاث. اختر مزوّداً مرخّصاً من SAMA يمنحك mada و Visa/Mastercard و Apple Pay عبر ربط واحد: PayTabs أو HyperPay أو Moyasar أو Tap في السعودية، و PayTabs أو Telr أو Checkout.com في الإمارات، و Paymob إن كانت مصر ضمن نطاقك. ربط واحد، تقرير تسوية واحد، عملية مطابقة حسابية واحدة.

أضف التقسيط ثانياً لا أولاً. Tabby و Tamara أدوات رفع تحويل، لا بنية تحتية للدفع. تستحق الإضافة — التجار في الخليج يلاحظون باستمرار ارتفاعاً في متوسط قيمة السلة بعد تفعيلها — لكنها عقد منفصل، وتسجيل منفصل، وتعاقد تقني منفصل على الإشعارات، ومسار استرداد منفصل. لا تدع أياً منها يعطّل إطلاقك.

لا يمكنك استخدام Stripe ككيان سعودي. هذه ليست تفضيلاً بل واقعاً، وسأفصّله في القسم السابع.

mada ليست اختيارية. هي البطاقة المهيمنة في المملكة بفارق واسع جداً. صفحة دفع سعودية بلا mada هي صفحة تفقد أغلب عملائها عند الخطوة الأخيرة.

لا تثق أبداً بمحتوى الإشعار الوارد كمصدر للحقيقة. تعامل مع كل إشعار على أنه تلميح بأن شيئاً ما تغيّر، ثم استدعِ endpoint الاستعلام لدى المزوّد وصدّق ما يعود منه. هذه القاعدة وحدها تمنع أغلب الأخطاء التي تكلّف مالاً حقيقياً والتي أُستدعى لإصلاحها.

2. بماذا يدفع العميل الخليجي فعلاً

أرقام الحصص السوقية المنشورة عن الدفع في السعودية متفاوتة جداً بين المصادر، لذا تعامل مع أي نسبة دقيقة تقرأها — بما في ذلك ما يقتبسه لك مندوبو المبيعات — كمؤشر اتجاه لا كقياس. ما لا خلاف عليه هو الترتيب.

mada في المقدمة بوضوح. هي شبكة الخصم المحلية التي أنشأها البنك المركزي السعودي، وهي موجودة على بطاقة كل بنك سعودي تقريباً، والمستهلك السعودي يمد يده إلى بطاقة الخصم أولاً. بطاقات Visa و Mastercard الائتمانية الدولية تأتي ثانياً، وغالباً من المقيمين والشركات. Apple Pay نمت بسرعة كافية لتصبح متطلباً أساسياً لا إضافة لطيفة. STC Pay تحتفظ بحصة محفظة معتبرة. التقسيط عبر Tabby و Tamara شريحة أصغر من حيث عدد العمليات لكنها شريحة أكبر بكثير من حيث قيمة السلة. الدفع عند الاستلام يتراجع لكنه لم يختفِ، خصوصاً خارج المدن الكبرى.

الأثر التصميمي: صفحة الدفع تحتاج mada و Apple Pay من اليوم الأول، والبطاقة كبديل، والتقسيط كأداة رفع، والدفع عند الاستلام إن كان تصنيفك يبرره — مع عملية مطابقة حسابية ليست جدول بيانات. إن كنت لا تزال في مرحلة اختيار البنية العامة للمتجر، فإن دليل تطوير المتاجر الإلكترونية يغطي الطبقات التي تقع أسفل هذه الطبقة.

ما لا يخبرك به أحد عن mada على الإنترنت: بطاقات mada بطاقات خصم. الخصم يعني رصيد العميل الفعلي، ورمز تحقق في كل عملية، وخطوة 3D Secure إجبارية لا يمكن تخطيها. صفحة الدفع لديك يجب أن تنجو من تحويل كامل إلى صفحة مصادقة البنك والعودة منها، على هاتف، على اتصال متقطع، وأحياناً مع انتقال العميل إلى تطبيق البنك لالتقاط الرمز. إن كانت حالة الطلب لديك تعتمد على عودة العميل إلى رابط النجاح، فستخسر طلبات. صمّم بحيث يكون الإشعار بين الخوادم هو الإشارة الأساسية، وعودة المتصفح مجرد راحة إضافية.

3. كيف أضيف Tabby و Tamara إلى متجر مبني خصيصاً؟

هذا أكثر سؤال يصلني، والإجابة الصادقة شقّان: الشق التجاري يستغرق وقتاً أطول من الشق التقني.

قبل أي كود: المسار التجاري

كل من Tabby و Tamara يشترط أن تكون تاجراً معتمداً قبل أن تحصل على مفاتيح الإنتاج. هذا يعني سجلاً تجارياً في السوق الذي تبيع فيه، وحساباً بنكياً في ذلك السوق، وبيانات المنشأة، ومراجعة لتصنيف نشاطك، وفي الغالب اتفاقية تاجر موقّعة بنسبة متفاوض عليها. بعض التصنيفات تُرفض أو تُسعّر بقسوة: القطاعات كثيرة الاسترداد، والمنتجات الرقمية، وأي نشاط يبدو كإعادة بيع لقيمة مخزّنة.

يمكنك عادة الحصول على بيانات اعتماد تجريبية بسرعة لتبدأ البناء. لكنك لن تنتقل إلى الإنتاج بلا عقد. ابدأ المسار التجاري في اليوم الأول من المشروع بالتوازي مع التطوير، وإلا صار هو المسار الحرج.

مسار Tabby

نموذج Tabby يقوم على جلسة دفع تتبعها عملية دفع لها دورة حياة. تعلّم هذه الدورة جيداً لأن أغلب أخطاء الربط تنبع من سوء فهمها.

  1. أنشئ جلسة دفع من الخادم لديك، تتضمن قيمة الطلب والعملة وبيانات المشتري وعناصر السلة وعنوان الشحن، والأهم: سجل المشتري وسجل طلباته السابقة.
  2. يقيّم Tabby العميل مسبقاً. الاستجابة تخبرك إن كان العميل مؤهلاً وأي خطط تقسيط متاحة له. إن أعادت الحالة rejected فهذا يعني عدم توفر أي منتج لهذا المشتري، وعليك إخفاء خيار Tabby أو تعطيله بلباقة بدلاً من تركه يضغط ليصل إلى طريق مسدود.
  3. حوّل العميل إلى الرابط العائد من Tabby ليصادق ويوافق على الخطة.
  4. تصبح العملية authorized. المبلغ محجوز والتزام قائم، لكنه ليس ملكك بعد.
  5. تُحصّل المبلغ كلياً أو جزئياً عند الشحن. التحصيل الكامل ينقل العملية إلى closed وهي الحالة النهائية.
  6. تسترد مقابل عملية محصّلة، أو تلغي تفويضاً لم تحصّله.

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

// Laravel: إنشاء جلسة دفع Tabby
$payload = [
    'payment' => [
        'amount'      => number_format($order->total, 2, '.', ''),
        'currency'    => 'SAR',
        'description' => "Order #{$order->reference}",
        'buyer' => [
            'phone' => $customer->phone_e164,
            'email' => $customer->email,
            'name'  => $customer->full_name,
        ],
        'buyer_history' => [
            'registered_since' => $customer->created_at->toIso8601String(),
            'loyalty_level'    => $customer->completed_orders_count,
        ],
        'order' => [
            'reference_id' => $order->reference,
            'items'        => $this->mapItems($order),
        ],
        'order_history' => $this->lastOrders($customer, 10),
    ],
    'lang'          => app()->getLocale(),
    'merchant_code' => config('tabby.merchant_code'),
    'merchant_urls' => [
        'success' => route('checkout.tabby.success', $order),
        'cancel'  => route('checkout.tabby.cancel', $order),
        'failure' => route('checkout.tabby.failure', $order),
    ],
];

$response = Http::withToken(config('tabby.public_key'))
    ->timeout(15)
    ->post(config('tabby.base_url') . '/api/v2/checkout', $payload)
    ->throw()
    ->json();

if (($response['status'] ?? null) === 'rejected') {
    // لا توجد خطة متاحة لهذا المشتري: أخفِ الخيار ولا تحوّله
    return back()->with('bnpl_unavailable', true);
}

انتبه إلى الرابط الأساسي المختلف حسب السوق. يخدم Tabby المملكة وبقية أسواق الخليج من نطاقات مختلفة بمسارات متطابقة، والبيئة — تجريبية أو إنتاجية — تُحدَّد بالمفتاح الذي تصادق به لا بخانة في الطلب. اجعل الرابط الأساسي إعداداً لكل سوق ولا تكتبه ثابتاً في الكود أبداً.

مسار Tamara

Tamara مشابهة في البنية لكنها مختلفة في تفاصيل جوهرية ستؤذيك إن افترضت التماثل.

  1. أنشئ جلسة دفع ببيانات الشراء وبيانات المستهلك وتفصيل السلة وروابط النجاح والفشل والإلغاء والإشعار.
  2. يوافق العميل على صفحة Tamara المستضافة، فينتقل الطلب إلى approved.
  3. يجب أن تفوّض الطلب صراحة. هذه الخطوة التي يغفلها الناس. الطلب المعتمَد لدى Tamara ليس طلباً مكتملاً — عليك استدعاء واجهة Authorize Order لتأكيد استلامك وقبولك له. تجاهل هذه الخطوة يعني أن الطلب لن يصبح قابلاً للتحصيل أبداً.
  4. تُحصّل عند الشحن.
  5. تحصّل Tamara تلقائياً إن لم تفعل. السلوك الموثّق لديهم أن الطلب المفوَّض الذي يبقى بلا تحصيل واحداً وعشرين يوماً يُحصَّل تلقائياً وينتقل إلى حالة التحصيل الكامل.

نافذة التحصيل التلقائي هذه هي أهم فرق عملي بين المزوّدَين لمن يبيع منتجات تُصنَّع حسب الطلب أو حجوزات مسبقة أو أي شيء بمدة تنفيذ طويلة. إن كانت مدة إنتاجك ثلاثين يوماً، فستحصّل Tamara في اليوم الحادي والعشرين سواء شحنت أم لا، فتقول دفاترك محصَّل، ويقول المستودع لم يخرج شيء، ويكتشف محاسبك الفجوة في الربع التالي. ابنِ مهمة مجدولة ترصد الطلبات المفوَّضة غير المشحونة قبل إغلاق النافذة بوقت كافٍ وتفرض قراراً بشرياً.

مصادقة إشعارات Tamara مختلفة أيضاً. تسجّل رابط الإشعار في بوابة الشركاء لديهم، وتختار أحداث حالة الطلب التي تريدها، وتوقّع Tamara كل إشعار بـ JWT يُمرَّر كوسيط في الرابط وكـ bearer token في ترويسة التفويض، وتفكّه بمفتاح الإشعار لديك للتأكد أن المحتوى لم يُعبث به أثناء النقل.

عرض التقسيط على صفحة المنتج بشكل صحيح

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

4. هل تتطلب mada حساب تاجر سعودياً محلياً؟

نعم عملياً، وهذا هو المتطلب الذي يفاجئ أغلب المؤسسين العاملين من خارج المملكة.

mada شبكة محلية يحكمها البنك المركزي السعودي. لقبول mada عبر الإنترنت تحتاج معرّف تاجر صادراً عبر جهة استحواذ سعودية، أي عملياً التعاقد مع بوابة دفع أو بنك مرخّص من SAMA. الترخيص يحمله المزوّد، ولست بحاجة إلى ترخيص خاص بك كتاجر. لكنك تحتاج أن تكون مؤهلاً للتسجيل لدى مزوّد محلي مرخّص، وتسجيله سيطلب منك:

  • سجلاً تجارياً سعودياً، أو في بعض الحالات وثيقة عمل حر للممارسين الأفراد.
  • حساباً بنكياً سعودياً باسم الكيان المسجّل لأغراض التسوية.
  • هويات المالك أو المفوّض بالتوقيع.
  • موقعاً منشوراً بأسعار ظاهرة وشروط وسياسة استرداد وبيانات تواصل، ومحتوى عربي بشكل متزايد.
  • إفصاحاً عن التصنيف وحجم المبيعات المتوقع، وأحياناً عرضاً لمسار الدفع لديك.

الشركة الأجنبية بلا كيان سعودي أمامها مساران واقعيان: تأسيس كيان سعودي، أو العمل مع جهة استحواذ دولية تملك قدرة استحواذ سعودية وتستطيع تقديم mada لحسابك. المسار الثاني موجود لكنه عادة محجوز لأحجام كبيرة.

تفصيل عملي إضافي: بطاقات mada المُصدَرة اليوم مزدوجة الشعار. محلياً تمر عبر شبكة mada، ودولياً يتولاها الجانب التابع لـ Visa أو Mastercard. قرار التوجيه لدى بوابتك يؤثر على تكلفتك. إن كانت أحجامك معتبرة، اسأل مزوّدك مباشرة كيف تُوجَّه عمليات mada المحلية وكيف تُسعَّر مقابل الشبكة الدولية — الفرق مال حقيقي عند الحجم، وهو سؤال لا يطرحه أغلب التجار.

تحقق من قائمة المستندات الدقيقة وجدول الرسوم الحالي مع المزوّد قبل الالتزام. متطلبات التسجيل والتسعير في هذا السوق تتغير بوتيرة تجعل أي رقم منشور اليوم نقطة بداية للتفاوض لا عرضاً نهائياً.

5. مقارنة صادقة بين البوابات

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

المزوّد النوع الأسواق الأساسية شكل الربط شكل الرسوم والتسوية الأنسب لـ
PayTabs بوابة بطاقات السعودية والإمارات ومصر والكويت وعُمان والبحرين وقطر والأردن وما جاورها صفحة دفع مستضافة أو نموذج مُدار أو واجهة كاملة، مع IPN و callback لكل طلب وتوقيع HMAC على كامل محتوى الطلب نسبة مئوية مع مبلغ ثابت لكل عملية، وتسوية خلال أيام عمل قليلة، أسرع في السعودية منها في الإمارات التجار متعددو الدول الذين يريدون عقداً واحداً عبر الحدود
HyperPay بوابة بطاقات السعودية والخليج أداة COPYandPAY المستضافة أو ربط بين الخوادم بنموذج معرّف الدفع، مع إدارة 3D Secure نيابة عنك تسعير موجّه للمؤسسات، وتسجيل ومراجعة امتثال أثقل التجار الكبار والقطاعات المنظّمة والمشتريات المؤسسية
Moyasar بوابة بطاقات السعودية واجهة REST نظيفة وتوثيق جيد ودعم مباشر لـ mada و Apple Pay تسعير منشور وشفاف، وسرعة تسوية mada هي ميزتها المعلنة الأبرز الشركات الناشئة السعودية والفرق التي يقودها المطورون وتريد الإطلاق هذا الشهر
Paymob بوابة بطاقات مصر والسعودية والإمارات وباكستان واجهة Intention ومعرّفات ربط لكل وسيلة وتحقق HMAC على الإشعارات تسعير تنافسي في مصر مع محافظ محلية وشركاء تقسيط مدمجين المتاجر التي تكون فيها مصر السوق الأول أو سوقاً رئيسياً
Tabby تقسيط السعودية والإمارات والكويت وقطر والبحرين جلسة دفع وتقييم مسبق ثم تفويض فتحصيل، وإشعارات بترويسة مخصصة تحمل سراً مشتركاً نسبة خصم تاجر أعلى بوضوح من البطاقات، وتسوية خلال أيام بحسب الخطة الانتشار الخليجي الواسع وحضور قوي في الإمارات
Tamara تقسيط السعودية والإمارات والكويت جلسة دفع ثم خطوة تفويض صريحة ثم تحصيل، مع تحصيل تلقائي بعد 21 يوماً وإشعارات موقّعة بـ JWT نسبة خصم تاجر أعلى بوضوح من البطاقات، وتسوية متدرجة بحسب الخطة المتاجر السعودية أولاً، مع وعي بالعلامة قوي داخل المملكة

القراءة العملية: بوابات البطاقات تتنافس على جودة الربط وسرعة التسوية، والفروق بينها صغيرة بما يكفي لتجعل تجربة المطور هي الفيصل. أما مزوّدو التقسيط فيتنافسون على نسبة القبول ووعي المستهلك بالعلامة، والفروق هناك كبيرة بما يكفي لتجعل كثيراً من المتاجر السعودية الجادة تشغّل Tabby و Tamara معاً وتترك الاختيار للعميل.

6. كم يكلف ربط التقسيط وكم يستغرق؟

ثلاث تكاليف منفصلة، والناس يضعون ميزانية للأولى فقط.

تكلفة البناء

لإضافة مزوّد تقسيط واحد إلى متجر مخصص قائم ومبني جيداً — أي لديك بالفعل آلة حالات نظيفة للطلب وطبقة تجريد عاملة للدفع — يحتاج مطور كفء عدة أيام عمل. تغطي إنشاء الجلسة ومعالجة التحويل ونقطة استقبال الإشعارات والتحصيل عند التنفيذ ومعالجة الاسترداد وأداة صفحة المنتج وظهور الحالة في لوحة التحكم واختبار مسارات الفشل في البيئة التجريبية.

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

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

الزمن المنقضي

البناء ليس القيد. تسجيل التاجر هو القيد. بين التقديم ومراجعة المستندات واعتماد التصنيف والتفاوض التجاري وإصدار مفاتيح الإنتاج، خطّط لأسابيع لا لأيام، وابدأ قبل التطوير. أقول لعملائي: تعاملوا مع إطلاق التقسيط كمرحلة تعتمد على طرف ثالث لا تتحكمون فيه، وأطلقوا المتجر بدونه إن لم يُوقَّع العقد.

التكلفة المستمرة

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

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

7. هل أستطيع استخدام Stripe بدل بوابة خليجية في السعودية؟

لا، ليس ككيان مسجّل في السعودية.

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

  • لا mada. هذا وحده مانع. ستردّ عملاءك حاملي البطاقة الأكثر انتشاراً في السوق.
  • نسب رفض عابرة للحدود. البطاقات السعودية المقدَّمة لجهة استحواذ أجنبية تُرفض أكثر. لن ترى ذلك في الاختبار، بل في نسبة التحويل.
  • احتكاك العملة والتسوية. العميل يرى رسوم عملية دولية، وأنت تخسر على فروق الصرف، ودفاترك تتوقف عن مطابقة وضعك الضريبي المحلي.
  • انكشاف تنظيمي. البيع داخل المملكة مع المعالجة عبر كيان خارجي يفتح أسئلة عن فوترتك الإلكترونية ووضعك الضريبي لا تحب أن تجيب عنها بأثر رجعي. وإن كنت مسجلاً في ضريبة القيمة المضافة بالسعودية فلديك التزامات الفوترة الإلكترونية لدى ZATCA التي يجب أن تتسق مع طريقة تسوية المدفوعات فعلياً.

أين يصلح Stripe فعلاً: أن تكون شركة مسجلة في دولة مدعومة، تبيع منتجات رقمية عالمياً، والعملاء السعوديون أقلية من إيرادك. عندها Stripe مع بوابة خليجية كمسار ثانوي منطق سليم. أما لمتجر خليجي أولاً فلا.

المنطق نفسه ينطبق على PayPal في هذه المنطقة. هو وسيلة مكمّلة لشريحة عملاء محددة، لا مسار دفع رئيسي.

8. الإشعارات: الجزء الذي لا يوثّقه أحد جيداً

هنا تنكسر المتاجر المخصصة فعلاً، وهذا هو القسم الذي كنت أتمنى قراءته قبل خمس سنوات.

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

  • PayTabs يرسل ترويسة توقيع تحتوي HMAC لكامل محتوى الطلب مجزّأً بمفتاح الخادم الخاص بملفك. تعيد الحساب وتقارن.
  • Paymob يرسل HMAC محسوباً على تسلسل محدد ومرتّب من حقول بعينها، لا على المحتوى الخام، ويجب أن تبنيه بالترتيب الموثّق حرفياً. اخطئ في الترتيب يفشل التحقق في كل إشعار.
  • Tamara ترسل JWT للإشعار كوسيط في الرابط وكـ bearer token، موقّعاً بخوارزمية HS256، تفكّه وتتحقق منه.
  • Tabby يتيح لك تسجيل اسم ترويسة مخصصة وقيمتها عند تسجيل نقطة الإشعار، ويرسل ذلك السر المشترك مع كل إشعار. انتبه جيداً لما هو عليه: سر مشترك، لا توقيع على المحتوى. هو يثبت أن الطلب جاء من طرف يملك سرك، ولا يثبت أن المحتوى لم يُعدَّل.

هذا التمييز الأخير هو سبب وجود القاعدة التالية.

القاعدة الأولى: طابِق ولا تثق

لا تغيّر حالة الطلب أو المال مباشرة اعتماداً على محتوى الإشعار. استخدم الإشعار فقط لتعرف أن شيئاً ما في عملية الدفع هذه قد تغيّر، ثم استدعِ endpoint الاستعلام لدى المزوّد بمفتاحك السري وتصرّف بناءً على تلك الاستجابة الموثوقة.

هذا يكلفك طلباً واحداً إضافياً. ويشتري لك مناعة من المحتويات المزوّرة والطلبات المعادة والإشعارات المبتورة وكل تغيير في البنية يشحنه المزوّد دون إخبارك.

القاعدة الثانية: الـ idempotency إلزامي

كل مزوّد يعيد المحاولة. وإعادة المحاولة لا تُميَّز عن التكرار عند نقطة الاستقبال لديك. بلا إزالة تكرار ستحصل على تنفيذ مزدوج للطلب ورسائل مزدوجة وقيود محاسبية مزدوجة، وفي النهاية استرداد مزدوج.

أزل التكرار بناءً على معرّف مستقر: معرّف الحدث إن أرسله المزوّد، وإلا فبصمة تجمع معرّف الدفع مع الحالة الناتجة، مخزّنة بقيد فريد في قاعدة البيانات. اجعل القيد هو أداة الفرض، لا فحصاً على مستوى التطبيق يتسابق عند وصول إشعارين متزامنين.

القاعدة الثالثة: افترض وصولاً خارج الترتيب

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

مثّل حالة الدفع كآلة حالات صريحة بانتقالات مسموحة، وارفض أي انتقال يعيد العملية إلى الوراء. عملية مستردّة يصلها إشعار تفويض متأخر يجب أن تُسجَّل وتُتجاهل، لا أن تتراجع.

القاعدة الرابعة: أقرّ بالاستلام بسرعة وعالج بشكل غير متزامن

أعِد الرمز 200 فور تسجيلك الحدث بشكل دائم. أما المطابقة وتشغيل التنفيذ وإصدار الفاتورة والرسائل فاجعلها في طابور معالجة. إن نفّذت عمل التجهيز داخل المعالجة واستغرقت ثماني ثوانٍ، فسينتهي وقت انتظار المزوّد ويعتبر التسليم فاشلاً ويعيد المحاولة، وتصبح تنفّذ العمل نفسه مرتين بالتوازي.

// Laravel: نقطة استقبال إشعارات تتصرف بشكل صحيح مع إعادة المحاولة
public function handle(Request $request, string $provider)
{
    $verifier = $this->verifiers->for($provider);

    if (! $verifier->verify($request)) {
        Log::warning('payment.webhook.rejected', ['provider' => $provider]);
        return response()->noContent(401);
    }

    $eventKey = $verifier->eventKey($request); // مستقر لكل حدث منطقي

    try {
        $event = WebhookEvent::create([
            'provider'  => $provider,
            'event_key' => $eventKey,   // UNIQUE (provider, event_key)
            'payload'   => $request->all(),
        ]);
    } catch (QueryException $e) {
        // مسجّل مسبقاً: إعادة محاولة أو تكرار. أقرّ وتوقف.
        return response()->noContent(200);
    }

    ReconcilePayment::dispatch($provider, $verifier->paymentId($request), $event->id);

    return response()->noContent(200);
}

والمهمة التي تقوم بالعمل الفعلي — لاحظ أنها تسأل المزوّد بدل أن تصدّق ما وصلها:

public function handle(PaymentGatewayRegistry $gateways): void
{
    $gateway = $gateways->get($this->provider);

    // القراءة الموثوقة. الإشعار كان مجرد تلميح.
    $remote = $gateway->retrievePayment($this->paymentId);

    DB::transaction(function () use ($remote) {
        $payment = Payment::where('provider_payment_id', $remote->id)
            ->lockForUpdate()
            ->firstOrFail();

        if (! $payment->state->canTransitionTo($remote->state)) {
            Log::info('payment.transition.ignored', [
                'from' => $payment->state->value,
                'to'   => $remote->state->value,
            ]);
            return;
        }

        $payment->applyRemoteState($remote);
        $payment->save();
    });
}

أمران إضافيان يجب أن يوجدا في كل ربط إنتاجي. أولاً، سجّل كل إشعار وارد بصيغته الخام واحتفظ به — حين ينازعك مزوّد في تسوية، يكون المحتوى المخزَّن ورمز استجابتك هما الدليل. ثانياً، تعامل مع نقطة الإشعار كمسار عام غير مصادَق وأمّنها على هذا الأساس؛ مكانها في قائمة التحقق من أمان الموقع إلى جانب تحديد المعدل وحد حجم الطلب.

مهمة المطابقة التي ستندم على عدم بنائها

الإشعارات تفشل. المزوّدون ينقطعون، وخادمك يمر بعمليات نشر، والـ DNS له أيام سيئة. شغّل مهمة مجدولة — كل ساعة تكفي عادة — تبحث عن كل عملية دفع عالقة في حالة غير نهائية أقدم من حد معين وتستعلم عن حالتها لدى المزوّد. هذه تلتقط كل ما فاتته طبقة الإشعارات، وهي ربما ثلاثون سطراً من الكود. كل ربط دفع ناضج عملت عليه لديه واحدة. أغلب الأنظمة المعطلة التي استُدعيت لإصلاحها لم يكن لديها.

9. التحصيل والاسترداد وأين يوجد المال فعلاً

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

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

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

الاسترداد ليس إلغاءً. الاسترداد على طلب تقسيط لا يلغي خطة الأقساط ببساطة. المزوّد يعدّل جدول المستهلك المتبقي، ومدد وصول المبلغ إلى العميل تمتد أسابيع بحسب البنك المستقبِل. اضبط هذا التوقع في نصوصك الموجّهة للعميل بالعربية، وإلا تحمّل فريق الدعم التكلفة.

التسوية ليست لكل طلب. المزوّدون يجمّعون العمليات. تستلم مبلغاً إجمالياً على دورة، صافياً بعد الرسوم، يغطي نافذة زمنية من العمليات. قاعدة بياناتك فيها طلبات، وكشف حسابك فيه إيداعات، ولا شيء يتطابق تلقائياً. ابنِ استيراداً لتقارير التسوية يربطها بمعرّفات الطلبات من الإطلاق، لا بعد ثمانية عشر شهراً حين يسأل أحدهم أخيراً لماذا لا تتطابق الأرقام. هذه مسألة نمذجة بيانات بقدر ما هي مسألة مدفوعات، وتنطبق عليها أسس تصميم قواعد بيانات تطبيقات الويب: المدفوعات والتحصيلات والاستردادات والتسويات أربعة جداول مترابطة، لا أربعة أعمدة في جدول الطلبات.

أصدر الفاتورة عند التحصيل لا عند الطلب. إن كنت مسجلاً في ضريبة القيمة المضافة بالسعودية، فتوقيت فاتورتك الضريبية مهم ويجب أن يتبع المال لا النقرة. اربط إصدار الفاتورة بحدث التحصيل. مقالتي عن ربط الفوترة الإلكترونية ZATCA مع Laravel تغطي الجانب الامتثالي بالتفصيل.

10. بأي بوابة يبدأ المتجر الخليجي؟

توصيتي بوضوح.

متجر سعودي فقط: ابدأ بـ Moyasar إن كان فريقك يقدّر تجربة المطور وسرعة الوصول للسوق، أو PayTabs إن كنت تتوقع التوسع خارج المملكة خلال سنة. كلاهما يمنحك mada والبطاقات و Apple Pay عبر ربط واحد. أضف Tamara أولاً للتقسيط لأن وعي العلامة السعودي أقوى لديها، ثم Tabby بعد استقرار الأول.

متجر إماراتي أولاً: PayTabs أو Checkout.com للبطاقات، و Tabby أولاً للتقسيط نظراً لقوته في الإمارات، ثم Tamara.

متعدد الدول الخليجية من اليوم الأول: PayTabs، لأن عقداً واحداً يغطي أغلب أسواق الخليج يزيل قدراً هائلاً من العبء التشغيلي — مطابقة حسابية منفصلة لكل دولة تكلفة حقيقية لا تظهر في مقارنة الرسوم.

مصر ضمن النطاق: Paymob للجانب المصري، مع تقبّل أنك ستشغّل بوابتَي بطاقات. لا تحاول إجبار مزوّد واحد على تغطية مصر والخليج معاً بشكل جيد.

في كل الحالات: ابنِ طبقة التجريد قبل المزوّد الثاني لا بعده. الواجهة التي تحتاجها صغيرة — إنشاء جلسة، استعلام عن دفع، تحصيل، تحصيل جزئي، استرداد، إلغاء — والانضباط بكتابتها مسبقاً هو ما يجعل المزوّد الثالث عمل يومين بدل عمل أسبوعين.

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

11. أخطاء أُستدعى لإصلاحها باستمرار

حالة الطلب مبنية على عودة المتصفح. ينقطع اتصال هاتف العميل في طريق العودة من صفحة رمز التحقق البنكي، فلا يُستدعى مسار النجاح، ويبقى الطلب غير مدفوع بينما خُصم المبلغ من العميل. اجعل الإشعار بين الخوادم مع مهمة المطابقة هما مالكا الحالة دائماً.

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

المفاتيح السرية في واجهة المستخدم. Tabby وأغلب البوابات تصدر مفتاحاً عاماً وآخر سرياً لسبب. المفتاح السري لا يغادر خادمك أبداً. ما زلت أجده داخل حزم JavaScript.

غياب التكافؤ مع البيئة التجريبية. اختبار المسار السعيد وحده، ثم اكتشاف أن 3D Secure في الإنتاج يضيف تحويلاً لم تتوقعه آلة حالاتك.

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

لا مفتاح idempotency على الطلبات الصادرة أيضاً. إزالة تكرار الإشعارات تنال الاهتمام، أما أمان إعادة المحاولة الصادرة فلا. إن انتهى وقت انتظار طلب التحصيل وأعدت المحاولة بلا مفتاح idempotency، فقد تحصّل مرتين.

اعتبار لوحة المزوّد دفتر حساباتك. هي عرض تقريري لبياناتهم، لا دفاترك. نظامك يحتاج سجلات دفع خاصة به تستطيع الاستعلام عنها وتدقيقها ومطابقتها باستقلال.

12. من أين تبدأ

إن كنت في البداية: اختر بوابة بطاقات واحدة، وقدّم طلب التاجر هذا الأسبوع، وابنِ طبقة تجريد الدفع بينما تنتظر الموافقة. أضف التقسيط حين يُوقَّع العقد لا قبله. وابنِ مهمة المطابقة في اليوم الأول لأنك لن تجد لها وقتاً لاحقاً.

وإن كان لديك متجر قائم يخسر طلبات عند الدفع، فالتشخيص عادة أحد ثلاثة: غياب mada، أو آلة حالات تعتمد على عودة المتصفح، أو معالج إشعارات غير محصّن ضد التكرار. الثلاثة قابلة للإصلاح في أيام لا شهور.

أبني وأصلح ربط المدفوعات الخليجية ضمن تطوير المتاجر الإلكترونية المخصصة، غالباً على Laravel، وأنا مستعد لمراجعة ربط قائم وإخبارك بما فيه من خلل بنفس القدر الذي أستعد فيه لإعادة بنائه. إن أردت من يتولى هذا من أوله إلى آخره، يمكنك توظيفي كمطور Laravel — أو ببساطة أرسل لي تفاصيل متجرك وسأخبرك بصراحة إن كانت لديك مشكلة تستحق أن تدفع لحلها.

أسئله شائعه

كيف أضيف Tabby و Tamara إلى متجر مبني خصيصاً؟
هناك مساران، والتجاري أطول. تجارياً، كلاهما يشترط حساب تاجر معتمداً: سجل تجاري في السوق الذي تبيع فيه، وحساب بنكي محلي، ومراجعة للتصنيف، واتفاقية موقّعة بنسبة متفاوض عليها. ابدأ هذا من اليوم الأول. تقنياً، كلاهما يتبع: إنشاء جلسة، موافقة العميل، تفويض، تحصيل، استرداد. في Tabby تنشئ جلسة الدفع من الخادم متضمنة سجل المشتري وسجل طلباته — وهي مدخلات التقييم المسبق لديهم فعبّئها من جدول طلباتك — وتعالج حالة rejected بإخفاء الخيار، ثم تحوّل العميل، ثم تحصّل عند الشحن. في Tamara تنشئ الجلسة ثم يجب أن تستدعي صراحة واجهة Authorize Order بعد موافقة العميل، فالطلب المعتمَد ليس قابلاً للتحصيل قبل ذلك، ثم تحصّل عند الشحن. وابنِ طبقة تجريد للمزوّدين تضم إنشاء جلسة واستعلاماً وتحصيلاً وتحصيلاً جزئياً واسترداداً وإلغاءً قبل إضافة المزوّد الثاني.
هل تتطلب mada حساب تاجر سعودياً محلياً؟
عملياً نعم. mada شبكة محلية يحكمها البنك المركزي السعودي، وقبولها عبر الإنترنت يتطلب معرّف تاجر صادراً عبر جهة استحواذ سعودية، أي عملياً بوابة مرخّصة من SAMA مثل PayTabs أو HyperPay أو Moyasar أو Tap. الترخيص لدى البوابة لا لديك، فلا تحتاج ترخيصاً خاصاً بك كتاجر. لكنك تحتاج أن تكون مؤهلاً للتسجيل: سجل تجاري سعودي أو وثيقة عمل حر في بعض الحالات، وحساب بنكي سعودي باسم الكيان لأغراض التسوية، وهويات المالك أو المفوّض بالتوقيع، وموقع منشور بأسعار وشروط وسياسة استرداد وبيانات تواصل. الشركة الأجنبية بلا كيان سعودي إما تؤسس كياناً أو تعمل مع جهة استحواذ دولية تملك قدرة استحواذ سعودية، وهذا عادة للأحجام الكبيرة. تحقق من قائمة المستندات الدقيقة مع المزوّد لأن هذه المتطلبات تتغير.
كم يكلف ربط التقسيط وكم يستغرق؟
ثلاث تكاليف. البناء: لإضافة مزوّد واحد إلى متجر لديه بالفعل آلة حالات نظيفة وطبقة تجريد للدفع، يحتاج مطور كفء عدة أيام عمل تغطي إنشاء الجلسة ومعالجة التحويل ونقطة الإشعارات والتحصيل والاسترداد وأداة صفحة المنتج واختبار مسارات الفشل. إن لم توجد طبقة تجريد فخصّص ميزانية لبنائها أولاً. الزمن: القيد هو تسجيل التاجر لا الكود — التقديم ومراجعة المستندات واعتماد التصنيف والتفاوض وإصدار المفاتيح تستغرق أسابيع واقعياً، فابدأ قبل التطوير وأطلق بدون التقسيط إن لم يُوقَّع العقد. المستمرة: نسب خصم التاجر في التقسيط أعلى بشكل ملموس من البطاقات، بما يكفي لتحريك هامشك الإجمالي، وتتغير بحسب الخطة والتصنيف والتفاوض. احسبها على مزيج سلتك الفعلي؛ فمع هامش ضيق ومتوسط طلب منخفض قد يكلفك التقسيط أكثر مما تستحقه الطلبات الإضافية.
هل أستطيع استخدام Stripe بدل بوابة خليجية في السعودية؟
ليس ككيان مسجّل في السعودية. السعودية ليست ضمن الدول المدعومة لفتح حساب تاجر لدى Stripe، فالكيان السعودي لا يستطيع التسجيل مباشرة. والحيلة الشائعة بتسجيل شركة في دولة مدعومة والمعالجة عبرها قائمة فعلاً لكنها فكرة سيئة لمتجر سعودي. لن تحصل على mada، وهذا وحده مانع لأنها البطاقة التي يحملها أغلب عملائك. والبطاقات السعودية المقدَّمة لجهة استحواذ أجنبية تُرفض أكثر، ولن ترى ذلك إلا في نسبة التحويل. والعميل يواجه رسوم عملية دولية، وأنت تخسر على فروق الصرف، وتتوقف دفاترك عن مطابقة وضعك الضريبي المحلي بما في ذلك التزامات الفوترة الإلكترونية لدى ZATCA. Stripe منطقي فقط إن كنت مسجلاً في دولة مدعومة وتبيع منتجات رقمية عالمياً والعملاء السعوديون أقلية من إيرادك. والمنطق نفسه ينطبق على PayPal هنا: وسيلة مكمّلة لا مسار دفع رئيسي.
بأي بوابة يبدأ المتجر الخليجي؟
أطلق ببوابة بطاقات واحدة لا بثلاث. لمتجر سعودي فقط: Moyasar إن كان فريقك يقدّر تجربة المطور وسرعة الوصول للسوق، أو PayTabs إن كنت تتوقع التوسع خارج المملكة خلال سنة، وكلاهما يمنحك mada والبطاقات و Apple Pay عبر ربط واحد. للإمارات أولاً: PayTabs أو Checkout.com للبطاقات. لمتعدد الدول الخليجية من اليوم الأول: PayTabs، لأن عقداً واحداً عبر أغلب أسواق الخليج يزيل عبء مطابقة حسابية لا يظهر في مقارنة الرسوم. ومع وجود مصر في النطاق: Paymob لمصر، وتقبّل تشغيل بوابتَي بطاقات بدل إجبار مزوّد واحد على خدمة المنطقتين بشكل ضعيف. أضف التقسيط فقط بعد استقرار مسار البطاقات: Tamara أولاً في السعودية لقوة العلامة، و Tabby أولاً في الإمارات للسبب نفسه.
كيف أعالج إشعارات الدفع بحيث لا تنكسر الطلبات؟
أربع قواعد. أولاً، طابِق ولا تثق: لا تغيّر حالة الطلب أو المال اعتماداً على محتوى الإشعار، بل تعامل معه كإشارة بأن شيئاً في عملية الدفع تغيّر، ثم استدعِ endpoint الاستعلام لدى المزوّد بمفتاحك السري وتصرّف بناءً عليه. وهذا أهم ما يكون مع Tabby لأن ترويسته المخصصة سر مشترك لا توقيع على المحتوى، بخلاف PayTabs الذي يرسل HMAC لكامل المحتوى بمفتاح الخادم، و Paymob الذي يحسب HMAC على تسلسل حقول محدد ومرتّب، و Tamara التي ترسل JWT موقّعاً بـ HS256. ثانياً، أزل التكرار بمعرّف حدث مستقر مفروض بقيد فريد في قاعدة البيانات، فكل مزوّد يعيد المحاولة وإعادة المحاولة لا تُميَّز عن التكرار. ثالثاً، مثّل حالة الدفع كآلة حالات صريحة وارفض الانتقالات إلى الوراء، لأن الإشعارات تصل خارج الترتيب. رابعاً، سجّل الحدث وأعِد 200 فوراً ونفّذ العمل في طابور معالجة. ثم أضف مهمة كل ساعة تستعلم عن أي عملية عالقة في حالة غير نهائية.
متى أحصّل المبلغ، وكيف تعمل التسوية فعلاً؟
حصّل عند التنفيذ لا عند إتمام الطلب. التفويض والتحصيل والتسوية ثلاثة أحداث مختلفة بثلاثة توقيتات. التحصيل عند إتمام الطلب في البضائع المادية يعني احتجاز مال العميل مقابل أصناف قد تكون نافدة، وهو ما يضخّم مؤشرات الاسترداد والمنازعات لديك. وإن شحنت ثلاثة أصناف من خمسة، حصّل قيمة الثلاثة بدل التحصيل الكامل ثم استرداد الفرق، فالأمران يبدوان متطابقين في قاعدة بياناتك ومختلفين تماماً في تقارير المزوّد وفاتورة رسومك. وانتبه لنافذة التحصيل التلقائي الموثّقة لدى Tamara بعد واحد وعشرين يوماً: الطلب المفوَّض الذي يبقى بلا تحصيل هذه المدة يُحصَّل تلقائياً، وهذا يفسد دفاترك بصمت إن كانت مدة تنفيذك أطول. والتسوية مجمّعة لا لكل طلب: تستلم مبلغاً إجمالياً على دورة صافياً بعد الرسوم، فابنِ استيراداً لتقارير التسوية يربطها بمعرّفات الطلبات من الإطلاق. وإن كنت مسجلاً في ضريبة القيمة المضافة بالسعودية، أصدر الفاتورة الضريبية عند حدث التحصيل لا عند تقديم الطلب.
كلمات مفتاحية: Payment GatewaysTabbyTamaramadaPayTabsBNPLSaudi ArabiaEcommerce

مستعد لتطبيق ما قرأته؟

استشاره مجانية 30 دقيقة، رد خلال 24 ساعة، وعرض سعر مكتوب.

تواصل واتساب