كل المقالات
Deep diveمدة القراءة 7 دقائق

يمكن لتطبيقك عرض ورقة طلب استرداد داخل التطبيق، وإليك ما تفعله Apple بعد أن ينقر العميل على إرسال

يتيح طلب الاسترداد داخل التطبيق من Apple للعميل أن يطلب استردادًا دون مغادرة تطبيقك، على ورقة تبنيها Apple وتراجعها. إليك ما يعيده beginRefundRequest، وساعات CONSUMPTION_REQUEST و48 ساعة التي يبدأها على خادمك، وما إذا كان الزر يستحق الإطلاق.

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

أهم الخلاصات

  • إن beginRefundRequest من Apple هو طريقة في StoreKit 2 تعرض ورقة الاسترداد الخاصة بـApple داخل تطبيقك. يرى العميل تفاصيل شرائه وقائمة برموز الأسباب، يختار واحدًا، فيذهب الطلب إلى Apple. أنت لا تبني النموذج ولا تقرر النتيجة.
  • يعيد الاستدعاء حالة success أو userCancelled، أو يرمي duplicateRequest أو failed. حالة success تعني أن App Store استلم الطلب، لا أنه وافق عليه. لا تعرض أبدًا استردادًا مؤكدًا في واجهتك عند success.
  • بعد أن يرسل العميل، تأخذ Apple حتى 48 ساعة للموافقة أو الرفض. وبالنسبة للمشتريات القابلة للاستهلاك، ترسل أولًا CONSUMPTION_REQUEST إلى خادمك، ولديك الـ12 ساعة المعتادة للرد ببيانات الاستخدام إذا وافق العميل.
  • تصل النتيجة إلى خادمك بوصفها App Store Server Notification، وهو نفس التدفق الذي تستقبله بالفعل. الموافقة إشعار REFUND، والرفض REFUND_DECLINED. يُوجَّه الطلب داخل التطبيق إلى ذلك التدفق تمامًا كأي استرداد بُدئ على صفحة reportaproblem من Apple.
  • الزر متاح ابتداءً من iOS 15 وiPadOS 15، وMac Catalyst 15، وvisionOS 1، لذا يمكن لأي تطبيق يستهدف تلك الإصدارات عرضه اليوم.
  • الحجة المالية هي أن استردادًا يمكنك الطعن فيه أفضل من chargeback لا يمكنك الطعن فيه. إبقاء العميل داخل مسار Apple يطلق CONSUMPTION_REQUEST يمكنك الرد عليه بدلًا من chargeback مصرفي نهائي ويحمل رسمًا.
  • توجيه Apple بشأن الموضع هو استدعاؤه من إعدادات الحساب أو قائمة المساعدة، لا من شاشة شراء، حتى يجده العميل غير الراضي دون أن تُعلن الاستردادات لسائر العملاء.

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

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

ما هي حقًا ورقة طلب الاسترداد داخل التطبيق

إن beginRefundRequest هو طريقة في StoreKit 2 تعرض ورقة طلب الاسترداد لمعاملة في مشهد نافذة. التوقيع قصير: func beginRefundRequest(in scene: UIWindowScene) async throws -> Transaction.RefundRequestStatus. عندما تستدعيه، يعرض النظام ورقة تحمل تفاصيل شراء العميل وقائمة برموز الأسباب ليختار منها. تبني Apple تلك الواجهة وتتحكم بها. أنت تمرر المشهد والمعاملة، لا غير.

توجيه Apple بشأن أين تضعه صريح. استدعِ هذه الوظيفة من إعدادات الحساب أو قائمة المساعدة، حتى يجدها العميل الذي يريد استردادًا حيث يبحث عن الدعم. صدرت في iOS 15 وiPadOS 15، وMac Catalyst 15، وvisionOS 1، لذا يمكن لأي تطبيق يستهدف تلك الإصدارات عرضها اليوم.

طريقتان لفتح الورقة

