الانتقال إلى المحتوى الرئيسي
كل المقالات
المنتج10 دقائق قراءة

استرداد مبلغ لزبون: كليًا أو جزئيًا، من بوابة التاجر أو عبر API

استرداد مبلغ لزبون كليًا أو جزئيًا، من بوابة التاجر أو عبر API: مرجع refundReference، والحالات، والأثر على الرصيد، وسطر التصدير، والرسالة إلى الزبون.

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

الإلغاء قبل الأداء، والاسترداد بعده

ChariPay منصة دفع مغربية، مزوّد خدمات دفع (PSP) تشغّله Chari Money، مؤسسة أداء مرخَّصة من بنك المغرب. قبل البحث عن طريقة الاسترداد، اطرحوا سؤالًا واحدًا: هل تحرّك المال فعلًا؟ ما دام الزبون لم يؤدِّ، فلا شيء يُردّ — يكفي منعه من الأداء. أما بعد نجاح أداء بالبطاقة، فالاسترداد هو الإجراء الوحيد الممكن.

الحالةالإجراء الصحيحما يحدث
رابط دفع أُرسل ولم يُؤدَّ بعدإلغاء الرابط — عبر API: POST /v1/payment-links/{reference}/cancelيصبح الرابط «ملغى»؛ والرابط الملغى لا يمكن أداؤه بعد ذلك
جلسة دفع أُنشئت ولم تُؤدَّ بعدإلغاء الجلسة — POST /v1/payment-sessions/{sessionId}/cancelتُلغى الجلسة؛ ودون هذا النداء تنتهي صلاحيتها من تلقاء نفسها، بعد 72 ساعة افتراضيًا أو عند expiresAt
أداء ناجح بالبطاقةالاسترداد، كليًا أو جزئيًايُخصم المبلغ من رصيدكم المتاح؛ والعودة من جهة البنك ليست فورية

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

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

استرداد مبلغ لزبون من بوابة التاجر

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

قبل التأكيد، أربعة قرارات تعود إليكم:

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

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

الاسترداد عبر API بمرجع refundReference ثابت

عبر API، يكفي نداء واحد للاسترداد: POST /v1/refunds، مع معرّف الأداء الأصلي ومرجع الاسترداد الخاص بكم وسبب.

bash
curl -X POST 'https://api-psp.charipay.ma/v1/refunds' \
  -H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
  -H 'Content-Type: application/json' \
  -d '{
    "operationId": 8123,
    "refundReference": "refund-ORD-2026-0421-1",
    "refundAmount": 100.00,
    "reason": "CUSTOMER_CANCELLATION",
    "note": "Article retourne"
  }'

حقلًا حقلًا:

  • `operationId` يحدّد الأداء المراد استرداده. اقرؤوه في GET /v1/transactions أو GET /v1/transactions/{operationId}. وبدلًا منه، يقبل externalId قيمة orderId الخاصة بكم لأداء تمّ عبر جلسة — انتبهوا: ليس هو externalId الذي أرسلتموه عند إنشاء الجلسة. ويبيّن دليل ربط الأداء بالطلبية أين يعود كل معرّف.
  • `refundReference` (64 حرفًا على الأكثر) مرجعكم أنتم، ثابت ومبنيّ على رقم الطلبية، مثل refund-ORD-2026-0421-1. وهو مفتاح الـIdempotency: يجيب الإنشاء بـ202 Accepted، وإعادة المرجع نفسه تُرجع الاسترداد الموجود بـ200 دون خصم ثانٍ — ولا 201 أبدًا. والمبدأ مشروح في Idempotency في المدفوعات.
  • `refundAmount` يحدّد مبلغ الاسترداد الجزئي؛ وفي غيابه يكون الاسترداد كليًا.
  • `reason` يأخذ قيمة من قائمة محدّدة: MERCHANT_CANCELLATION أو CUSTOMER_CANCELLATION أو PLATFORM_ORCHESTRATION أو OTHER. والنص الحرّ مرفوض فيه: مكانه `note`، في حدود 128 حرفًا. ويقبل metadata أيضًا مفاتيحكم الخاصة.

والمرجع الكامل لنقاط النهاية الثلاث — الإنشاء والقراءة والقائمة — في وحدة «الاستردادات» في توثيق API.

يمكنكم تكرار هذه الدورة دون أي مخاطرة في السندبوكس: ابدؤوا في وضع الاختبار. ثلاثة حقول (الاسم، والبريد الإلكتروني المهني، والمؤسسة)، ورابط تفعيل يصلكم بالبريد لاختيار كلمة المرور، ثم بوابة التاجر حيث تنشئون بأنفسكم مفتاح الاختبار. أدّوا طلبية ببطاقة الاختبار، واستردّوها عبر API، وأعيدوا النداء لتروا الرد 200: لا يتحرك أي مال حقيقي، والتحقق من مؤسستكم (KYB) لا يشترطه إلا الانتقال إلى الإنتاج.

استرداد جزئي أم كلي: refundAmount هو الفيصل

