StoreKit

RSS for tag

Support in-app purchases and interactions with the App Store using StoreKit.

StoreKit Documentation

Posts under StoreKit subtopic

Post

Replies

Boosts

Views

Activity

StoreKit: No products returned in Sandbox + "This item is not available" in "initiate transaction"
Hi, my app was rejected because IAP were not present in the app. I followed guidelines more carefully and filled all buisness detail since then. And now I have: StoreKit Configuration in XCode is set to None, Products (subscription + consumable product) are already approved (from the previous review) Paid Apps Agreement - active Bank account - active Tax forms - active Compliance - active Problems: When trying to test it with TestFlight + sandbox account, StoreKit is returning zero products. When trying to check my products by "initiate transaction" from Sandbox App Store manage dashboard I am getting an error "This item is not available" I am totally stuck and don't know what to process next. Unfortunately API.
1
0
77
2w
Unknown Error when Trying to Add New Offer Codes
Hi there! Whenever I try to add a new Offer Code for my app's subscription, I get an unknown error. When I get to the last step of the "Create Offer for Codes" flow, I get an error that error reads "An error has occurred. Try again later." I have been getting this same error for over a week now, so any help figuring out how to add new offer codes would be greatly appreciated!
3
1
637
Dec ’25
Unresolved pending purchases for consumables
In our app we are running into a few issues with pending purchases staying on receipt indefinitely. These are consumable purchases where we received the purchase succeeded from apple but then something went wrong on our servers to validate and confirm the purchase. At this point the purchase stays on the apple receipt indefinitely or until we confirm it. The problem is there are lots of scenarios where we can't confirm purchases anymore (like a game world expired/banned player/etc). So there's a few things I'd like to know to see how this could be handle correctly. 1- Was the user already charged, and if yes would they ever be refunded if the purchase is not confirmed (some sort of expiry)? 2- Is there a way to cancel this sort of pending transaction directly from the app or backend? 3- If one of these users asked for a refund from apple would this clear the purchase from the receipt? Any information would be greatI couldn't find a lot of info on this topic.
0
1
53
Jun ’25
Apple Media Services T&C pop-up
I had published an App, and my app has App Clip supported. The issue I faced is that I had received complaints where the user keep seeing the pop up "Apple Media Services Terms and Conditions Have Changed" when user clicked on the "Open" Button in the App Clip. What we had tried so far: Let user switch the Apple Id's region to our supported region. Let user try to log out and log in to Apple Id within the supported region.
1
0
223
Feb ’26
Unable to load a subscription product in the app
Hi, I am building a new app in the App Store - the app is not live yet. I have setup an annual subscription product in AppStore Connect. Our problem is that we are unable to retrieve the product from our app - we've made sure that there are no missing metadata (e.g. price, availability). Has anyone encountered before? Appreciate any help provided. Thanks
7
0
187
Jan ’26
AppStoreServerNotificationV2 EXPIRED event after removing from sale
Our app is supposed to be removed from sale on May 31st. Subscriptions our app is offering will also be removed on May 1st one month before our app removal. I would like to know if AppStoreServerNotificationV2 EXPIRED event will be sent to a specified endpoint after the removal of these subscriptions. I think each subscription will be canceled automatically from May 1st to May 31st and it will send EXPIRED event to our server, but is it true? Thank you in advance.
1
0
155
Feb ’26
Does SubscriptionStoreView .storeButton(for:.policies) work?
I've added .storeButton(.visible, for:.policies) to my SubscriptionStoreView, and the buttons do appear, but when I tap on them I get a sheet that just says "Terms of Service Unavailable / Somethng went wrong. Try Again.". (similar for Privacy Policy). Is this expected in development? Will these start working correctly in production? (and, more importantly, in App Review?) The docs say that these use the values (i.e. URLs) set in App Store Connect, but that I can override those. This is a new app. Is that wrong, do I need to set the URLs explicitly? Edited to add: the console reports: Failed to fetch terms of service and privacy policy: Error Domain=NSURLErrorDomain Code=-1011 "(null)"
7
1
1.1k
2w
Unable to retrieve data from In App Purchase
I want to add in-app purchasing to my app, but I can't figure out what part of my workflow is wrong. I created a product for my app in iTunes Connect (the product ID is com.mycompany.products.***) and it's in "Ready to submit" status. I created a sandbox test user for this app. I connected to iTunes on a real device using the sandbox AppleID. I went back to XCode and added in-app purchasing to my app. I turned on developer mode on the real device and logged in as the sandbox user. I built the app and ran it on a real device (not the simulator). I tried to get product information (com.mycompany.products.***) but nothing was returned. In-app purchasing is registered in App Store Connect and the status is "Ready to submit". The code only retrieves product information in a simple way, so I don't think there's a problem. inAppPurchase.getProducts(["com.mycompany.products.***"]).then(console.log).catch(console.error); But it only returns an empty array. What could be wrong? Any help would be much appreciated.
2
1
74
Jul ’25
Promotional offer purchase fails in Sandbox with ASDServerErrorDomain 3902 after payment sheet
Hello, I’m integrating promotional offers for auto-renewable subscriptions using StoreKit 2. The offer is displayed correctly, the Apple purchase sheet appears, and I can start the payment flow. The sheet shows the correct discounted price and the end date of the offer. However, after confirming the purchase, an alert appears saying “Unable to Purchase - Contact the developer for more information” When dismissing the alert, Xcode logs the following: Purchase did not return a transaction: Error Domain=ASDServerErrorDomain Code=3902 "No se ha podido realizar la compra" UserInfo={ NSLocalizedFailureReason=No se ha podido realizar la compra, client-environment-type=Sandbox, AMSServerErrorCode=3902, storefront-country-code=ESP } Test environment: App installed from Xcode on a real iPhone Logged in with a Sandbox Apple ID Using StoreKit 2 Promotional offer applied using: Product.PurchaseOption.promotionalOffer(_:compactJWS:) On the server side, I generate the promotional offer signature exactly as described in Apple’s documentation: https://developer.apple.com/documentation/storekit/generating-a-signature-for-promotional-offers The signature is generated using a Subscription Key Signed with ECDSA + SHA256 Uses the correct invisible separator (U+2063) The signature is validated locally using the derived public key and verifies correctly The sandbox user has had previous subscriptions, which is why this promotional offer is eligible and shown. Given that: The offer is displayed correctly The purchase sheet shows the discounted price and duration The signature validates locally The error occurs only after confirming the purchase My question is: Is this a known limitation or issue with promotional offers in the Sandbox environment? Should promotional offers be tested exclusively via TestFlight instead of Sandbox? Any clarification would be greatly appreciated. Thank you!
2
0
178
Dec ’25
Double-counted consumable in StoreKit unfinished and updates workflow
In Getting started with In-App Purchase using StoreKit views and the corresponding sample project, Store simultaneously enumerates Transaction.unfinished and Transaction.updates. Since, "if your app has unfinished transactions, the updates listener receives them once, immediately after the app launches," it appears that Transaction.unfinished would also receive the same unfinished transactions causing handle(updatedTransaction:) to be called for twice for each transaction, causing consumables to be double-counted. Is this a bug in the sample? Is there more information on concurrent execution of unfinished and updates?
1
1
221
3w
StoreKit 2: Delayed Transaction and Entitlement Updates After Promo Code Subscription Redemption
I’m implementing a subscription purchase flow using promo code redemption via an external App Store URL. Flow: User taps “Purchase” in the app (spinner shown) App opens the promo redemption URL (apps.apple.com/redeem) User completes redemption in the App Store User returns to the app The app must determine whether the subscription was purchased within a reasonable time window The app listens to Transaction.updates and also checks Transaction.currentEntitlements when the app returns to the foreground. Issue: After redeeming a subscription promo code via the App Store and returning to the app, the app cannot reliably determine whether the subscription was successfully purchased within a short, user-acceptable time window. In many cases, neither Transaction.updates nor Transaction.currentEntitlements reflects the newly redeemed subscription immediately after returning to the app. The entitlement may appear only after a significant delay, or not within a 60-second timeout at all, even though the promo code redemption succeeded. Expected: When the user returns to the app after completing promo code redemption, StoreKit 2 should report the updated subscription entitlement shortly thereafter (e.g. within a few seconds) via either Transaction.updates or Transaction.currentEntitlements. Below is the minimal interactor used in the sample project. The app considers the purchase successful if either a verified transaction for the product is received via Transaction.updates, or the product appears in Transaction.currentEntitlements when the app returns to the foreground. Otherwise, the flow fails after a 60-second timeout. Questions: Is this entitlement propagation delay expected when redeeming promo codes through the App Store? Is there a recommended API or flow for immediately determining whether a subscription has been successfully redeemed? Is there a more reliable way to detect entitlement changes after promo code redemption without triggering user authentication prompts (e.g., from AppStore.sync())? import UIKit import StoreKit final class PromoPurchaseInteractor { private let timeout: TimeInterval = 60 private struct PendingOfferRedemption { let productId: String let completion: (Result<Bool, Error>) -> Void } private var pendingRedemption: PendingOfferRedemption? private var updatesTask: Task<Void, Never>? private var timeoutTask: Task<Void, Never>? enum DefaultError: Error { case generic case timeout } init() { NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) } deinit { NotificationCenter.default.removeObserver(self) updatesTask?.cancel() timeoutTask?.cancel() } func purchaseProduct(using offerUrl: URL, productId: String, completion: @escaping (Result<Bool, Error>) -> Void) { guard pendingRedemption == nil else { completion(.failure(DefaultError.generic)) return } pendingRedemption = PendingOfferRedemption(productId: productId, completion: completion) startPurchase(using: offerUrl) } @objc private func willEnterForeground() { guard let pendingRedemption = pendingRedemption else { return } startTimeoutObserver() Task { if await hasEntitlement(for: pendingRedemption.productId) { await MainActor.run { self.completePurchase(result: .success(true)) } } } } private func startPurchase(using offerURL: URL) { startTransactionUpdatesObserver() UIApplication.shared.open(offerURL) { [weak self] success in guard let self = self else { return } if !success { self.completePurchase(result: .failure(DefaultError.generic)) } } } private func completePurchase(result: Result<Bool, Error>) { stopTransactionUpdatesObserver() stopTimeoutObserver() guard let _ = pendingRedemption else { return } pendingRedemption?.completion(result) pendingRedemption = nil } private func startTransactionUpdatesObserver() { updatesTask?.cancel() updatesTask = Task { for await update in Transaction.updates { guard case .verified(let transaction) = update else { continue } await MainActor.run { [weak self] in guard let self = self, let pending = self.pendingRedemption, transaction.productID == pending.productId else { return } self.completePurchase(result: .success(true)) } await transaction.finish() } } } private func stopTransactionUpdatesObserver() { updatesTask?.cancel() updatesTask = nil } private func startTimeoutObserver() { guard pendingRedemption != nil else { return } timeoutTask?.cancel() timeoutTask = Task { try? await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000)) await MainActor.run { [weak self] in self?.completePurchase(result: .failure(DefaultError.timeout)) } } } private func stopTimeoutObserver() { timeoutTask?.cancel() timeoutTask = nil } private func hasEntitlement(for productId: String) async -> Bool { for await result in Transaction.currentEntitlements { guard case .verified(let transaction) = result else { continue } if transaction.productID == productId { return true } } return false } }
1
1
203
Jan ’26
Can you buy an IAP via StoreKit 1 on iOS 26.2?
If an app on the App Store still uses StoreKit 1 (a.k.a. the Original StoreKit) to handle In-App Purchases, would IAPs work for users who download such app on iOS 26.2? Would the app allow the users to purchase an IAP via StoreKit 1 or would it be impossible to buy the IAP on iOS 26? The iOS Documentation says that SKPaymentQueue (which is a part of StoreKit 1) is "Deprecated" and "No longer supported.", with the support being for iOS 3.0–18.0. Does this mean that apps using StoreKit 1 won't be able to make IAP purchases when running on iOS 26?
1
1
197
Dec ’25
AppTransaction.shared doesn’t return originalAppVersion for users who installed the app in 2017
Hi, I'm using the AppTransaction.shared API to retrieve the originalAppVersion, but I'm encountering issues for users who originally installed the app in 2017. Specifically, the property doesn't seem to return the expected value (or returns nil) for these older accounts. I have verified this issue using a real App Store purchase from 2017. Steps to Reproduce: Use a test account that originally downloaded the app in 2017. Call: let shared = try await AppTransaction.shared print(shared.originalAppVersion) Observe that originalAppVersion is missing or not returned correctly. Any insights on whether this is expected behavior for very old App Store purchases, or if there is a workaround to reliably detect the original app version? Thanks in advance!
4
1
138
May ’25
StoreKit 2 - Is it necessary to finish unverified transactions?
The sample code provided in https://developer.apple.com/wwdc21/10114 doesn't appear to call finish() on unverified transactions, and I haven't been able to find any documentation regarding what to do with unfinished transactions. However, Apple has always emphasized the importance of finishing transactions, and since a transaction object is provided even with the unverified state, I'd love some guidance!
4
1
2.8k
May ’25
StoreKit sandbox purchase and product fetch not working (IAPError: storekit_no_response)
💬 Post Content Hello everyone, I’m currently testing In-App Purchases (auto-renewable subscriptions) for my iOS app, and I’m experiencing an issue where the product information cannot be fetched from StoreKit. ❓ Questions For sandbox testing, is it absolutely necessary to submit a new app version for review (with the in-app purchase included)? Or can I test subscriptions without submitting a new build to App Review? Under what conditions does the error IAPError(code: storekit_no_response, source: app_store, message: StoreKit: Failed to get response from platform.) 🧪 What I’ve Tried • Confirmed that the bundle identifier matches the App Store Connect record • Verified that In-App Purchase capability is enabled in Xcode • Ensured the sandbox tester account is logged in (Settings → App Store) • Removed the StoreKit configuration file to use the sandbox environment • Tried both real device and simulator (same error) • Accepted the Paid Apps Agreement in App Store Connect • Products are created but currently not yet submitted for review 🔍 Environment • App type: iOS app built with Flutter (using in_app_purchase plugin) • Build type: Archive build installed via Xcode (Run on device) and testFlight • StoreKit Configuration File: Currently removed (for sandbox test); • Status: Ready to submit in App Store Connect
0
1
166
Nov ’25
Mismatch between App Store Server API `expiresDate` (July 23) and iOS UI “Expires on” date (July 22) for 1-month subscription
Hi everyone, I’m seeing a consistent one-day discrepancy between the expiresDate returned by the App Store Server API and the “Expires on” date shown in the iOS Settings / App Store subscription list. I’d like to confirm whether this behavior is expected or if I’m misunderstanding the way Apple rounds dates. Reproduction steps Step Action Result 1 Purchase a 1-month auto-renewable subscription on 23 June 2025 14:00 JST (UTC+9) Transaction succeeds 2 Immediately fetch the transaction with GET /inApps/v1/subscriptions/{transactionId} Response contains "expiresDate": "2025-07-23T05:00:00Z" (= 23 July 2025 14:00 JST) 3 On the same device open Settings › Apple ID › Subscriptions (or App Store › Account › Subscriptions) UI shows Expires on: 22 July 2025 The same happens for every monthly renewal and on multiple devices. Region is Japan, device time zone Asia/Tokyo. What I understand so far (and my hypothesis) Apple’s docs say a monthly subscription renews “on the same calendar date” of the next month, so renewal in this example is 23 July. If the renewal is scheduled for 23 July at 14:00 JST, the subscription is fully usable until the end of 22 July in calendar terms, because the new billing period starts the moment the 23rd begins in Apple’s canonical time zone. Therefore, it might be intentional for the UI to display 22 July—i.e., “you can keep using it through the 22nd; on the 23rd it renews.” This hypothesis makes sense internally, yet it still looks confusing to end users who read “Expires on 22 July” and assume access ends at 00:00 on the 22nd, a whole day earlier than in reality. Questions Is showing the day before the renewal date the official/expected behavior? If so, could Apple clarify that the “Expires on” label represents the last full calendar day rather than the exact expiry timestamp? Which value should we surface in-app when telling users “Your subscription is valid until …”? The server’s expiresDate (precise to the second, converted to user time zone), or A UI-style date that’s one day earlier, matching Settings / App Store? Does Apple have a public document describing this rounding/visual convention? Have other developers encountered user confusion about the apparent 1-day “shortening” and, if so, how did you word your in-app messaging? Any insight from Apple engineers or fellow developers would be greatly appreciated. Thank you!
0
1
284
Jun ’25
StoreKit: No products returned in Sandbox + "This item is not available" in "initiate transaction"
Hi, my app was rejected because IAP were not present in the app. I followed guidelines more carefully and filled all buisness detail since then. And now I have: StoreKit Configuration in XCode is set to None, Products (subscription + consumable product) are already approved (from the previous review) Paid Apps Agreement - active Bank account - active Tax forms - active Compliance - active Problems: When trying to test it with TestFlight + sandbox account, StoreKit is returning zero products. When trying to check my products by "initiate transaction" from Sandbox App Store manage dashboard I am getting an error "This item is not available" I am totally stuck and don't know what to process next. Unfortunately API.
Replies
1
Boosts
0
Views
77
Activity
2w
Unknown Error when Trying to Add New Offer Codes
Hi there! Whenever I try to add a new Offer Code for my app's subscription, I get an unknown error. When I get to the last step of the "Create Offer for Codes" flow, I get an error that error reads "An error has occurred. Try again later." I have been getting this same error for over a week now, so any help figuring out how to add new offer codes would be greatly appreciated!
Replies
3
Boosts
1
Views
637
Activity
Dec ’25
iOS 26.4 beta3,内购支付,票据被延迟
在iOS 26.4 beta3版本中,当前支付完成,获取的票据是上次支付的票据,在拉起一笔支付成,获取的又是上次支付的票据
Replies
1
Boosts
1
Views
248
Activity
3w
Unresolved pending purchases for consumables
In our app we are running into a few issues with pending purchases staying on receipt indefinitely. These are consumable purchases where we received the purchase succeeded from apple but then something went wrong on our servers to validate and confirm the purchase. At this point the purchase stays on the apple receipt indefinitely or until we confirm it. The problem is there are lots of scenarios where we can't confirm purchases anymore (like a game world expired/banned player/etc). So there's a few things I'd like to know to see how this could be handle correctly. 1- Was the user already charged, and if yes would they ever be refunded if the purchase is not confirmed (some sort of expiry)? 2- Is there a way to cancel this sort of pending transaction directly from the app or backend? 3- If one of these users asked for a refund from apple would this clear the purchase from the receipt? Any information would be greatI couldn't find a lot of info on this topic.
Replies
0
Boosts
1
Views
53
Activity
Jun ’25
Apple Media Services T&C pop-up
I had published an App, and my app has App Clip supported. The issue I faced is that I had received complaints where the user keep seeing the pop up "Apple Media Services Terms and Conditions Have Changed" when user clicked on the "Open" Button in the App Clip. What we had tried so far: Let user switch the Apple Id's region to our supported region. Let user try to log out and log in to Apple Id within the supported region.
Replies
1
Boosts
0
Views
223
Activity
Feb ’26
Storekit2 StoreKitError.unknown
iOS Storekit2 Appstore production environment, some user feedback in app purchase faliure, What our log records is StoreKitError.unknown,please How to solve problem, thanks
Replies
1
Boosts
1
Views
251
Activity
Apr ’25
Unable to load a subscription product in the app
Hi, I am building a new app in the App Store - the app is not live yet. I have setup an annual subscription product in AppStore Connect. Our problem is that we are unable to retrieve the product from our app - we've made sure that there are no missing metadata (e.g. price, availability). Has anyone encountered before? Appreciate any help provided. Thanks
Replies
7
Boosts
0
Views
187
Activity
Jan ’26
AppStoreServerNotificationV2 EXPIRED event after removing from sale
Our app is supposed to be removed from sale on May 31st. Subscriptions our app is offering will also be removed on May 1st one month before our app removal. I would like to know if AppStoreServerNotificationV2 EXPIRED event will be sent to a specified endpoint after the removal of these subscriptions. I think each subscription will be canceled automatically from May 1st to May 31st and it will send EXPIRED event to our server, but is it true? Thank you in advance.
Replies
1
Boosts
0
Views
155
Activity
Feb ’26
Does SubscriptionStoreView .storeButton(for:.policies) work?
I've added .storeButton(.visible, for:.policies) to my SubscriptionStoreView, and the buttons do appear, but when I tap on them I get a sheet that just says "Terms of Service Unavailable / Somethng went wrong. Try Again.". (similar for Privacy Policy). Is this expected in development? Will these start working correctly in production? (and, more importantly, in App Review?) The docs say that these use the values (i.e. URLs) set in App Store Connect, but that I can override those. This is a new app. Is that wrong, do I need to set the URLs explicitly? Edited to add: the console reports: Failed to fetch terms of service and privacy policy: Error Domain=NSURLErrorDomain Code=-1011 "(null)"
Replies
7
Boosts
1
Views
1.1k
Activity
2w
Unable to retrieve data from In App Purchase
I want to add in-app purchasing to my app, but I can't figure out what part of my workflow is wrong. I created a product for my app in iTunes Connect (the product ID is com.mycompany.products.***) and it's in "Ready to submit" status. I created a sandbox test user for this app. I connected to iTunes on a real device using the sandbox AppleID. I went back to XCode and added in-app purchasing to my app. I turned on developer mode on the real device and logged in as the sandbox user. I built the app and ran it on a real device (not the simulator). I tried to get product information (com.mycompany.products.***) but nothing was returned. In-app purchasing is registered in App Store Connect and the status is "Ready to submit". The code only retrieves product information in a simple way, so I don't think there's a problem. inAppPurchase.getProducts(["com.mycompany.products.***"]).then(console.log).catch(console.error); But it only returns an empty array. What could be wrong? Any help would be much appreciated.
Replies
2
Boosts
1
Views
74
Activity
Jul ’25
Promotional offer purchase fails in Sandbox with ASDServerErrorDomain 3902 after payment sheet
Hello, I’m integrating promotional offers for auto-renewable subscriptions using StoreKit 2. The offer is displayed correctly, the Apple purchase sheet appears, and I can start the payment flow. The sheet shows the correct discounted price and the end date of the offer. However, after confirming the purchase, an alert appears saying “Unable to Purchase - Contact the developer for more information” When dismissing the alert, Xcode logs the following: Purchase did not return a transaction: Error Domain=ASDServerErrorDomain Code=3902 "No se ha podido realizar la compra" UserInfo={ NSLocalizedFailureReason=No se ha podido realizar la compra, client-environment-type=Sandbox, AMSServerErrorCode=3902, storefront-country-code=ESP } Test environment: App installed from Xcode on a real iPhone Logged in with a Sandbox Apple ID Using StoreKit 2 Promotional offer applied using: Product.PurchaseOption.promotionalOffer(_:compactJWS:) On the server side, I generate the promotional offer signature exactly as described in Apple’s documentation: https://developer.apple.com/documentation/storekit/generating-a-signature-for-promotional-offers The signature is generated using a Subscription Key Signed with ECDSA + SHA256 Uses the correct invisible separator (U+2063) The signature is validated locally using the derived public key and verifies correctly The sandbox user has had previous subscriptions, which is why this promotional offer is eligible and shown. Given that: The offer is displayed correctly The purchase sheet shows the discounted price and duration The signature validates locally The error occurs only after confirming the purchase My question is: Is this a known limitation or issue with promotional offers in the Sandbox environment? Should promotional offers be tested exclusively via TestFlight instead of Sandbox? Any clarification would be greatly appreciated. Thank you!
Replies
2
Boosts
0
Views
178
Activity
Dec ’25
Double-counted consumable in StoreKit unfinished and updates workflow
In Getting started with In-App Purchase using StoreKit views and the corresponding sample project, Store simultaneously enumerates Transaction.unfinished and Transaction.updates. Since, "if your app has unfinished transactions, the updates listener receives them once, immediately after the app launches," it appears that Transaction.unfinished would also receive the same unfinished transactions causing handle(updatedTransaction:) to be called for twice for each transaction, causing consumables to be double-counted. Is this a bug in the sample? Is there more information on concurrent execution of unfinished and updates?
Replies
1
Boosts
1
Views
221
Activity
3w
StoreKit 2: Delayed Transaction and Entitlement Updates After Promo Code Subscription Redemption
I’m implementing a subscription purchase flow using promo code redemption via an external App Store URL. Flow: User taps “Purchase” in the app (spinner shown) App opens the promo redemption URL (apps.apple.com/redeem) User completes redemption in the App Store User returns to the app The app must determine whether the subscription was purchased within a reasonable time window The app listens to Transaction.updates and also checks Transaction.currentEntitlements when the app returns to the foreground. Issue: After redeeming a subscription promo code via the App Store and returning to the app, the app cannot reliably determine whether the subscription was successfully purchased within a short, user-acceptable time window. In many cases, neither Transaction.updates nor Transaction.currentEntitlements reflects the newly redeemed subscription immediately after returning to the app. The entitlement may appear only after a significant delay, or not within a 60-second timeout at all, even though the promo code redemption succeeded. Expected: When the user returns to the app after completing promo code redemption, StoreKit 2 should report the updated subscription entitlement shortly thereafter (e.g. within a few seconds) via either Transaction.updates or Transaction.currentEntitlements. Below is the minimal interactor used in the sample project. The app considers the purchase successful if either a verified transaction for the product is received via Transaction.updates, or the product appears in Transaction.currentEntitlements when the app returns to the foreground. Otherwise, the flow fails after a 60-second timeout. Questions: Is this entitlement propagation delay expected when redeeming promo codes through the App Store? Is there a recommended API or flow for immediately determining whether a subscription has been successfully redeemed? Is there a more reliable way to detect entitlement changes after promo code redemption without triggering user authentication prompts (e.g., from AppStore.sync())? import UIKit import StoreKit final class PromoPurchaseInteractor { private let timeout: TimeInterval = 60 private struct PendingOfferRedemption { let productId: String let completion: (Result<Bool, Error>) -> Void } private var pendingRedemption: PendingOfferRedemption? private var updatesTask: Task<Void, Never>? private var timeoutTask: Task<Void, Never>? enum DefaultError: Error { case generic case timeout } init() { NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) } deinit { NotificationCenter.default.removeObserver(self) updatesTask?.cancel() timeoutTask?.cancel() } func purchaseProduct(using offerUrl: URL, productId: String, completion: @escaping (Result<Bool, Error>) -> Void) { guard pendingRedemption == nil else { completion(.failure(DefaultError.generic)) return } pendingRedemption = PendingOfferRedemption(productId: productId, completion: completion) startPurchase(using: offerUrl) } @objc private func willEnterForeground() { guard let pendingRedemption = pendingRedemption else { return } startTimeoutObserver() Task { if await hasEntitlement(for: pendingRedemption.productId) { await MainActor.run { self.completePurchase(result: .success(true)) } } } } private func startPurchase(using offerURL: URL) { startTransactionUpdatesObserver() UIApplication.shared.open(offerURL) { [weak self] success in guard let self = self else { return } if !success { self.completePurchase(result: .failure(DefaultError.generic)) } } } private func completePurchase(result: Result<Bool, Error>) { stopTransactionUpdatesObserver() stopTimeoutObserver() guard let _ = pendingRedemption else { return } pendingRedemption?.completion(result) pendingRedemption = nil } private func startTransactionUpdatesObserver() { updatesTask?.cancel() updatesTask = Task { for await update in Transaction.updates { guard case .verified(let transaction) = update else { continue } await MainActor.run { [weak self] in guard let self = self, let pending = self.pendingRedemption, transaction.productID == pending.productId else { return } self.completePurchase(result: .success(true)) } await transaction.finish() } } } private func stopTransactionUpdatesObserver() { updatesTask?.cancel() updatesTask = nil } private func startTimeoutObserver() { guard pendingRedemption != nil else { return } timeoutTask?.cancel() timeoutTask = Task { try? await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000)) await MainActor.run { [weak self] in self?.completePurchase(result: .failure(DefaultError.timeout)) } } } private func stopTimeoutObserver() { timeoutTask?.cancel() timeoutTask = nil } private func hasEntitlement(for productId: String) async -> Bool { for await result in Transaction.currentEntitlements { guard case .verified(let transaction) = result else { continue } if transaction.productID == productId { return true } } return false } }
Replies
1
Boosts
1
Views
203
Activity
Jan ’26
Can you buy an IAP via StoreKit 1 on iOS 26.2?
If an app on the App Store still uses StoreKit 1 (a.k.a. the Original StoreKit) to handle In-App Purchases, would IAPs work for users who download such app on iOS 26.2? Would the app allow the users to purchase an IAP via StoreKit 1 or would it be impossible to buy the IAP on iOS 26? The iOS Documentation says that SKPaymentQueue (which is a part of StoreKit 1) is "Deprecated" and "No longer supported.", with the support being for iOS 3.0–18.0. Does this mean that apps using StoreKit 1 won't be able to make IAP purchases when running on iOS 26?
Replies
1
Boosts
1
Views
197
Activity
Dec ’25
App 内购买项目对接
最近我们有个应用要对接App 内购买项目,有什么好的资料或者demo提供一下吗?
Replies
0
Boosts
1
Views
89
Activity
Nov ’25
AppTransaction.shared doesn’t return originalAppVersion for users who installed the app in 2017
Hi, I'm using the AppTransaction.shared API to retrieve the originalAppVersion, but I'm encountering issues for users who originally installed the app in 2017. Specifically, the property doesn't seem to return the expected value (or returns nil) for these older accounts. I have verified this issue using a real App Store purchase from 2017. Steps to Reproduce: Use a test account that originally downloaded the app in 2017. Call: let shared = try await AppTransaction.shared print(shared.originalAppVersion) Observe that originalAppVersion is missing or not returned correctly. Any insights on whether this is expected behavior for very old App Store purchases, or if there is a workaround to reliably detect the original app version? Thanks in advance!
Replies
4
Boosts
1
Views
138
Activity
May ’25
StoreKit 2 - Is it necessary to finish unverified transactions?
The sample code provided in https://developer.apple.com/wwdc21/10114 doesn't appear to call finish() on unverified transactions, and I haven't been able to find any documentation regarding what to do with unfinished transactions. However, Apple has always emphasized the importance of finishing transactions, and since a transaction object is provided even with the unverified state, I'd love some guidance!
Replies
4
Boosts
1
Views
2.8k
Activity
May ’25
StoreKit sandbox purchase and product fetch not working (IAPError: storekit_no_response)
💬 Post Content Hello everyone, I’m currently testing In-App Purchases (auto-renewable subscriptions) for my iOS app, and I’m experiencing an issue where the product information cannot be fetched from StoreKit. ❓ Questions For sandbox testing, is it absolutely necessary to submit a new app version for review (with the in-app purchase included)? Or can I test subscriptions without submitting a new build to App Review? Under what conditions does the error IAPError(code: storekit_no_response, source: app_store, message: StoreKit: Failed to get response from platform.) 🧪 What I’ve Tried • Confirmed that the bundle identifier matches the App Store Connect record • Verified that In-App Purchase capability is enabled in Xcode • Ensured the sandbox tester account is logged in (Settings → App Store) • Removed the StoreKit configuration file to use the sandbox environment • Tried both real device and simulator (same error) • Accepted the Paid Apps Agreement in App Store Connect • Products are created but currently not yet submitted for review 🔍 Environment • App type: iOS app built with Flutter (using in_app_purchase plugin) • Build type: Archive build installed via Xcode (Run on device) and testFlight • StoreKit Configuration File: Currently removed (for sandbox test); • Status: Ready to submit in App Store Connect
Replies
0
Boosts
1
Views
166
Activity
Nov ’25
Mismatch between App Store Server API `expiresDate` (July 23) and iOS UI “Expires on” date (July 22) for 1-month subscription
Hi everyone, I’m seeing a consistent one-day discrepancy between the expiresDate returned by the App Store Server API and the “Expires on” date shown in the iOS Settings / App Store subscription list. I’d like to confirm whether this behavior is expected or if I’m misunderstanding the way Apple rounds dates. Reproduction steps Step Action Result 1 Purchase a 1-month auto-renewable subscription on 23 June 2025 14:00 JST (UTC+9) Transaction succeeds 2 Immediately fetch the transaction with GET /inApps/v1/subscriptions/{transactionId} Response contains "expiresDate": "2025-07-23T05:00:00Z" (= 23 July 2025 14:00 JST) 3 On the same device open Settings › Apple ID › Subscriptions (or App Store › Account › Subscriptions) UI shows Expires on: 22 July 2025 The same happens for every monthly renewal and on multiple devices. Region is Japan, device time zone Asia/Tokyo. What I understand so far (and my hypothesis) Apple’s docs say a monthly subscription renews “on the same calendar date” of the next month, so renewal in this example is 23 July. If the renewal is scheduled for 23 July at 14:00 JST, the subscription is fully usable until the end of 22 July in calendar terms, because the new billing period starts the moment the 23rd begins in Apple’s canonical time zone. Therefore, it might be intentional for the UI to display 22 July—i.e., “you can keep using it through the 22nd; on the 23rd it renews.” This hypothesis makes sense internally, yet it still looks confusing to end users who read “Expires on 22 July” and assume access ends at 00:00 on the 22nd, a whole day earlier than in reality. Questions Is showing the day before the renewal date the official/expected behavior? If so, could Apple clarify that the “Expires on” label represents the last full calendar day rather than the exact expiry timestamp? Which value should we surface in-app when telling users “Your subscription is valid until …”? The server’s expiresDate (precise to the second, converted to user time zone), or A UI-style date that’s one day earlier, matching Settings / App Store? Does Apple have a public document describing this rounding/visual convention? Have other developers encountered user confusion about the apparent 1-day “shortening” and, if so, how did you word your in-app messaging? Any insight from Apple engineers or fellow developers would be greatly appreciated. Thank you!
Replies
0
Boosts
1
Views
284
Activity
Jun ’25
Age Verification: what is a sandbox account?
On this page: https://developer.apple.com/documentation/storekit/testing-age-assurance-in-sandbox It says: Start with a Sandbox account. What is a Sandbox account and how does one set one up? Just it just simply mean an Apple account id used for testing, or something else?
Replies
1
Boosts
0
Views
147
Activity
Nov ’25