هناك نقطتا دخول. يمكنك استدعاء beginRefundRequest(in:) على معاملة محددة تمسكها بالفعل، وهذا يقصر الورقة على ذلك الشراء وحده. ويمكنك أيضًا فتح الورقة عبر معرّف المنتج حين تريد أن يسترد العميل شراء منتج معين. في الحالتين، الورقة وقائمة الأسباب والقرار كلها ملك لـApple. تنتهي مهمتك عند عرضها وقراءة النتيجة.

ما الذي يعيده الاستدعاء، وما الذي يمكن أن يخطئ

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

النتيجةالنوعماذا تعني
successRefundRequestStatusاستلم App Store طلب الاسترداد. تم إرساله، لا الموافقة عليه
userCancelledRefundRequestStatusأغلق العميل الورقة دون إرسال. لم يُرسَل شيء
duplicateRequestRefundRequestErrorلدى App Store بالفعل طلب استرداد لهذا الشراء
failedRefundRequestErrorفشل الإرسال نفسه. دع العميل يحاول مجددًا

ماذا يحدث على خادمك بعد أن ينقر العميل على إرسال

إغلاق الورقة هو بداية العملية لا نهايتها. تراجع Apple الطلب وتأخذ حتى 48 ساعة للموافقة أو الرفض. وبالنسبة لشراء قابل للاستهلاك داخل التطبيق، قبل أن تقرر، يرسل App Store إشعار CONSUMPTION_REQUEST إلى خادمك طالبًا بيانات الاستخدام. إذا وافق العميل على مشاركة تلك البيانات، ترد عبر نقطة النهاية Send Consumption Information. وإذا لم يوافق، فتعليمات Apple نفسها هي ألا ترد على الإشعار مطلقًا.

بمجرد أن تحكم Apple، تحطّ النتيجة على خادمك بوصفها App Store Server Notification. هذا هو نفس التدفق الذي تستقبله بالفعل، ويُوجَّه الطلب داخل التطبيق إليه تمامًا كاسترداد يبدؤه عميل على صفحة reportaproblem من Apple. لا يتغير شيء في المعالجة لمجرد أن الطلب بدأ داخل تطبيقك.

المرحلةما الذي يُطلَقتحرّككالساعة
العميل يرسل الورقةbeginRefundRequest يعيد successسجّله، اعرض قيد الانتظار لا تم الاستردادفوري
القابل للاستهلاك فقط، Apple تسأل أولًاإشعار CONSUMPTION_REQUESTأرسل بيانات الاستهلاك إن وافق العميل، وإلا فالتزم الصمت12 ساعة للرد
Apple توافقإشعار REFUNDاسحب صلاحية الوصول لتلك المعاملةحتى 48 ساعة للقرار
Apple ترفضإشعار REFUND_DECLINEDاحتفظ بالبيع، لا تغيّر شيئًاحتى 48 ساعة للقرار
An hourglass beside a smartphone and a paper receipt, illustrating the up-to-48-hour wait after a customer submits an in-app refund request to Apple

ما الذي يكلفك إياه الزر، وما الذي يمكن أن يوفره

استرداد يمكنك الطعن فيه أفضل من chargeback لا يمكنك

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

أنت تخفض الاحتكاك على الاسترداد

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

الكلفة التي تجري طوال الوقت هي خدمة حساب مسترَد

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

هل ينبغي أن تطلق طلب الاسترداد داخل التطبيق

ضعه حيث يعيش الدعم، لا حيث تعيش المبيعات

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

اختبر المسار كاملًا في بيئة الاختبار قبل أن تثق به

يمكنك محاكاة المسار بأكمله في بيئة الاختبار وفي اختبار StoreKit داخل Xcode، ناقلًا طلبًا من قيد الانتظار إلى موافَق عليه أو مرفوض. الموافقة تسلّم إشعار REFUND إلى خادمك، والرفض يسلّم REFUND_DECLINED، فتستطيع إثبات أن معالجك يتفاعل بشكل صحيح قبل أن ينقر عميل حقيقي على إرسال إطلاقًا.

تعامل مع كل نتيجة، ولا تبالغ أبدًا