الاسترداد الجزئي ليس عملية مستقلة: إنه النداء نفسه بحقل إضافي. دون refundAmount تردّون الأداء كاملًا؛ ومع refundAmount تردّون ذلك المبلغ بالدرهم وبالوحدات الرئيسية (100.00 = 100,00 درهم).

مثال: أُدّيت الطلبية ORD-2026-0421 بمبلغ 250,00 درهمًا، وأرجع الزبون منتجًا ثمنه 100,00 درهم. وهذا هو النداء أعلاه: "refundAmount": 100.00، والسبب CUSTOMER_CANCELLATION، والملاحظة "Article retourne" (منتج مُرجَع). فيحتفظ الزبون ببقية طلبيته، ويعرف نظامكم بدقة ما رُدّ ولماذا.

الحالةrefundAmountreason المقترحnote
تلغون قبل الشحن (نفاد المخزون)غائب: كليMERCHANT_CANCELLATION«نفاد المخزون»
الزبون يتراجع قبل التسليمغائب: كليCUSTOMER_CANCELLATION«إلغاء من الزبون»
الزبون يُرجع منتجًاثمن المنتجCUSTOMER_CANCELLATION«منتج مُرجَع»
منتج ناقص في الطردثمن المنتجMERCHANT_CANCELLATION«منتج ناقص»
خدمة أُنجزت جزئيًاالجزء غير المنجزحسب من يتراجعوصف قصير
بادرة تجارية بعد تأخيرمبلغ البادرةOTHER«بادرة تجارية»

القاعدة الذهبية: حدّدوا المبلغ الدقيق قبل النداء، مع الشخص الذي يعرف الطلبية. فمرجع refundReference وملاحظة note ومبلغ refundAmount يجب أن تروي القصة نفسها.

تتبّع الاسترداد: الحالة والأحداث

الردّ 202 Accepted يعني أن الطلب سُجّل، لا أن المال عاد إلى الزبون: فالاسترداد ليس فوريًا من جهة البنك. ولمعرفة النتيجة، طريقان متكاملان:

  • أحداث الويب هوك. refund.succeeded حين ينجح الاسترداد، وrefund.failed حين يفشل. إن كانت نقطة الاستقبال لديكم تصرّح بقائمة enabledEvents صريحة، فأضيفوا إليها هذين الحدثين — والقائمة الفارغة تستقبل كل الأحداث. وجّهوا المعالجة حسب الترويسة Chari-Event-Type، وأزيلوا التكرار على Chari-Event-Id.
  • القراءة المباشرة. يعيد GET /v1/refunds/{reference} الاسترداد انطلاقًا من مرجع refundReference الخاص بكم (أو من المعرّف الذي تمنحه المنصة)، ويعرض GET /v1/refunds قائمة استرداداتكم من الأحدث إلى الأقدم.

في نظامكم، تصبح الطلبية «مستردّة» عند وصول refund.succeeded، لا لحظة النداء. وبين الاثنين، اعرضوا «استرداد قيد المعالجة»: فهذه هي الحالة الفعلية. وإن لم ينجح استرداد، فتحقّقوا أولًا من رصيدكم المتاح — فإن لم يكفِ تُوقَف العملية — ثم تواصلوا مع الفريق إن لم يكن السبب واضحًا.

وبلا مطوّر، تكفي بوابة التاجر: فكل حركة في الحساب، ومنها الاستردادات، تحمل فيها مرجع البيع أو الاسترداد أو الدفعة التي تفسّرها.

الأثر على رصيدكم وعلى الدفعة التالية

استرداد مبلغ لزبون مجاني: لا تُضاف أي رسوم استرداد، كما تبيّن صفحة الأسعار. ويُخصم المبلغ المستردّ من رصيدكم المتاح.

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

  • قبل استرداد مبلغ كبير، انظروا إلى رصيدكم المتاح — في بوابة التاجر أو عبر GET /v1/wallet.
  • وإن لم يغطِّ المبلغ، فانتظروا مستخلصات جديدة أو غذّوا الحساب عبر POST /v1/wallet/cash-ins، مع ترويسة Idempotency-Key الإلزامية.

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

سطر الاسترداد في التصدير

الاسترداد لا يمحو البيع: بل يليه. في التصدير، كل استرداد حركة مستقلة، مرتبطة بالمعاملة الأصلية وحاملة لمرجع الاسترداد. وتميّز بوابة التاجر بين المبلغ المدفوع والرسوم والصافي، ويحتفظ تصدير CSV بهذه المراجع — من بوابة التاجر أو عبر GET /v1/transactions/export.csv، حتى 10 000 سطر؛ وفوق ذلك قسّموا حسب الفترة بـfrom وto.

وبالنسبة إلى محاسبكم، يعني ذلك قيدين مؤرَّخين: البيع، ثم الاسترداد. ثلاث عادات تُبسّط هذا التتبّع:

  1. 1احتفظوا بمرجع `refundReference` في نظام الطلبيات لديكم: فهو الذي يربط سطر التصدير بملف الزبون.
  2. 2طابقوا الدفعة الأصغر مع تصدير الفترة نفسها، لا مع البيع المستردّ.
  3. 3حوّلوا الطوابع الزمنية: فهي بتوقيت UTC، والمغرب على UTC+1. والاسترداد الذي يتمّ بُعيد منتصف الليل بتوقيت المغرب يحمل في التصدير تاريخ اليوم السابق.

