Günümün büyük bir kısmını Undelivered Consumption Percentage Non Zero Error hatasına kaybettim. Çözülmesi zor bir hata olduğu için değil. deliveryStatus'u DELIVERED dışında bir değere ayarlamış ve consumptionPercentage'ı 60000'de bırakmış olduğum için - Apple bu kombinasyonu hiç çekinmeden reddediyor.
Bu da asıl soruya dolaylı bir giriş oldu.
Apple geri ödeme taleplerine otomatik olarak nasıl yanıt vereceğinizi çözmeye çalışıyorsanız, bu çoğu ekibin düşündüğünden daha küçük bir iştir. Zor kısım hiçbir zaman API çağrısı olmadı. Zor olan, o çağrıya koyacağınız veriye sahip olmak. Alan alan anlatım Apple CONSUMPTION_REQUEST açıklaması yazısında yer alıyor. Bu yazı ise kimsenin uyanık kalmasına gerek kalmayacak şekilde bunu kurmakla ilgili.
Önemli noktalar
Apple geri ödeme otomasyonu bir webhook ve bir PUT isteğinden ibarettir. Apple bir CONSUMPTION_REQUEST gönderir, siz 12 saat içinde yanıt verirsiniz.
App Store Connect API anahtarınız değil, bir In-App Purchase key'e ihtiyacınız var. Bunlar birbirinin yerine kullanılamaz.
Beş alanın üçü zorunludur ve bunlardan ikisinin kısıtlamaları yalnızca hata olarak ortaya çıkar.
Müşteri onayı olmadan hiç yanıt vermemelisiniz ve onayı geriye dönük olarak toplayamazsınız.
Uç nokta v2'ye taşındı. Üretim ortamı api.storekit.apple.com adresidir ve sandbox size 12 saat yerine 5 dakika verir.
Geliştiriciler için Apple geri ödeme talepleri gerçekte nasıl işler
Bir müşteri reportaproblem.apple.com adresini açar, son 90 gün içindeki satın alımı bulur, bir neden seçer ve gönderir. App Store Server Notifications V2'yi yapılandırmışsanız, uç noktanız; işlemi, ürünü ve seçtikleri nedeni taşıyan imzalı bir JWS payload'ı olarak bir CONSUMPTION_REQUEST alır.
Bu webhook, bir Apple Store uygulama içi satın alım geri ödemesinin tüm tetikleyicisidir. Dashboard'unuzda hiçbir şey görünmez ve kontrol edilecek bir kuyruk yoktur. Bu yüzden ekipler, bu sistemin varlığını, yüzünden para kaybetmeye başladıktan haftalar sonra fark eder.
Ardından 12 saatiniz vardır.
Düzeltilmesi gereken bir nokta var, çünkü her yerde tekrarlanıyor. Bu durum tüketilebilir (consumable) ürünlerle sınırlı değil. Apple'ın güncel dokümantasyonu, bir CONSUMPTION_REQUEST'in herhangi bir ürün türü için geldiğini belirtiyor: consumable, non-consumable, non-renewing subscription, auto-renewable subscription. Daha eski kılavuzlar hâlâ yalnızca consumable'lar ve abonelikler için geçerli olduğunu söylüyor. Bunlar güncelliğini kaybetmiş.
"Yanıt vermek" somut olarak ne anlama geliyor
Bir JSON gövdesini tek bir uç noktaya PUT edersiniz.
PUT https://api.storekit.apple.com/inApps/v2/transactions/consumption/{transactionId}
Sandbox adresi api.storekit-sandbox.apple.com'dur, aynı path. Başarılı bir istek 200 değil, 202 Accepted döner; bu da durum kodlarını kontrol eden kişilerin ayağını kaydırır.
Kimlik doğrulama, App Store Connect'te Users and Access altında, Integrations içinde oluşturulan bir In-App Purchase key ile imzalanmış, kısa ömürlü bir ES256 JWT'dir. Bu, App Store Connect API anahtarınız değildir. .p8 dosyası yalnızca oluşturulduğu anda, bir kez indirilir; dolayısıyla kaybederseniz yeni bir anahtar oluşturup onu kullanan her şeyi değiştirmeniz gerekir. Nereden bildiğimi sorun.
Beş alan ve ısıran iki tanesi
Gövde bir Consumption Request'tir. Üçü zorunlu, ikisi isteğe bağlı.
Customer Consented (zorunlu). Yalnızca gerçek bir onayınız varsa true olmalıdır. Aşağıda daha fazla bilgi var, çünkü bu alan her şeyin kapısını tutuyor.
Delivery Status (zorunlu). Satın alımın ulaşıp çalışıp çalışmadığı.
Sample Content Provided (zorunlu). Satın alımdan önce ücretsiz bir örnek, deneme veya işlevsellik bilgisi sunulup sunulmadığı.
Consumption Percentage (isteğe bağlı). Ne kadar tüketildiği, milliunit cinsinden. 0 ile 100000 arası, yani yüzde 45.2 değeri 45200'dür.
Refund Preference (isteğe bağlı). GRANT_FULL, GRANT_PRORATED, DECLINE veya NO_PREFERENCE.
Size her biri bir öğleden sonranızı alacak iki kısıtlama var.
Delivery Status, DELIVERED değilse, Consumption Percentage 0 olmalıdır. Başka herhangi bir değer Undelivered Consumption Percentage Non Zero Error ile başarısız olur. Günüm bu şekilde geçti.
Ve bir auto-renewable subscription için GRANT_PRORATED gönderiyorsanız, consumptionPercentage'ı hiç dahil etmeyin. Apple bunu, faturalandırma döneminde geçen süreden hesaplar ve sizinkini Consumption Percentage Auto Renewable Subscription Error ile reddeder. Hata adları en azından açıklayıcı, bu da beklediğimden fazlasıydı.
Onay bir kapıdır, bir formalite değil
Apple'ın dokümantasyonu burada alışılmadık şekilde doğrudan: müşteri onay vermemişse, bildirime yanıt vermeyin. Customer Consented'ı false olarak ayarlayıp yanıt vermeyin. Hiç yanıt vermeyin.
Bir talep geldikten sonra gidip onay toplayamazsınız da. Onay, önceden mevcut olmalıdır; bu da ilgili ifadelerin, bunların herhangi birini yayına almadan önce - ilk itirazlı geri ödemenizden sonra değil - kullanım şartlarınızda veya gizlilik politikanızda yer alması gerektiği anlamına gelir. Apple'ın yönergesi, onayın özgürce verilmiş, spesifik, bilgilendirilmiş ve açık olması gerektiğini, opt-in'in opt-out'tan daha iyi olduğunu ve bunu almanın tamamen sizin sorumluluğunuzda olduğunu belirtir.
Pratikte: geri ödeme taleplerinin incelenmesine yardımcı olmak için satın alım ve kullanım verilerini Apple ile paylaşabileceğinizi belirten bir cümle, bunun yanında geri çekme imkânı. Bunu kendi hukuk ekibinize kontrol ettirin. Ben avukat değilim ve bu bir tavsiye değildir.
Geliştiriciler App Store geri ödeme taleplerini nasıl otomatikleştirir
Kuracağım sırayla pipeline:
App Store Connect'te, App Information altında bir Production Server URL yapılandırın ve Version 2'yi seçin. Consumption talepleri V1 üzerinden gelmez.
Tek bir alana bile güvenmeden önce JWS imza zincirini Apple'ın kök sertifikalarına karşı doğrulayın.
İşlemi bir kullanıcıyla eşleştirin. Satın alım sırasında eklediğiniz appAccountToken, en hızlı yoldur. Bu olmadan ürün ve tarihe göre tersine arama yapmanız gerekir, bu da çok çabuk karmaşıklaşır.
Onayı kontrol edin. Onay yoksa yanıt yoktur. Bunu kaydedin ve devam edin.
Gerçek kullanım verisini çekin. Bir tahmin değil, varsayılan bir değer değil. "Bundan ne kadarını kullandılar" sorusuna cevap veremiyorsanız, otomasyonunuzdaki gerçek boşluk budur.
Yukarıdaki iki kısıtlamayı uygulayarak ConsumptionRequest'i oluşturun.
PUT ile gönderin, 202 yanıtını doğrulayın ve gönderdiğiniz payload'ı kaydedin.
5. adım, çoğu girişimin tıkandığı yerdir. API çağrısı bir öğleden sonralık iştir. Yedi hafta önce yapılmış bir satın alım için kullanıcı başına doğru tüketim verisine sahip olmak ise henüz çözmemiş olabileceğiniz bir veri modelleme problemidir.
Üretimde sağlam kalmasını sağlayan şey
Mutlu senaryonun ötesinde dört şey:
Idempotency. Apple bildirimleri yeniden dener ve handler'ınız aynı bildirimi iki kez görür. Bildirim UUID'sine göre dedupe yapın, yoksa yinelenen yanıtlar göndermiş olursunuz.
Gerçekten birine haber veren alerting. Sessizce başarısız olan bir handler, hiç handler olmamasından daha kötüdür, çünkü korunduğunuza inanırsınız.
Bir sandbox test düzeneği. Sandbox size 12 saat yerine 5 dakika verir, dolayısıyla bunu elle gelişigüzel test edemezsiniz. Script'leştirin.
Ve her vaka için ne gönderdiğinizin kaydı. Bir geri ödeme reddedildiğinde, hangi preference'ı gönderdiğinizi ve nedenini bilmek isteyeceksiniz. DECLINE'ınıza karşın bir geri ödeme onaylandığında, bunu da bilmek isteyeceksiniz.
Dürüst bir tahmin: daha önce webhook altyapısı kurduysanız birkaç günlük bağlayıcı iş, ona güvenmek için ise birkaç hafta. Bunun büyük kısmı Apple tarafıyla ilgili değil.
Ya da bunu başka bir şeye bırakın
Zaten RevenueCat veya Adapty kullanıyorsanız, önce onların sunduklarına bakın. İkisi de geri ödeme yanıt özellikleri ekledi ve receipt'leriniz ile müşteri eşlemeniz zaten orada mevcut.
Bu amaca özel geliştirilmiş Apple geri ödeme yönetim yazılımları daha da ileri gider. Refund Sensor zaten sahip olduğunuz App Store Connect anahtarlarıyla çalışır, her talebi süre içinde işlem kanıtıyla yanıtlar ve her vakanın sonucunu kaydeder. SDK yok, kod değişikliği yok, bağlanması yaklaşık beş dakika sürer. Daha geniş alandaki seçenekleri karşılaştırmayı tercih ederseniz, Apple geri ödeme yönetim araçları yazımıza bakabilirsiniz.
Müşteri tarafı, çünkü soruluyor
App Store satın alımları için nasıl geri ödeme talep edilir konusunda, kullanıcı tarafından bakıldığında: reportaproblem.apple.com adresine girin, oturum açın, son 90 gün içindeki satın alımı bulun, bir neden seçin. Apple, müşterilere 48 saat içinde yanıt alacaklarını söylüyor.
Aynı formu, StoreKit'in refund request sheet'ini kullanarak uygulamanızın içinde de gösterebilirsiniz; bu, mutsuz kullanıcıları bir yıldızlı yorum yerine Apple'a yönlendirir. Bu, geri ödemeyi onaylayamaz. Bunu sadece Apple yapabilir. Apple Support'un geri ödeme talep etme kılavuzu müşterinin gördüklerini ele alıyor.
Açıkça söylemekte fayda var, çünkü App Store refund management konusu fazla büyütülüyor: bir geri ödemeyi onaylayamaz veya reddedemezsiniz. Apple karar verirken önüne kanıt koyabilir ve bir preference belirtebilirsiniz. Elinizdeki tüm etki bundan ibarettir ve bu, çoğu geliştiricinin kullandığından daha fazlasıdır.
Kaynaklar
Sık sorulan sorular
Evet. CONSUMPTION_REQUEST bildirimi ve Send Consumption Information uç noktası tam olarak bunun için var. Geri ödemeyi onaylayamaz veya reddedemezsiniz, ancak Apple gönderdiğiniz bilgiyi kararına girdi olarak kullanır.
App Store Server Notifications V2'yi alın, JWS imzasını doğrulayın, işlemi bir kullanıcıyla eşleştirin, onayı kontrol edin, gerçek tüketim verilerini bir araya getirin ve 12 saat içinde v2 consumption uç noktasına PUT isteği gönderin. Bunun dışındaki her şey idempotency, uyarı (alerting) ve kayıt tutmadan ibarettir.
Integrations altındaki Users and Access bölümünden alınan bir In-App Purchase key. App Store Connect API anahtarınız bu çağrıları doğrulamaz ve saat sorunu gibi görünen bir 401 hatası alırsınız.
Hayır, isteğe bağlıdır. Ancak deliveryStatus DELIVERED değilse 0 olmalıdır ve orantılı (prorated) bir otomatik yenilenen abonelik için bu alanı tamamen atlamanız gerekir.
Yanıt vermeyin. Apple'ın yönergesi bu konuda açıktır ve talep geldikten sonra onay toplanamaz.
Bu bir garanti değil, bir girdidir. Apple, çeşitli faktörleri kullandığını belirtiyor. Pratikte, yoğun şekilde tüketilmiş bir satın alım için iyi kanıtlanmış bir DECLINE, hiç yanıt verilmeyen bir talebe kıyasla çok daha sık reddedilir.