اعرض قيد الانتظار عند success، وقدّم إعادة محاولة عند failed، وقل إن شيئًا لم يتغير عند userCancelled، وعامل duplicateRequest بوصفه ملاحظة هادئة بأن طلب العميل الأسبق لا يزال قائمًا. الخطأ الوحيد الذي يضر هو إخبار العميل بأن استرداده قد تم بينما كل ما تملكه طلب مُرسَل.

كيف تتعامل RefundHalt مع ما بعد ذلك

الورقة داخل التطبيق ملك لـApple. ما يأتي بعدها ملك لك، وهذا هو الجزء الذي تديره RefundHalt. حين يرسل عميل استردادًا من داخل تطبيقك، تلتقط RefundHalt الـCONSUMPTION_REQUEST للمشتريات القابلة للاستهلاك وترد عليه ضمن نافذة الـ12 ساعة بأدلة الاستخدام التي تساعد Apple على القرار. وحين تحكم Apple، تسحب الوصول عند REFUND وتُبقي الوصول دون مساس عند REFUND_DECLINED، وكل منها مرتبط بالمعاملة بعينها. تحصل على فرصة تقديم مسار الاسترداد داخل التطبيق الأكثر ودًّا دون أن تترك المراجعة أو الأدلة أو السحب لتخبّط يدوي.

الأسئلة الشائعة

ماذا يفعل beginRefundRequest؟
يعرض ورقة طلب الاسترداد من Apple داخل تطبيقك لمعاملة محددة. يرى العميل تفاصيل شرائه وقائمة برموز الأسباب، يختار واحدًا، فيذهب الطلب إلى Apple. تعيد الطريقة حالة success أو userCancelled، أو ترمي duplicateRequest أو failed. وهي لا تسترد الشراء نفسه، لأن Apple تراجع الطلب وتأخذ حتى 48 ساعة لتقرر.
هل يسترد طلب الاسترداد داخل التطبيق المال فورًا؟
لا. نتيجة success تعني أن App Store استلم الطلب، لا أنه وافق عليه. تأخذ Apple حتى 48 ساعة للموافقة أو الرفض، وبالنسبة للقابل للاستهلاك تطلب أولًا من خادمك بيانات الاستخدام عبر إشعار CONSUMPTION_REQUEST. اعرض للعميل حالة قيد الانتظار عند success، لا استردادًا مؤكدًا أبدًا.
أي إصدار من iOS يدعم طلب الاسترداد داخل التطبيق؟
iOS 15 وiPadOS 15، وMac Catalyst 15، وvisionOS 1. طريقة StoreKit 2 المسماة beginRefundRequest(in:) متاحة ابتداءً من تلك الإصدارات، فيمكن لأي تطبيق يستهدف iOS 15 أو أحدث أن يعرض ورقة الاسترداد من Apple من داخل التطبيق.
أين ينبغي أن أضع زر الاسترداد داخل التطبيق؟
توجيه Apple هو استدعاؤه من إعدادات الحساب أو قائمة المساعدة، لا من شاشة شراء أو جدار دفع. هذا يضع مسار الاسترداد حيث يبحث العميل غير الراضي عن الدعم، دون أن تُعلن الاستردادات لعملاء لم يكونوا سيطلبونها.
هل الاسترداد داخل التطبيق أفضل من اتصال العميل بمصرفه؟
عادةً نعم، لإيراداتك. إن chargeback المصرف نهائي ويحمل رسمًا، وهو يزيل كلًّا من Apple وأنت من القرار. أما طلب الاسترداد داخل التطبيق فيبقي العميل في مسار Apple، حيث يطلق شراء قابل للاستهلاك CONSUMPTION_REQUEST يمكنك الرد عليه ومراجعة يمكنك التأثير فيها. استرداد يمكن الطعن فيه أفضل من chargeback لا يمكن الطعن فيه.

المصادر وقراءات إضافية

RefundHalt

الطيار الآلي للاستردادات في App Store وGoogle Play

تابع القراءة

طلب الاسترداد التالي في طريقه إليك بالفعل.

أعد RefundHalt في الوقت الذي تستغرقه لقراءة رسالة دعم أخرى عن استرداد لم تتمكن من الاعتراض عليه.