والطريقة الكاملة — الفوارق بين المستخلَص وما دُفع نحو البنك، والاستردادات، والمنطقة الزمنية — في مطابقة المستخلصات.

إخبار الزبون: الرسالة التي تُرسل

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

مرحبًا أمين، أطلقنا استرداد 100,00 درهم على طلبيتكم ORD-2026-0421 (استرداد جزئي: منتج مُرجَع). والاسترداد ليس فوريًا من جهة البنك: سيعود إليكم المبلغ حسب معالجة بنككم. مرجعنا: refund-ORD-2026-0421-1. ولن نطلب منكم أبدًا بيانات بطاقتكم.

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

وإن سمحت أداتكم، فرسالة ثانية أقصر عند وصول refund.succeeded تُغلق الدائرة. وللعلاقة مع الزبون عبر الإنترنت بمعناها الواسع — التأكيدات والإيصالات وسياسة الإرجاع — راجعوا دليل الدفع الإلكتروني للتجارة الإلكترونية في المغرب.

أسئلة شائعة

كم يكلّف الاسترداد؟

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

هل يمكن القيام باسترداد جزئي؟

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

ماذا يحدث إذا لم يكفِ الرصيد للاسترداد؟

تُوقَف العملية بدل إحداث رصيد مدين: فلا سحب على المكشوف في حساب الأداء ولا ائتمان. تحقّقوا من رصيدكم المتاح في بوابة التاجر أو عبر GET /v1/wallet، ثم انتظروا مستخلصات جديدة أو غذّوا الحساب عبر POST /v1/wallet/cash-ins. وفي الأثناء، أخبروا الزبون بأن استرداده قيد التحضير بدل تركه دون أخبار.

متى يرى الزبون المال يعود إلى بطاقته؟

الاسترداد ليس فوريًا من جهة البنك، ولا ننشر أي أجل: فالعودة تتوقف على معالجة بنك الزبون. ومن جهتكم، يخبركم الحدث refund.succeeded، أو القراءة عبر GET /v1/refunds/{reference}، بأن الاسترداد نجح. أخبروا الزبون بأن العملية انطلقت، وأعطوه مرجع الاسترداد الخاص بكم، ولا تعِدوه بتاريخ محدّد.

من يستطيع استرداد مبلغ لزبون في بوابة التاجر؟

المالك أو مسيّر مخوَّل: فهما من يُطلقان العمليات الصادرة. يستخلص أمين الصندوق دون أن يرى الرصيد أو التحويلات، ولا يستردّ؛ ويقرأ المحاسب كل شيء دون أن يُطلق أي عملية. لذا يُرفع الطلب الوارد إلى الصندوق إلى المسيّر. وعبر API، ينطلق النداء بمفتاح API الخاص بكم، وهو سرّ لا يغادر خادمكم أبدًا.

هل نستردّ أم نلغي رابط دفع لم يُؤدَّ؟

نلغيه. ما دام الرابط غير مؤدّى، فلا شيء يُستردّ: ألغوه، والرابط الملغى لا يمكن أداؤه بعد ذلك. وعبر API، النداء هو POST /v1/payment-links/{reference}/cancel. والمنطق نفسه لجلسة دفع غير مؤدّاة، عبر POST /v1/payment-sessions/{sessionId}/cancel. فالاسترداد لا يخص إلا الأداءات الناجحة؛ ومن بين الإجراءين، هو وحده ما يحرّك رصيدكم.

هل يظهر الاسترداد في كشف حسابي البنكي؟

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

أي سبب نذكر في استرداد عبر API؟

لا يقبل الحقل reason إلا قيمة من قائمة محدّدة: MERCHANT_CANCELLATION حين تلغون أنتم، وCUSTOMER_CANCELLATION حين يتراجع الزبون، وOTHER لأي سبب آخر؛ وتضمّ القائمة أيضًا PLATFORM_ORCHESTRATION. والنص الحرّ مرفوض فيه. ضعوا شروحكم في note، في حدود 128 حرفًا — «منتج ناقص»، «بادرة تجارية» — واحتفظوا بالصياغة نفسها في نظامكم.

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

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

بقلم فريق ChariPay.

اقرؤوا بعده

دليل4 دقائق قراءة

مطابقة تحصيلاتكم مع محاسبتكم

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

دليل11 دقيقة قراءة

التحصيل على Shopify في المغرب

متجر Shopify وزبناء مغاربة: اقبلوا البطاقة مع ‎3-D Secure والنقد في الوكالة بالدرهم، عبر رابط الدفع ثم صفحة الدفع عبر API، خطوة بخطوة، بلا أي إضافة.

مستعدون للتجربة بأنفسكم؟

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

  • مجاني ودون التزام
  • وضع الاختبار منذ التسجيل
  • لا موافقة تنتظرونها