كل عملية استرداد على App Store هي قرار Apple وحدها، لكن Apple تفضّل ألا تتخذه دون معرفة كافية. يؤدي طلب الاسترداد إلى إيقاف العملية مؤقتًا، وتوجيه سؤال إلى خادمك (server)، وفتح فترة زمنية محددة لك للرد بحقائق حول عملية الشراء. ارد بشكل موضوعي وسترفض المطالبات غير المعقولة. التزم الصمت وستكون رواية العميل وحدها هي ما تسمعه Apple.
أبرز النقاط
تؤدي طلبات الاسترداد على App Store إلى إرسال Apple إشعار CONSUMPTION_REQUEST إلى خادمك، ثم الانتظار لمدة تصل إلى 12 ساعة بحثًا عن أدلة قبل إصدار القرار.
الرد يعني استدعاء نقطة النهاية Send Consumption Information بحمولة بيانات (payload) مختصرة: الموافقة، وحالة التسليم، وما إذا كانت هناك نسخة تجريبية، ومقدار ما تم استهلاكه، والنتيجة التي تريدها.
عدم إرسال أي شيء هو رد بحد ذاته. تمضي Apple قدمًا معتمدة فقط على ما أكده العميل إلى جانب سجل حسابه.
تعمل الموافقة كبوابة صارمة. توثيق Apple صريح في أنه يجب عدم الرد إطلاقًا في حال لم يوافق العميل على مشاركة بيانات استهلاكه.
تحسب Apple نسبة الاستهلاك للاشتراكات المتجددة تلقائيًا بناءً على الوقت المنقضي، وتقديم رقم خاص بك يؤدي إلى حدوث خطأ.
لا تتسع هذه النافذة الزمنية لأي عملية يدوية. المطورون الذين يستفيدون من هذا هم أولئك الذين يُجمَّع ردهم ويُقدَّم تلقائيًا.
تبدأ كل عملية استرداد على App Store بالطريقة نفسها: يزور شخص ما reportaproblem.apple.com، ويختار عملية شراء، ويحدد سببًا.
الإشعار الذي يبقى بلا رد في أغلب الأحيان
تتلقى التطبيقات المُهيأة لاستخدام App Store Server Notifications V2 إشعار CONSUMPTION_REQUEST فور طلب الاسترداد. وتتضمن هذه الحمولة (payload) المعاملة، والمنتج، ومنذ عام 2024، السبب الذي اختاره العميل: UNINTENDED_PURCHASE، أو FULFILLMENT_ISSUE، أو UNSATISFIED_WITH_PURCHASE، أو LEGAL، أو OTHER.
تبدأ من هذه اللحظة فترة 12 ساعة، يمكنك خلالها استدعاء نقطة النهاية Send Consumption Information وتسجيل روايتك رسميًا. وما تطلبه نقطة النهاية هذه مُصمَّم ليكون محدودًا عمدًا: خمسة حقول لا تحمل سوى مؤشرات (flags) وأرقام.
customerConsented يخبر Apple ما إذا كان العميل قد وافق على مشاركة بيانات استخدامه. والقيمة المعتادة هي true.
deliveryStatus يخبر Apple ما إذا كانت عملية الشراء قد وصلت وعملت بشكل صحيح. والقيمة المعتادة هي DELIVERED.
sampleContentProvided يخبر Apple ما إذا كانت هناك نسخة مجانية أو تجريبية متاحة مسبقًا. والقيمة المعتادة هي true.
consumptionPercentage يخبر Apple بالنسبة المُستهلكة، معبّرًا عنها بوحدات الألف (milliunits) حيث تعني القيمة 100000 نسبة 100 بالمئة. والقيمة المعتادة هي 67500.
refundPreference يخبر Apple بالنتيجة التي تفضلها، سواء كانت الموافقة أو الرفض أو عدم وجود تفضيل. والقيمة المعتادة هي DECLINE.
يقتصر نطاق consumptionPercentage على: المنتجات الاستهلاكية (consumables)، والمشتريات لمرة واحدة، والاشتراكات غير المتجددة. أما الاشتراكات المتجددة تلقائيًا فتحسبها Apple بناءً على الوقت المنقضي ضمن فترة الفوترة، وتُرفض أي قيمة تقدمها بنفسك.
ماذا تفعل Apple بما ترسله
تستخدم Apple معلومات الاستهلاك، بشكل صريح، كمُدخل يؤثر في كيفية حسم الاسترداد. لا ترسل شيئًا وسيأتي القرار بالاعتماد فقط على ما أكده العميل إلى جانب سجل حسابه. أرسل الأدلة وستُرفض طلبات الاسترداد المتنازع عليها بتكرار ملحوظ فعليًا.
بناء مسار الرد بنفسك، من البداية إلى النهاية
لا شيء في هذا التسلسل سرّي. لكن كل جزء منه يحتاج إلى العمل دون إشراف في الساعة الثالثة صباحًا.
1. تفعيل وصول الإشعارات
افتح صفحة App Information الخاصة بتطبيقك داخل App Store Connect، واضبط Production Server URL ضمن قسم App Store Server Notifications، مع اختيار Version 2. فطلبات الاستهلاك (consumption requests) لا تُرسَل عبر V1. وبعدها تصل كل الإشعارات، بما فيها إشعارات الاسترداد، إلى ذلك العنوان عبر طلب POST كحمولة JWS موقّعة.
2. إنشاء المفتاح الصحيح
تعتمد مصادقة الردود على مفتاح In-App Purchase، الذي يُنشأ ضمن قسم Users and Access في Integrations. وهو نوع مفتاح مختلف تمامًا، ولن يصادق مفتاح App Store Connect API الموجود بجانبه على هذه الاستدعاءات. ويُنزَّل ملف .p8 مرة واحدة بالضبط، وبعدها تُنشئ رمز JWT من نوع ES256 قصير المدة لكل طلب.
3. التحقق، والمطابقة، ثم اتخاذ القرار
تحتاج إشعارات CONSUMPTION_REQUEST الواردة إلى التحقق من سلسلة توقيع JWS الخاصة بها مقابل شهادات الجذر (root certificates) الخاصة بـ Apple قبل أن تثق بأي جزء من محتواها. بعد ذلك، اربط المعاملة بمستخدم معين، ويُفضَّل أن يكون ذلك عبر أي قيمة appAccountToken (UUID) أرفقتها أثناء الشراء، واسترجع استخدامه الحقيقي. ثم استقر على تفضيل: تنازل في الحالات التي تستدعي حسن النية، ونازع في الحالات التي استُهلك فيها المنتج بوضوح.
4. تقديم الرد قبل إغلاق النافذة الزمنية
أرسل هذه الحقول الخمسة بطلب PUT إلى نقطة النهاية Send Consumption Information مقابل معرّف تلك المعاملة (transaction id)، خلال فترة الـ12 ساعة. وهناك خطآن يقع فيهما الجميع تقريبًا: تحكم وحدات الألف (milliunits) في النسبة المئوية، لذا فإن 100% تعني 100000 وليس مليونًا. والموافقة تمثل بوابة لكل شيء، لأن توثيق Apple نفسه ينص على وجوب عدم الرد إطلاقًا في غياب موافقة العميل. لذا أدرج صياغة هذه الموافقة في شروط الخدمة (terms of service) الخاصة بك قبل إطلاق أي من هذا.
لماذا يخسر هذا العدد الكبير من المطورين
نصف يوم هو مهلة قاسية لأي عملية تُدار يدويًا. فالإشعارات تصل في الساعة 3 صباحًا أيام السبت. وما تتطلبه هو خادم قادر على التحقق من سلسلة توقيع JWS الخاصة بـ Apple، وربط المعاملة بمستخدم، وحساب نسبة الاستهلاك بوحدات الألف (milliunits)، واستدعاء واجهة برمجية (API) مصادق عليها عبر JWT. لكل طلب على حدة. وإلى أجل غير مسمى.
عمليًا، تسير قائمة المهام كما يلي:
إعداد App Store Server Notifications V2، فبدونها لن يصلك الطلب إطلاقًا.
التحقق من الحمولة الموقّعة مقابل سلسلة شهادات Apple قبل منحها أي ثقة.
ربط المعاملة بمستخدم في نظامك الخاص، عادةً عبر appAccountToken المُرفق وقت الشراء.
استنتاج نسبة الاستهلاك من بيانات الاستخدام الفعلية المسجلة بدلًا من التقدير.
استدعاء Send Consumption Information باستخدام مفتاح In-App Purchase بينما لا تزال النافذة الزمنية مفتوحة.
يوجد Refund Sensor لتحمّل هذا العبء، حيث يقدّم ردًا كاملًا ومدعومًا بالأدلة ضمن الوقت المحدد بوضوح دون أن يضطر أحد للاستيقاظ.
أين يمكن الاطلاع على توثيق هذه القواعد
الأسئلة الشائعة
لا يزال قرار الاسترداد يُتخذ، لكن بناءً فقط على مطالبة العميل وسجل حسابه هذه المرة. ستفقد الفرصة الوحيدة المتاحة لإثبات أن عملية الشراء وصلت واستُخدمت على نطاق واسع. والطلبات التي لا تُجاب عليها تُقبل بشكل أكبر بكثير في الواقع العملي.
نعم، فعلاً. يجب أن تكون قيمة customerConsented هي true، ويجب أن تكون الموافقة وراء هذه العلامة حقيقية، وعادةً ما تُسجَّل في أي من مستنداتك القانونية التي تغطي مشاركة البيانات. وتوجّه إرشادات Apple نفسها المطورين إلى ترك الإشعار دون رد إطلاقًا في حال عدم وجود هذه الموافقة.
فقط للنوع غير المتجدد. أما الاشتراكات المتجددة تلقائيًا، فتحسب Apple الاستهلاك فيها بناءً على الوقت المنقضي داخل فترة الفوترة الحالية، وترفض الواجهة البرمجية (API) أي نسبة تقدمها أنت. ومع ذلك، تظل أفضليتك للاسترداد ذات وزن وتأثير.
مفتاح In-App Purchase، الذي يُنشأ في App Store Connect ضمن قسم Users and Access، في Integrations. وهذا يختلف عن مفتاح App Store Connect API، وملف .p8 الخاص به قابل للتنزيل مرة واحدة فقط، عند لحظة إنشائه.
تتيح بيئة الإنتاج (Production) 12 ساعة من وقت الإشعار. أما بيئة الاختبار (Sandbox) فلا تتيح سوى 5 دقائق فقط، وهو ما يُعد إشارة واضحة إلى ما تتوقعه Apple: الأتمتة لا شخصًا يقوم بالرد يدويًا.



