إذا سبق لك العمل مع آلية استرداد الأموال في Apple، فمن المرجّح أنك صادفت الإشارة إلى نافذة الاستجابة التي مدتها 12 ساعة في التوثيق. لكن ما لا يوضحه التوثيق دائمًا هو كيفية الرد فعليًا.
CONSUMPTION_REQUEST هو إشعار؛ أما الرد فهو استدعاء لواجهة برمجة تطبيقات مختلفة، لها مفتاحها الخاص ونص طلب تغيّر شكله مرتين منذ عام 2021. تناولنا من قبل ما يحتويه الإشعار نفسه في مقال سابق. وهذا المقال هو الجزء الذي يليه، حين يتعين عليك فعليًا الرد عليه.
أبرز النقاط
الأمر لا يعدو كونه طلب PUT واحدًا إلى App Store Server API. هذه هي الآلية بأكملها.
يُوقَّع كل طلب برمز JWT من مفتاح مشترياتك داخل التطبيق؛ وتُرفض الرموز التي يتجاوز عمرها 60 دقيقة.
يحتوي نص الإصدار الثاني (v2) على خمسة حقول، ثلاثة منها مطلوبة.
تردّ Apple برمز 202 ولا شيء غير ذلك. ويصل قرار الاسترداد لاحقًا في صورة إشعار منفصل.
اثنتا عشرة ساعة من لحظة وصول الإشعار، ويمكنك إعادة الإرسال ضمن هذه النافذة.
ما هو طلب الاستهلاك من Apple؟
طلب الاستهلاك من Apple هو، بعيدًا عن المصطلحات التقنية، سؤال بسيط. فقد طلب أحد العملاء من Apple استرداد أمواله، وقبل أن تردّ عليه Apple، تتوجه إلى خادمك بسؤال: هل حصل هذا الشخص على ما دفع مقابله، وهل استخدمه؟
تدمج Apple ما تقوله مع معطيات تعرفها بالفعل، مثل عدد المرات التي يطلب فيها هذا العميل استرداد أمواله، ثم تتخذ قرارها بنفسها.
يخطئ الناس باستمرار في فهم هذه النقطة الأخيرة. فأنت لا توافق على شيء ولا ترفضه؛ أنت فقط تقدّم الحقائق.
يصل إشعار CONSUMPTION_REQUEST الذي ترسله Apple إلى عنوان URL الخاص بالخادم الذي أدخلته في App Store Connect، في صورة إشعار خادم من الإصدار الثاني.
في عام 2021 كان يُطلق فقط للمنتجات الاستهلاكية (consumables). ثم أُضيفت الاشتراكات في عام 2024، وفي ديسمبر 2025 نشرت Apple الإصدار الثاني من نقطة النهاية، الذي يذكر توثيقه أنه يغطي كل أنواع المنتجات، بما في ذلك المنتجات غير الاستهلاكية والاشتراكات غير المتجددة. ولا تزال صفحة مرجع الإشعارات تسرد النوعين الأصليين فقط؛ وأنا أثق في الصفحة الأحدث وأبني الحل ليشمل الأنواع الأربعة كلها.
وبما أنني أتطرق إلى التسمية: يبحث كثيرون عن "Apple refund API" ولا وجود لواجهة برمجة تطبيقات بهذا الاسم كعنصر منفصل. فهذا الاستدعاء هو جزء من App Store Server API.
ما تحتاج إليه قبل أن تتمكن من الإرسال
ثلاثة من هذه العناصر الأربعة لا يمكن استعجالها، لذا اقرأ هذا الجزء قبل طلبك الأول لا بعده.
العنصر الأول هو مفتاح، وتحديدًا مفتاح مشتريات داخل التطبيق، يُنشأ في App Store Connect ضمن قسم Users and Access. تمنحك Apple ملف .p8 مرة واحدة فقط؛ وستحتاج أيضًا إلى معرّف المفتاح (key ID) ومعرّف المُصدِر (issuer ID) الخاص بك.
ثانيًا، تحتاج إلى وسيلة للانتقال من معرّف المعاملة (transaction ID) الذي تمنحك إياه Apple إلى شخص محدد في قاعدة بياناتك، وهو ما تحتاجه فعليًا. والطريقة الأنظف هي appAccountToken، الذي يُضبط عند الشراء، ثم يعود في كل إشعار متعلق بتلك المعاملة.
إذا كان هذا المصطلح جديدًا عليك، فاقرأ أولًا لماذا يُعد appAccountToken مهمًا للدفاع عن طلبات الاسترداد، لأنه بدون هذا الربط يصبح بقية هذا المقال نظريًا بحتًا.
ثالثًا، وهذا هو العنصر الذي لا يمكن إصلاحه في الساعة الثانية صباحًا: الموافقة (consent).
ينص توثيق Apple بوضوح على أنه إذا لم يوافق العميل على مشاركتك لهذه البيانات، فلا يجب عليك الرد إطلاقًا. كما يذكر التوثيق، بلغة قانونية أكثر، أن ما يُعد موافقة صالحة يعتمد على المكان الذي تعمل فيه، وأنهم لا يستطيعون تقديم المشورة لك في هذا الشأن.
الطريقة المعتادة هي إدراج صياغة موافقة صريحة (opt-in) في شروطك، ويجب أن تكون موجودة قبل وصول الطلب.
أما العنصر الرابع فهو معرّف المعاملة نفسه، الذي لا تحصل عليه إلا بعد وصول الإشعار والتحقق من توقيع Apple.
كيفية إرسال معلومات الاستهلاك خطوة بخطوة
معظم من يبحثون عن "send consumption information apple" ينتهي بهم المطاف إلى صفحة مرجع Apple، التي تسرد الحقول ثم تتوقف فجأة دون مزيد من الشرح. وفيما يلي التسلسل العملي للخطوات.
ابدأ بالتحقق من أن الإشعار حقيقي. حمولة signedPayload هي JWS؛ وتتحقق منها مكتبة App Store Server Library الخاصة بـ Apple، ثم تعيد المعاملة بعد فك ترميزها، بما في ذلك transactionId وappAccountToken.
ابحث عن عملية الشراء في نظامك. ما تحتاج إلى معرفته: هل سلّمنا المنتج فعلًا، وما هي النسبة التقريبية التي استُخدمت منه، وهل رأى العميل عيّنة أو نسخة تجريبية مسبقًا، وماذا نفضّل أن تفعله Apple.
والآن الرمز (token). في الترويسة (Header): alg يساوي ES256، وkid هو معرّف مفتاحك، وtyp هو JWT. وفي الحمولة (Payload): iss هو معرّف المُصدِر الخاص بك، وiat هو الوقت الحالي، وexp لا يتجاوز 60 دقيقة بعده، وaud هو السلسلة الحرفية appstoreconnect-v1، وbid هو معرّف الحزمة (bundle ID) الخاص بك. يوضح دليل Apple حول إنشاء رموز JSON Web Tokens التنسيق الدقيق، رغم أن المكتبة تتولى بناء هذا من أجلك.
أرسل طلب PUT. عنوان URL الخاص بالإنتاج هو https://api.storekit.apple.com/inApps/v2/transactions/consumption/{transactionId}، مع وضع رمز JWT كرمز Bearer في ترويسة Authorization، ونص طلب على النحو التالي:
{
"customerConsented": true,
"deliveryStatus": "DELIVERED",
"consumptionPercentage": 94000,
"sampleContentProvided": false,
"refundPreference": "DECLINE"
}
تردّ Apple برمز 202 Accepted، وهذا كل ما تحصل عليه. سجّل الوقت ونص الطلب ومعرّف المعاملة، لأنه بعد شهر سيسأل أحدهم عمّا أخبرنا به Apple بشأن هذه الحالة.
ثم تنتظر. يصل القرار في صورة إشعار REFUND أو REFUND_DECLINED. وإذا كان القرار REFUND، فاسحب المحتوى أو الصلاحية في اليوم نفسه.
إذن إذا كنت تتساءل كيف ترسل معلومات استهلاك ستستخدمها Apple فعليًا، فهذا هو الجواب: طلب واحد، وخمسة حقول، ضمن النافذة الزمنية.
تتيح لك Apple أيضًا إرسال نسخة محدّثة من البيانات خلال تلك الساعات الـ12، لذا إذا خرج الاستدعاء الأول بصورة ناقصة، أرسل استدعاءً ثانيًا.
هناك بعض الأمور التي لا توضحها أسماء الحقول. فحقل consumptionPercentage يُقاس بوحدات الألفية (milliunits)، وهو ما يُوقع الناس في الخطأ: فالقيمة 94000 تعني 94 بالمئة، و100000 تعني الكل، ويجب أن تكون القيمة 0 إذا كانت deliveryStatus أي شيء غير DELIVERED.
خيارات عدم التسليم هي UNDELIVERED_QUALITY_ISSUE وUNDELIVERED_WRONG_ITEM وUNDELIVERED_SERVER_OUTAGE وUNDELIVERED_OTHER.
حقل refundPreference اختياري ويقبل القيم GRANT_FULL أو GRANT_PRORATED أو DECLINE؛ وفي حالة GRANT_PRORATED لاشتراك متجدد تلقائيًا، اترك النسبة المئوية فارغة وستحسبها Apple بناءً على الوقت المتبقي.
تحتوي صفحة مرجع Send Consumption Information على القائمة الكاملة للأخطاء.
ماذا تعني رموز الاستجابة
هناك استجابة جيدة واحدة فقط، وهي 202. أما كل ما عداها فهو طريقة Apple لإخبارك بما أخطأت فيه، وغالبًا باسمه الصريح.
رموز الفئة 400 هي الأكثر فائدة، لأن نص الاستجابة يسمي الخطأ بوضوح.
خطأ ConsumptionPercentageOutOfRangeError يعني في الغالب أن أحدهم أرسل 94 بدلًا من 94000.
خطأ UndeliveredConsumptionPercentageNonZeroError يعني أنك ذكرت أن العنصر لم يصل إطلاقًا، ثم ادّعيت أنه استُخدم جزئيًا.
خطأ InvalidCustomerConsentedError واضح بذاته.
رمز 401 يتعلق بالرمز المميز (token): مفتاح خاطئ، أو انتهاء صلاحية يتجاوز الساعة، أو معرّف حزمة لا يتطابق، أو ساعة خادم انحرفت بما يكفي لتجعل iat يبدو وكأنه في المستقبل.
رمز 404 يعني أن معرّف المعاملة لم يُعثر عليه، وسؤالي الأول دائمًا هو هل ذهبت معاملة من بيئة الاختبار (sandbox) إلى عنوان URL الخاص بالإنتاج، أو العكس.
رمز 429 هو حد معدل الطلبات (50 طلبًا في الثانية لكل تطبيق في بيئة الإنتاج، وعُشر هذا العدد في بيئة الاختبار)؛ اقرأ ترويسة Retry-After قبل إعادة المحاولة.
رمز 500 يعني أن المشكلة من جانب Apple؛ أعد المحاولة لاحقًا.
كيفية اختباره في بيئة Sandbox
اختبار هذا الأمر أسهل مما يبدو، مع وجود نقطة واحدة يجب الانتباه إليها.
ضع عنوان URL لخادم بيئة الاختبار في App Store Connect، وسجّل الدخول بحساب Apple Account خاص ببيئة الاختبار، واشترِ شيئًا، ثم افتح واجهة الاسترداد في تطبيقك (beginRefundRequest) وأرسل طلبًا.
يشرح دليل Apple لاختبار طلبات الاسترداد كيفية تصرف بيئة الاختبار: اختر أي سبب وسيُوافَق على الاسترداد تلقائيًا؛ اختر Other واكتب DECLINE وسيُرفض؛ واكتب GRANT_PRORATED للحصول على استرداد نسبي.
والنقطة الدقيقة في هذه القواعد هي أن بيئة الاختبار تقرر بناءً على ما كتبته في الواجهة، لا بناءً على ما أرسله خادمك، لذا لا يمكنها إخبارك ما إذا كانت بياناتك تقنع Apple بشيء.
ما يمكنها اختباره هو البنية التقنية: وصول الإشعار، وعودة طلب PUT الذي ترسله إلى api.storekit-sandbox.apple.com برمز 202، ومعالجة REFUND أو REFUND_DECLINED عند وصوله.
كذلك، لا ترسل بيئة الاختبار رسائل بريد إلكتروني خاصة بالاسترداد، لذا لا تنتظر وصول أي منها.
أتمتة استرداد أموال Apple: متى تتوقف عن القيام بذلك يدويًا
عند القيام بهذه المهمة يدويًا، فإنها تعني أن شخصًا ما يراقب التنبيهات في كل الأوقات، ويشغّل استعلامًا، ويرسل الحقول الخمسة قبل انتهاء ساعة الـ12 ساعة.
هذا مقبول عندما يكون لديك عدد قليل من طلبات استرداد أموال Apple شهريًا. لكنه يصبح أقل قبولًا بكثير في أول عطلة نهاية أسبوع طويلة لا يراقب فيها أحد.
لأتمتة طلبات استرداد أموال Apple، تأخذ كل ما سبق وتزيل الشخص من المعادلة: يصل الإشعار، وتحوّل قواعدك بيانات التسليم والاستخدام إلى حمولة بيانات، ويخرج الاستدعاء في غضون دقائق، ويُسجَّل القرار مقابل الحالة، ويؤدي REFUND إلى إلغاء الصلاحية.
بناء هذا النظام ليس مشروعًا ضخمًا؛ لكن مواكبة تغييرات Apple بعد ذلك (مثل الانتقال من الإصدار الأول إلى الإصدار الثاني) هو الجزء الذي يستمر في التكلفة بهدوء.
وإذا كنت تفضّل عدم القيام بذلك، فقد استعرضنا الخدمات المصممة لهذا الغرض في مقارنتنا لأدوات إدارة استرداد أموال Apple، بما في ذلك أين يناسب Refund Sensor وأين لا يناسب.
ثمة أمر أود توضيحه كلما طُرح الموضوع: أتمتة استرداد أموال Apple تغيّر مدى موثوقية ردك، لا من يتخذ القرار. فلا شيء في هذه الواجهة البرمجية يمنح المطوّر الكلمة الفصل.
الخاتمة
الاستدعاء نفسه بسيط: رمز موقّع، وطلب PUT واحد، وخمسة حقول، ورمز 202 يُسجَّل.
أما ما يحدد النجاح من الفشل فيحدث في مكان آخر: في الموافقة التي باتت مدرجة بالفعل في شروطك، وappAccountToken في كل عملية شراء، وسجلات استخدام يمكنك استدعاؤها خلال ثوانٍ، وشيء يستيقظ في الساعة الثالثة صباحًا عندما يستيقظ الإشعار.
رتّب هذه العناصر، وسيتوقف الأمر عن كونه فوضى عشوائية ويصبح شيئًا يقوم به خادمك ببساطة.
الأسئلة الشائعة
هي نقطة نهاية في App Store Server API تُستخدم للرد على إشعار CONSUMPTION_REQUEST. ترسل طلب PUT يتضمن تفاصيل الاستهلاك، وتردّ Apple برمز الاستجابة 202 Accepted.
لديك 12 ساعة من وقت وصول إشعار CONSUMPTION_REQUEST. تسمح Apple بإرسال نسخة محدّثة من البيانات ضمن نافذة الـ12 ساعة نفسها.
نعم. تسمح لك Apple بإرسال نسخة محدّثة من البيانات ضمن نافذة الـ12 ساعة. هذا مفيد عندما تكون الإرسالة الأولى غير مكتملة.
لا. الاستجابة 202 Accepted تعني فقط أن Apple استلمت معلوماتك. تصل النتيجة لاحقًا في صورة إشعار REFUND أو REFUND_DECLINED.
نعم. حقل customerConsented مطلوب عند إرسال معلومات الاستهلاك. وإذا لم يوافق العميل، فإن توثيق Apple ينص على عدم الرد.



