يمكن لتطبيقك عرض ورقة طلب استرداد داخل التطبيق، وإليك ما تفعله 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، لذا فهي إما تعيد حالة أو ترمي خطأً. كلاهما قائمتان قصيرتان، ويستحق التعامل معهما كلتيهما حتى تقول واجهتك شيئًا صحيحًا بعد إغلاق الورقة.
| النتيجة | النوع | ماذا تعني |
|---|---|---|
| success | RefundRequestStatus | استلم App Store طلب الاسترداد. تم إرساله، لا الموافقة عليه |
| userCancelled | RefundRequestStatus | أغلق العميل الورقة دون إرسال. لم يُرسَل شيء |
| duplicateRequest | RefundRequestError | لدى App Store بالفعل طلب استرداد لهذا الشراء |
| failed | RefundRequestError | فشل الإرسال نفسه. دع العميل يحاول مجددًا |
ماذا يحدث على خادمك بعد أن ينقر العميل على إرسال
إغلاق الورقة هو بداية العملية لا نهايتها. تراجع 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 ساعة للقرار |

ما الذي يكلفك إياه الزر، وما الذي يمكن أن يوفره
استرداد يمكنك الطعن فيه أفضل من 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 لا يمكن الطعن فيه.
المصادر وقراءات إضافية
- Apple Developer: beginRefundRequest(in:)
- Apple Developer: Transaction.RefundRequestStatus
- Apple Developer: Transaction.RefundRequestError
- Apple Developer: App Store Server Notifications V2 notificationType
- Apple Developer: Send Consumption Information
- Apple Developer: Support customers and handle refunds (WWDC21)
RefundHalt
الطيار الآلي للاستردادات في App Store وGoogle Play
تابع القراءة
عندما يُسترَد مبلغ عملية شراء على Google Play أو يحدث ردّ مبالغ، تكون Voided Purchases API هي الطريقة التي تعرف بها ذلك
يُبطِل Google Play عملية الشراء بهدوء عند استرداد مبلغها أو حدوث ردّ مبالغ. إن Voided Purchases API هي قائمة تلك الطلبات، حتى تتمكن من إلغاء الوصول. إليك كل حقل، ونافذة الثلاثين يومًا، وخيار الإلغاء الذي يُخفي الطلبات، وما يكلفه ذلك.
تصل ثلاثة إشعارات استرداد من App Store بعد أن يقرر Apple، وإشعار REFUND_REVERSED يعيد البيع إليك
يرسل Apple أربع رسائل استرداد عبر App Store Server Notifications V2، ومعظم التطبيقات تتعامل مع اثنتين فقط. إشعار REFUND يخبرك بإلغاء الوصول، وإشعار REFUND_DECLINED يعني احتفظ بالبيع، وإشعار REFUND_REVERSED يعيد البيع إليك ويطلب منك استعادة ما سحبته. إليك ما يتطلبه كل واحد منها.