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

Created

Switching App Store Server Notifications from V1 → V2 — what happens to existing subscriptions?
Hello — quick question about App Store Server Notifications migration. We have a live app using Production V1 notifications for recurring in-app subscriptions. We plan to switch the Production webhook to V2. After the switch: Will notifications for existing subscriptions be delivered in V1 format, V2 format, or will it depend (e.g., queued V1 retries vs new V2 deliveries)? If V1 retries are queued, how long should we expect overlap/retries to continue? Any recommended cutover best practices (support both formats, revert process, etc.)? Happy to share additional details. Thanks.
1
0
219
Dec ’25
Cannot repurchase subscription SKU — StoreKit keeps returning old expired transaction
Some users cannot repurchase a subscription SKU after it has expired. Flow: User previously subscribed. User canceled and the subscription fully expired. After weeks, user reinstalls the app and taps the same SKU. StoreKit does not create a new purchase transaction. Instead, StoreKit always returns the old expired transaction in updatedTransactions. Therefore, the user is permanently unable to purchase the SKU again. We have already tried: Adding payment observer at app launch Calling finishTransaction for all transactions Clearing queue at startup SKReceiptRefreshRequest Server-side verifyReceipt Ensuring subscription is truly expired (not in grace/retry) Not calling restoreCompletedTransactions None of these resolved the issue. StoreKit still only sends the old transaction and never generates a new one. Expected behavior: A new purchase transaction should be created when user taps the expired subscription SKU. Actual behavior: StoreKit repeatedly pushes the old expired transaction, blocking new purchases. We can provide: Some users cannot repurchase a subscription SKU after it has expired. Flow: User previously subscribed. User canceled and the subscription fully expired. After weeks, user reinstalls the app and taps the same SKU. StoreKit does not create a new purchase transaction. Instead, StoreKit always returns the old expired transaction in updatedTransactions. Therefore, the user is permanently unable to purchase the SKU again. We have already tried: Adding payment observer at app launch Calling finishTransaction for all transactions Clearing queue at startup SKReceiptRefreshRequest Server-side verifyReceipt Ensuring subscription is truly expired (not in grace/retry) Not calling restoreCompletedTransactions None of these resolved the issue. StoreKit still only sends the old transaction and never generates a new one. Expected behavior: A new purchase transaction should be created when user taps the expired subscription SKU. Actual behavior: StoreKit repeatedly pushes the old expired transaction, blocking new purchases. We can provide: Affected user’s base64 receipt verifyReceipt full response Transaction logs (transactionIdentifier, original_transaction_id, productIdentifier, state) Please help investigate why StoreKit is not allowing a new subscription purchase. Affected user’s base64 receipt verifyReceipt full response Transaction logs (transactionIdentifier, original_transaction_id, productIdentifier, state) Please help investigate why StoreKit is not allowing a new subscription purchase.
1
0
185
Dec ’25
RequestReviewAction never triggering rating dialog
Hello, We are having an issue with the RequestReview API and were hoping to get some help. We know that there is no guarantee that the in-app review modal will show and we know that there are 3 circumstances in which it will definitely not appear: if the user has turned off in-app review/ratings in their settings if the user has submitted a review for that app on that device within the last 365 days if the user has been asked for a review >3 times in the last 365 days When testing our implementation, every single one of our testers did not receive the rating modal despite the fact that we had all our testers turn on the app rating setting and that we have never asked for reviews from our app before. So that seems suspicious. While it is possible that something is up with our code (and I have provided some snippets below) we are also concerned that apple maybe is suppressing it for another reason. We really want to go live with our app review code but unfortunately we are not able to get confidence that it will ever appear for the user. Can you please help us understand why this isn't working. The code: We are using the SwiftUI approach to requesting review. Here are some relevant code snippets Important to note, we have a modal that appears when the user is in our list of active, targeted users. If they tap yes on this modal, it should show the in app rate the app system modal. If they tap no, we present them with an airship survey so that they can give feedback. Here is the code for the Yes button action: @Environment(\.requestReview) private var requestReview private var yesButton: some View { Button( action: { dismiss() requestReview() }, label: { Text(Lingua.General.appRateFirstButton) .regularParagraph() .frame(width: 180, height: 35) } ) .customButtonStyle( foregroundColor: .black, backgroundColor: Color(.powderBlue), radius: 36 ) } and this is the logic we use to determine whether we want to show them the modal in the first place. Obviously, a lot of this code leads to deeper areas in our logic and code but to give an idea... private func showAppRateModalIfNeeded() { if preferencesManager.appRateReviewShown == nil, accountManager.userAccount?.permissions.rateTheApp == true { let appReviewModalVC = UIHostingController(rootView: AppReviewModal()) appReviewModalVC.view.backgroundColor = .init(white: 0, alpha: 0.6) appReviewModalVC.modalPresentationStyle = .overFullScreen appReviewModalVC.modalTransitionStyle = .crossDissolve parentVC?.navigationController?.present(appReviewModalVC, animated: true) preferencesManager.appRateReviewShown = true } } When testing in debug, we do find that the modal appears and works as expected. However, on release builds nobody is able to trigger it. Why? Are we doing something wrong here or is Apple just suppressing it. We are thinking about implementing the button taking the user directly into the app store review but we'd prefer to do the lower-friction dialog in-app if we can get it work so the user doesn't get sent out of the app.
2
0
178
Dec ’25
Apple Pay v2 (signedTransactionInfo) : how to verify new token format and migrate from legacy EC_v1?
I’m updating a legacy application that used Apple Pay v1 token format, and in my new revamped version I’m now receiving the newer Apple Pay v2 format. The old (v1) payload looked like this: php { "version": "EC_v1", "data": "...", "signature": "...", "header": { "ephemeralPublicKey": "...", "publicKeyHash": "...", "transactionId": "..." } } In the new revamp (v2), Apple Pay returns this instead: php { "signedTransactionInfo": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF..." } From what I understand: v1 tokens were elliptic-curve encrypted JSON objects containing a header and signature. v2 tokens seem to be JWS (JSON Web Signature) strings using the ES256 algorithm, possibly containing transaction and subscription details inside. Questions Is there any official Apple documentation or migration note explaining the move from EC_v1 → signedTransactionInfo? How should I verify or decode the new signedTransactionInfo payload? Should the verification now use Apple’s public keys instead of the legacy Merchant ID certificate? Are there any example implementations or SDKs that can handle both v1 and v2 formats during migration? Is there a recommended way to maintain backward compatibility while transitioning existing users? Goal Ensure that my revamped app can handle Apple Pay v2 tokens securely while keeping the legacy v1 integration functional until all users are migrated.
1
0
520
Nov ’25
Ask to buy pending state lacking transaction object
StoreKit ask to buy should have more data in pending state. When user try to purchase ask to buy, we should get at least transactionID, product itself, and time that user start the request. So we can keep track of the whole transaction flow jwsRepresentation should always available for every state, actually even failing state. And should attach state inside of it. Instead of only available after verified purchase. So we can use transactionID and everything relate to transaction for both waiting for purchase and clearing up the cancel or invalid purchase Currently we only have jwsRepresentation after complete purchase, which is very limited its usage
0
0
137
Nov ’25
Unfinished transactions prevent the confirmation sheet
We feel like we're at the end of the long and treacherous process of migrating to StoreKit2. But we've hit a small snag. When testing in the sandbox environment, we've found that if we don't finish a transactions, no subsequent purchase (invoked via call to purchase or the other purchase) will produce the confirmation sheet. Is this the expected behavior? The behavior is observed on iOS26 and 18. Our app will only attempt to finish the transaction if it successfully uploads the receipt to our API. If it fails to do so for whatever reason, the transaction is left unfinished. Whilst the user is informed about this, users will commonly try again. Our concern is that since the confirmation sheet will not be shown again, users will not know they are actually paying again - most certainly not the UX we want to have. We'd much rather have our users be fully aware when they're paying us money. The reason we're choosing not to finish the transaction until our backend has received it and confirmed the receipt to be valid is that the only way the user can get their product is if the server side is aware of this and add more time to the users account. When finishing the transaction via finish immediately after the purchase() call, the confirmation sheet is shown every time after subsequent calls to purchase(). Again, is this the expected behavior both in the sandbox and the production environments? Are we doing something wrong or misusing the product API? We are somewhat stumped because technically, we could get the first confirmation for a product purchase, and then finish it only after an arbitrary amount of calls to purchase() have been made - the user will believe they will have paid only once, but we will receive however much money we can drain from their account - most certainly not the kind of app we want to develop. Please advise and best regards, Emīls
0
3
220
Nov ’25
StoreKit2 originalTransactionId
I would like to inquire about the originalTransactionId of StoreKit2. Users who purchase auto-renewal subscription products To re-purchase the same subscription item after cancellation and prior to refund If you receive a refund after cancellation and re-purchase the same subscription item If you do not renew immediately after expiration and re-purchase the same subscription after a long period of time I would like to ask if 1, 2, and 3 all use the same value as the original Transaction Id at the initial subscription. In the case of 3, if you re-purchase more than a few days after the last subscription purchase, please let me know if there are any detailed conditions such as the original Transaction Id not maintained.
0
0
81
Nov ’25
Subscribe button does nothing in App Review, but In
Hello, My app "MyCourses" (bundle id: com.ahmedbaqer.mycourses) was rejected under Guideline 2.1 because "No action followed when we tapped the button to subscribe to a course" on iPadOS 26.1. When I run the same code (version 1.0.0 (11)) from Xcode on a real device using a StoreKit configuration file (In App Purchase.storekit), the purchase flow works correctly: When I tap the "Subscribe via Apple" button, the App Store purchase sheet appears. The purchase completes successfully and unlocks the course. I use the in_app_purchase Flutter plugin and queryProductDetails to load products. However, when I install the build via TestFlight (and in App Review), tapping the same "Subscribe via Apple" button does nothing – which matches the behavior described by App Review. From my logs it looks like queryProductDetails is returning an empty productDetails list in that environment. For In‑App Purchases: I created 7 non‑consumable products in App Store Connect. Their Product IDs exactly match the IDs in my In App Purchase.storekit file (used only for local Xcode testing). All IAPs are now in "Waiting for Review" status and are linked to the iOS app version 1.0.0 (11) in the “In‑App Purchases and Subscriptions” section. At the time of the original review, some IAPs were in "Developer Action Needed / Rejected" state, so I suspect queryProductDetails may have returned no products and the reviewer saw no action after tapping the button. My questions: When IAP products are in "Waiting for Review" and linked to the app version, should queryProductDetails return them during App Review / TestFlight, or do they need to be fully approved first? Is there any additional configuration required so that the subscribe button reliably shows the App Store purchase sheet for reviewers (for example, any specific StoreKit / sandbox settings)? Are there recommended best practices to show a clearer error state when queryProductDetails returns no products, so that App Review understands this is a configuration / IAP-status issue rather than a UI bug? Any guidance from Apple engineers or other developers who faced a similar situation would be greatly appreciated. Thanks in advance.
0
0
246
Nov ’25
Product.SubscriptionInfo subscriptionPeriod does not provide the same result between the Sandbox/App Store environment and the StoreKit Testing in Xcode for a "1 week" subscription. "1 week" vs "7 days"
Hello, I noticed the Product.SubscriptionInfo subscriptionPeriod (of type Product.SubscriptionPeriod) is different for the same product between StoreKit Testing in Xcode and the sandbox/App Store (production) environment. For a “1 week” auto-renewable subscription, we get the following: StoreKit Testing in Xcode: 1 week gives a subscriptionPeriod with value of 1 and a unit of Product.SubscriptionPeriod.Unit.week Sandbox/App Store: 1 week gives a subscriptionPeriod with value of 7 and a unit of Product.SubscriptionPeriod.Unit.day This created issues in my app because I used the localizedDescription of a Product.SubscriptionPeriod to display a text similar to “$4.99 per week”. This is what I obtain with the StoreKit Testing in Xcode, but in the Sandbox/App Store environment, it displays “$4.99 per day” (because the subscriptionPeriod is “7 Days” and the unit is then .day). Obviously, this is not what I wanted to display. Other periods like “1 month”, “2 months”, “3 months”, “6 months, and “1 year”, the period provided by both StoreKit Testing and Sandbox/App Store correspond to the period unit specified in App Store Connect. In addition, I want to report that for a weekly subscription/offer or a 2 weeks offer, Product.SubscriptionInfo.subscriptionPeriod or Product.SubscriptionOffer.period == .weekly or .everyTwoWeeks is always false. We observe the following: With Sandbox or App Store live production: 1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is false (because it’s “7 days”) 1 week, Product.SubscriptionOffer.period == .weekly is false (because it’s “7 days”) 2 weeks (offer), Product.SubscriptionInfo.subscriptionPeriod == .everyTwoWeeks is false (because it’s “14 days”) 2 weeks (offer), Product.SubscriptionOffer.period == .everyTwoWeeks is false (because it’s “14 days”) But with an Xcode StoreKit configuration file: 1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is true (because it’s “1 week”) 1 week, Product.SubscriptionOffer.period == .weekly is true (because it’s “1 week”) 2 weeks, Product.SubscriptionInfo.subscriptionPeriod == . everyTwoWeeks is true (because it’s “2 weeks”) 2 weeks, Product.SubscriptionOffer.period == . everyTwoWeeks is true (because it’s “2 weeks”) So in sandbox and production, .weekly and .everyTwoWeeks is never possible. If someone from Apple could check the feedback FB19605865 🙂 Thank you Regards, Axel, @alpennec Code: do { let productIDs: [String] = ["revenueSocks_weekly_trial"] let products: [StoreKit.Product] = try await Product.products (for: productIDs) let weeklySubscription: StoreKit.Product = products.first! let displayPrice: String = weeklySubscription.displayPrice // For a weekly subscription in App Store Connect // With an Xcode StoreKit configuration file: subscriptionPeriod unit is Week (week), value is 1 → "1 Week" // With the Sandbox + App Store: subscriptionPeriod unit is Day (.day), value is 7 → "7 Days" let unitString: String = weeklySubscription.subscription!.subscriptionPeriod.unit.localizedDescription print("\(displayPrice) per \(unitString.localizedLowercase)") // StoreKit configuration file → "$4.99 per week" // Sandbox + App Store → "$4.99 per day" } catch { print(error) }
0
0
125
Nov ’25
Unable to enable eligibility for External Purchase Link APIs — seeking clarification
Hello, I am currently implementing External Purchase Link and External Purchase Custom Link and am encountering an issue where both ExternalPurchaseLink.canOpen and ExternalPurchaseCustomLink.isEligible always return false under all test conditions. I would like to confirm whether my setup is missing any required steps or whether this behavior is expected. Below are the details of my current environment and configuration: 🔧 1. Development Environment Xcode: 16.3, 16.4, 26.0 beta 4 Devices: iPhone running iOS 26.2 beta iPhone running iOS 16.7.12 macOS 15.5 (real device testing) Simulator iOS 18.0 Build Type: Local development build using a Developer Provisioning Profile Sandbox account signed in during testing 🔑 2. Entitlements (Developer site & Xcode) In Certificates → Identifiers → App ID, both capabilities are enabled: StoreKit External Purchase StoreKit External Purchase Link The .entitlements file in Xcode includes: com.apple.developer.storekit.external-purchase = YES com.apple.developer.storekit.external-purchase-link = YES The Provisioning Profile also contains both entitlements (confirmed via codesign -d --entitlements :-). 📄 3. Info.plist Configuration Both keys are configured with correct region codes according to documentation: SKExternalPurchase SKExternalPurchaseCustomLinkRegions 🌍 4. Test Storefront Device storefront verified as United States (US) or Portugal (PT) (US = target region for External Purchase Link, PT = EU region) But despite all the above configuration, both API calls consistently return false: ExternalPurchaseLink.canOpen // false ExternalPurchaseCustomLink.isEligible // false So I cannot proceed to testing the remaining flow (token retrieval, link opening, etc.) ------ Questions ------ ❓ Q1) Local Development Build Limitation Is it expected behavior that Developer-signed local builds always return canOpen = false / isEligible = false for External Purchase Link & Custom Link? Is there a technical or policy restriction that prevents eligibility in local dev builds? ❓ Q2) App Store Connect Configuration Requirement Are there mandatory App Store Connect settings (such as external purchase URLs, support URL, disclosures, or country configuration) that must be enabled before eligibility becomes true? Currently, no External Purchase Link or Custom Link menu is visible in my App Store Connect app settings. Is this menu only available after certain approvals or under specific conditions? ❓ Q3) TestFlight Requirement Do External Purchase Link and Custom Link only return eligibility = true on: TestFlight builds, or Distribution-signed builds? Or should eligibility also work on developer builds? Formal confirmation would be helpful. ❓ Q4) Developer Account Type Limitation We are using an Individual Developer Account (not Organization). Can Individual accounts fully request, test, and ship apps using: External Purchase Link External Purchase Custom Link Or are there limitations on account type? 🙏 Request We have completed all documented setup steps (Entitlements → Provisioning → Info.plist), but eligibility remains false, blocking feature validation. Please clarify which of the following is the cause: Local development builds do not support eligibility Missing App Store Connect configuration (not visible to us) Account type restriction Region rollout or entitlement approval requirement Any additional setup not documented publicly Thank you for your assistance.
2
1
308
Nov ’25
IAP Phantom Error
Trying to test IAP in sandbox. I created the test group and tester accounts. Accepted the invite downloaded the app. Signed into to sandbox in settings with the tester account. In app the purchases are failing and throwing my catch error message product couldn't be found. I decided to test it from settings/ sandbox/ manage/ initiate purchase/ but I've been getting "can't complete transaction. Something went wrong, ant this transaction couldn't be completed. Try again later" since last week. I reached out to dev support over the phone then email and they couldn't or wouldn't provide assistance. I asked my senior at work she took a look at it and confirmed I created the IAP correctly and that my sandbox account could make test purchases in apps she make but couldn't get mine to work. The storekit test work fine in xcode I just don't know what to do now.
0
0
120
Nov ’25
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
207
Nov ’25
SKTestSession.setSimulatedError() not working for .loadProducts API in iOS 26.2
Description SKTestSession.setSimulatedError() does not throw the configured error when testing StoreKit with the .loadProducts API in iOS 26.2. The simulated error is ignored, and products load successfully instead. Environment iOS: 26.2 (Simulator) Xcode: 26.2 beta 2 (Build 17C5038g) macOS: 15.6.1 Framework: StoreKitTest Testing Framework: Swift Testing base project: https://developer.apple.com/documentation/StoreKit/implementing-a-store-in-your-app-using-the-storekit-api Expected Behavior After calling session.setSimulatedError(.generic(.notAvailableInStorefront), forAPI: .loadProducts), the subsequent call to Product.products(for:) should throw StoreKitError.notAvailableInStorefront. Actual Behavior The error is not thrown. Products load successfully as if setSimulatedError() was never called. Steps to Reproduce Create an SKTestSession with a StoreKit configuration file Call session.setSimulatedError(.generic(.notAvailableInStorefront), forAPI: .loadProducts) Call Product.products(for:) with a valid product ID Observe that no error is thrown and the product loads successfully Sample Code import StoreKitTest import Testing struct SKDemoTests { let productID: String = "plus.standard" @Test func testSimulatedErrorForLoadProducts() async throws { let storeKitConfigURL = try Self.getStoreKitConfigurationURL() let session = try SKTestSession(contentsOf: storeKitConfigURL) try await session.setSimulatedError( .generic(.notAvailableInStorefront), forAPI: .loadProducts ) try await confirmation("StoreKitError throw") { throwStoreKitError in do { _ = try await Self.execute(productID: productID) } catch let error as StoreKitError { guard case StoreKitError.notAvailableInStorefront = error else { throw error } throwStoreKitError() } catch { Issue.record( "Expect StoreKitError. Error: \(error.localizedDescription)" ) } } #expect(session.allTransactions().isEmpty) } static func execute(productID: String) async throws { guard let product = try await Product.products(for: [productID]).first( where: { $0.id == productID }) else { throw NSError( domain: "SKDemoTests", code: 404, userInfo: [NSLocalizedDescriptionKey: "Product not found for ID: \(productID)"] ) } _ = product } static func getStoreKitConfigurationURL() throws -> URL { guard let bundle = Bundle(identifier: "your.bundle.identifier"), let url = bundle.url(forResource: "Products", withExtension: "storekit") else { fatalError("StoreKit configuration not found") } return url } } Test Result The test fails because the expected StoreKitError.notAvailableInStorefront is never thrown. Question Is this a known issue in iOS 26.2 / Xcode 26.2 beta 2, or is there a different approach required for simulating errors with SKTestSession in this version? Any guidance would be appreciated. Feedback Assistant report: FB21110809
2
2
293
Nov ’25
StoreKit 2: currentEntitlements always returns empty on Restore...
I tried deleting the configuration file, but I ended up with an alert asking me to sign in with my sandbox ID. I did, and it returned an error: "Request Canceled". It is as if the purchase function doesn't update the currentEntitlements. This is my purchase function. Am I doing something wrong? func purchase(_ product: Product) async throws { let result = try await product.purchase() switch result { case .success(let verificationResult): switch verificationResult { case .verified(let transaction): // Successful purchase - deliver content await updatePurchasedProducts() await transaction.finish() // Go back to the map integratePlanAhead() case .unverified(_, let error): // Purchase failed verification throw error } case .userCancelled: // User cancelled the purchase break case .pending: // Purchase is pending (e.g., parental approval needed) break @unknown default: break } } It looks like purchases are never updated for my sandbox user... Thanks for any help :)
1
0
131
Nov ’25
Auto renewable subsction, auto renews to different product id
I need help understanding how the In-App purchase subscription works within the same subscription group and how the Order plays a role at the time of auto-renewal. In my case, I have 5 in-app products in the same group as given below with their Order, Order Product ---------------------- 1 Gold Annual 2 Gold Monthly 3 Silver Annual Old, 3 Silver Annual New 4 Silver Monthly One user purchased Silver annual New, at the time of expiry, after a year, it auto-renewed to Silver annual Old. My understanding is that if a user has purchased Silver annual New, at the time of renewal, it should renew with the same product, not with different product id. Is this behaviour expected? Is there any official document which can explain this behaviour? Note: There was no Order given before, recently we have changed the Order to manage Upgrade and Downgrade for In-App subscriptions.
0
0
78
Nov ’25
StoreKit 2 not loading subscription products
Hi everyone, I’m seeing a strange behavior with StoreKit 2 and I’d like to know if anyone else experienced this. My subscription group “ROTA Premium” (Monthly + Annual) is currently Waiting for Review in App Store Connect. What works In Xcode’s StoreKit sandbox, everything loads correctly: Products appear Trial starts Purchases work What doesn’t work In TestFlight and App Review, StoreKit 2 returns zero products, so my paywall shows: “No subscription options found.” There are: No geo restrictions No backend No VPN/IP filtering Paid Apps Agreement is accepted App Review said the device was online, but couldn’t give technical help. My question Has anyone seen StoreKit 2 fail to load subscription products when the subscription group is still in Waiting for Review? Do subscription groups need to be reviewed together with the app version for StoreKit 2 to return them in TestFlight/App Review? Any advice would be appreciated! Thanks.
0
1
99
Nov ’25
SubscriptionStoreView - Restoring Subscriptions
I'm using code similar to the following to conditionally show the SubscriptionStoreView and the .storeButton(.visible, for: .restorePurchases) modifier is used to allow the user to restore an existing subscription. How can I listen for events that would allow me to close this view once the subscription is restored? The .onInAppPurchaseCompletion closure does not handle this and it also appears that listening for results in Transaction.currentEntitlements also doesn't handle the fact that a subscription is restored. Any guidance on how to determine if the subscription has been restored would be greatly appreciated. Finally, how can this be tested effectively in both TestFlight and in Xcode with the simulator. if subscriptionManager.subscription == .none { SubscriptionStoreView(groupID: "1234567") { SubscriptionMarketingView(transparency: false) .containerBackground(for: .subscriptionStoreFullHeight) { GradientBackground() } } .backgroundStyle(.clear) .storeButton(.visible, for: .restorePurchases) .storeButton(.visible, for: .redeemCode) .onInAppPurchaseCompletion { product, result in Task { await subscriptionManager.entitlements() } } }
0
1
133
Nov ’25
Switching App Store Server Notifications from V1 → V2 — what happens to existing subscriptions?
Hello — quick question about App Store Server Notifications migration. We have a live app using Production V1 notifications for recurring in-app subscriptions. We plan to switch the Production webhook to V2. After the switch: Will notifications for existing subscriptions be delivered in V1 format, V2 format, or will it depend (e.g., queued V1 retries vs new V2 deliveries)? If V1 retries are queued, how long should we expect overlap/retries to continue? Any recommended cutover best practices (support both formats, revert process, etc.)? Happy to share additional details. Thanks.
Replies
1
Boosts
0
Views
219
Activity
Dec ’25
Cannot repurchase subscription SKU — StoreKit keeps returning old expired transaction
Some users cannot repurchase a subscription SKU after it has expired. Flow: User previously subscribed. User canceled and the subscription fully expired. After weeks, user reinstalls the app and taps the same SKU. StoreKit does not create a new purchase transaction. Instead, StoreKit always returns the old expired transaction in updatedTransactions. Therefore, the user is permanently unable to purchase the SKU again. We have already tried: Adding payment observer at app launch Calling finishTransaction for all transactions Clearing queue at startup SKReceiptRefreshRequest Server-side verifyReceipt Ensuring subscription is truly expired (not in grace/retry) Not calling restoreCompletedTransactions None of these resolved the issue. StoreKit still only sends the old transaction and never generates a new one. Expected behavior: A new purchase transaction should be created when user taps the expired subscription SKU. Actual behavior: StoreKit repeatedly pushes the old expired transaction, blocking new purchases. We can provide: Some users cannot repurchase a subscription SKU after it has expired. Flow: User previously subscribed. User canceled and the subscription fully expired. After weeks, user reinstalls the app and taps the same SKU. StoreKit does not create a new purchase transaction. Instead, StoreKit always returns the old expired transaction in updatedTransactions. Therefore, the user is permanently unable to purchase the SKU again. We have already tried: Adding payment observer at app launch Calling finishTransaction for all transactions Clearing queue at startup SKReceiptRefreshRequest Server-side verifyReceipt Ensuring subscription is truly expired (not in grace/retry) Not calling restoreCompletedTransactions None of these resolved the issue. StoreKit still only sends the old transaction and never generates a new one. Expected behavior: A new purchase transaction should be created when user taps the expired subscription SKU. Actual behavior: StoreKit repeatedly pushes the old expired transaction, blocking new purchases. We can provide: Affected user’s base64 receipt verifyReceipt full response Transaction logs (transactionIdentifier, original_transaction_id, productIdentifier, state) Please help investigate why StoreKit is not allowing a new subscription purchase. Affected user’s base64 receipt verifyReceipt full response Transaction logs (transactionIdentifier, original_transaction_id, productIdentifier, state) Please help investigate why StoreKit is not allowing a new subscription purchase.
Replies
1
Boosts
0
Views
185
Activity
Dec ’25
RequestReviewAction never triggering rating dialog
Hello, We are having an issue with the RequestReview API and were hoping to get some help. We know that there is no guarantee that the in-app review modal will show and we know that there are 3 circumstances in which it will definitely not appear: if the user has turned off in-app review/ratings in their settings if the user has submitted a review for that app on that device within the last 365 days if the user has been asked for a review >3 times in the last 365 days When testing our implementation, every single one of our testers did not receive the rating modal despite the fact that we had all our testers turn on the app rating setting and that we have never asked for reviews from our app before. So that seems suspicious. While it is possible that something is up with our code (and I have provided some snippets below) we are also concerned that apple maybe is suppressing it for another reason. We really want to go live with our app review code but unfortunately we are not able to get confidence that it will ever appear for the user. Can you please help us understand why this isn't working. The code: We are using the SwiftUI approach to requesting review. Here are some relevant code snippets Important to note, we have a modal that appears when the user is in our list of active, targeted users. If they tap yes on this modal, it should show the in app rate the app system modal. If they tap no, we present them with an airship survey so that they can give feedback. Here is the code for the Yes button action: @Environment(\.requestReview) private var requestReview private var yesButton: some View { Button( action: { dismiss() requestReview() }, label: { Text(Lingua.General.appRateFirstButton) .regularParagraph() .frame(width: 180, height: 35) } ) .customButtonStyle( foregroundColor: .black, backgroundColor: Color(.powderBlue), radius: 36 ) } and this is the logic we use to determine whether we want to show them the modal in the first place. Obviously, a lot of this code leads to deeper areas in our logic and code but to give an idea... private func showAppRateModalIfNeeded() { if preferencesManager.appRateReviewShown == nil, accountManager.userAccount?.permissions.rateTheApp == true { let appReviewModalVC = UIHostingController(rootView: AppReviewModal()) appReviewModalVC.view.backgroundColor = .init(white: 0, alpha: 0.6) appReviewModalVC.modalPresentationStyle = .overFullScreen appReviewModalVC.modalTransitionStyle = .crossDissolve parentVC?.navigationController?.present(appReviewModalVC, animated: true) preferencesManager.appRateReviewShown = true } } When testing in debug, we do find that the modal appears and works as expected. However, on release builds nobody is able to trigger it. Why? Are we doing something wrong here or is Apple just suppressing it. We are thinking about implementing the button taking the user directly into the app store review but we'd prefer to do the lower-friction dialog in-app if we can get it work so the user doesn't get sent out of the app.
Replies
2
Boosts
0
Views
178
Activity
Dec ’25
Apple Pay v2 (signedTransactionInfo) : how to verify new token format and migrate from legacy EC_v1?
I’m updating a legacy application that used Apple Pay v1 token format, and in my new revamped version I’m now receiving the newer Apple Pay v2 format. The old (v1) payload looked like this: php { "version": "EC_v1", "data": "...", "signature": "...", "header": { "ephemeralPublicKey": "...", "publicKeyHash": "...", "transactionId": "..." } } In the new revamp (v2), Apple Pay returns this instead: php { "signedTransactionInfo": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF..." } From what I understand: v1 tokens were elliptic-curve encrypted JSON objects containing a header and signature. v2 tokens seem to be JWS (JSON Web Signature) strings using the ES256 algorithm, possibly containing transaction and subscription details inside. Questions Is there any official Apple documentation or migration note explaining the move from EC_v1 → signedTransactionInfo? How should I verify or decode the new signedTransactionInfo payload? Should the verification now use Apple’s public keys instead of the legacy Merchant ID certificate? Are there any example implementations or SDKs that can handle both v1 and v2 formats during migration? Is there a recommended way to maintain backward compatibility while transitioning existing users? Goal Ensure that my revamped app can handle Apple Pay v2 tokens securely while keeping the legacy v1 integration functional until all users are migrated.
Replies
1
Boosts
0
Views
520
Activity
Nov ’25
Ask to buy pending state lacking transaction object
StoreKit ask to buy should have more data in pending state. When user try to purchase ask to buy, we should get at least transactionID, product itself, and time that user start the request. So we can keep track of the whole transaction flow jwsRepresentation should always available for every state, actually even failing state. And should attach state inside of it. Instead of only available after verified purchase. So we can use transactionID and everything relate to transaction for both waiting for purchase and clearing up the cancel or invalid purchase Currently we only have jwsRepresentation after complete purchase, which is very limited its usage
Replies
0
Boosts
0
Views
137
Activity
Nov ’25
Unfinished transactions prevent the confirmation sheet
We feel like we're at the end of the long and treacherous process of migrating to StoreKit2. But we've hit a small snag. When testing in the sandbox environment, we've found that if we don't finish a transactions, no subsequent purchase (invoked via call to purchase or the other purchase) will produce the confirmation sheet. Is this the expected behavior? The behavior is observed on iOS26 and 18. Our app will only attempt to finish the transaction if it successfully uploads the receipt to our API. If it fails to do so for whatever reason, the transaction is left unfinished. Whilst the user is informed about this, users will commonly try again. Our concern is that since the confirmation sheet will not be shown again, users will not know they are actually paying again - most certainly not the UX we want to have. We'd much rather have our users be fully aware when they're paying us money. The reason we're choosing not to finish the transaction until our backend has received it and confirmed the receipt to be valid is that the only way the user can get their product is if the server side is aware of this and add more time to the users account. When finishing the transaction via finish immediately after the purchase() call, the confirmation sheet is shown every time after subsequent calls to purchase(). Again, is this the expected behavior both in the sandbox and the production environments? Are we doing something wrong or misusing the product API? We are somewhat stumped because technically, we could get the first confirmation for a product purchase, and then finish it only after an arbitrary amount of calls to purchase() have been made - the user will believe they will have paid only once, but we will receive however much money we can drain from their account - most certainly not the kind of app we want to develop. Please advise and best regards, Emīls
Replies
0
Boosts
3
Views
220
Activity
Nov ’25
App 内购买项目对接
最近我们有个应用要对接App 内购买项目,有什么好的资料或者demo提供一下吗?
Replies
0
Boosts
1
Views
98
Activity
Nov ’25
StoreKit2 originalTransactionId
I would like to inquire about the originalTransactionId of StoreKit2. Users who purchase auto-renewal subscription products To re-purchase the same subscription item after cancellation and prior to refund If you receive a refund after cancellation and re-purchase the same subscription item If you do not renew immediately after expiration and re-purchase the same subscription after a long period of time I would like to ask if 1, 2, and 3 all use the same value as the original Transaction Id at the initial subscription. In the case of 3, if you re-purchase more than a few days after the last subscription purchase, please let me know if there are any detailed conditions such as the original Transaction Id not maintained.
Replies
0
Boosts
0
Views
81
Activity
Nov ’25
Subscribe button does nothing in App Review, but In
Hello, My app "MyCourses" (bundle id: com.ahmedbaqer.mycourses) was rejected under Guideline 2.1 because "No action followed when we tapped the button to subscribe to a course" on iPadOS 26.1. When I run the same code (version 1.0.0 (11)) from Xcode on a real device using a StoreKit configuration file (In App Purchase.storekit), the purchase flow works correctly: When I tap the "Subscribe via Apple" button, the App Store purchase sheet appears. The purchase completes successfully and unlocks the course. I use the in_app_purchase Flutter plugin and queryProductDetails to load products. However, when I install the build via TestFlight (and in App Review), tapping the same "Subscribe via Apple" button does nothing – which matches the behavior described by App Review. From my logs it looks like queryProductDetails is returning an empty productDetails list in that environment. For In‑App Purchases: I created 7 non‑consumable products in App Store Connect. Their Product IDs exactly match the IDs in my In App Purchase.storekit file (used only for local Xcode testing). All IAPs are now in "Waiting for Review" status and are linked to the iOS app version 1.0.0 (11) in the “In‑App Purchases and Subscriptions” section. At the time of the original review, some IAPs were in "Developer Action Needed / Rejected" state, so I suspect queryProductDetails may have returned no products and the reviewer saw no action after tapping the button. My questions: When IAP products are in "Waiting for Review" and linked to the app version, should queryProductDetails return them during App Review / TestFlight, or do they need to be fully approved first? Is there any additional configuration required so that the subscribe button reliably shows the App Store purchase sheet for reviewers (for example, any specific StoreKit / sandbox settings)? Are there recommended best practices to show a clearer error state when queryProductDetails returns no products, so that App Review understands this is a configuration / IAP-status issue rather than a UI bug? Any guidance from Apple engineers or other developers who faced a similar situation would be greatly appreciated. Thanks in advance.
Replies
0
Boosts
0
Views
246
Activity
Nov ’25
Product.SubscriptionInfo subscriptionPeriod does not provide the same result between the Sandbox/App Store environment and the StoreKit Testing in Xcode for a "1 week" subscription. "1 week" vs "7 days"
Hello, I noticed the Product.SubscriptionInfo subscriptionPeriod (of type Product.SubscriptionPeriod) is different for the same product between StoreKit Testing in Xcode and the sandbox/App Store (production) environment. For a “1 week” auto-renewable subscription, we get the following: StoreKit Testing in Xcode: 1 week gives a subscriptionPeriod with value of 1 and a unit of Product.SubscriptionPeriod.Unit.week Sandbox/App Store: 1 week gives a subscriptionPeriod with value of 7 and a unit of Product.SubscriptionPeriod.Unit.day This created issues in my app because I used the localizedDescription of a Product.SubscriptionPeriod to display a text similar to “$4.99 per week”. This is what I obtain with the StoreKit Testing in Xcode, but in the Sandbox/App Store environment, it displays “$4.99 per day” (because the subscriptionPeriod is “7 Days” and the unit is then .day). Obviously, this is not what I wanted to display. Other periods like “1 month”, “2 months”, “3 months”, “6 months, and “1 year”, the period provided by both StoreKit Testing and Sandbox/App Store correspond to the period unit specified in App Store Connect. In addition, I want to report that for a weekly subscription/offer or a 2 weeks offer, Product.SubscriptionInfo.subscriptionPeriod or Product.SubscriptionOffer.period == .weekly or .everyTwoWeeks is always false. We observe the following: With Sandbox or App Store live production: 1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is false (because it’s “7 days”) 1 week, Product.SubscriptionOffer.period == .weekly is false (because it’s “7 days”) 2 weeks (offer), Product.SubscriptionInfo.subscriptionPeriod == .everyTwoWeeks is false (because it’s “14 days”) 2 weeks (offer), Product.SubscriptionOffer.period == .everyTwoWeeks is false (because it’s “14 days”) But with an Xcode StoreKit configuration file: 1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is true (because it’s “1 week”) 1 week, Product.SubscriptionOffer.period == .weekly is true (because it’s “1 week”) 2 weeks, Product.SubscriptionInfo.subscriptionPeriod == . everyTwoWeeks is true (because it’s “2 weeks”) 2 weeks, Product.SubscriptionOffer.period == . everyTwoWeeks is true (because it’s “2 weeks”) So in sandbox and production, .weekly and .everyTwoWeeks is never possible. If someone from Apple could check the feedback FB19605865 🙂 Thank you Regards, Axel, @alpennec Code: do { let productIDs: [String] = ["revenueSocks_weekly_trial"] let products: [StoreKit.Product] = try await Product.products (for: productIDs) let weeklySubscription: StoreKit.Product = products.first! let displayPrice: String = weeklySubscription.displayPrice // For a weekly subscription in App Store Connect // With an Xcode StoreKit configuration file: subscriptionPeriod unit is Week (week), value is 1 → "1 Week" // With the Sandbox + App Store: subscriptionPeriod unit is Day (.day), value is 7 → "7 Days" let unitString: String = weeklySubscription.subscription!.subscriptionPeriod.unit.localizedDescription print("\(displayPrice) per \(unitString.localizedLowercase)") // StoreKit configuration file → "$4.99 per week" // Sandbox + App Store → "$4.99 per day" } catch { print(error) }
Replies
0
Boosts
0
Views
125
Activity
Nov ’25
Unable to enable eligibility for External Purchase Link APIs — seeking clarification
Hello, I am currently implementing External Purchase Link and External Purchase Custom Link and am encountering an issue where both ExternalPurchaseLink.canOpen and ExternalPurchaseCustomLink.isEligible always return false under all test conditions. I would like to confirm whether my setup is missing any required steps or whether this behavior is expected. Below are the details of my current environment and configuration: 🔧 1. Development Environment Xcode: 16.3, 16.4, 26.0 beta 4 Devices: iPhone running iOS 26.2 beta iPhone running iOS 16.7.12 macOS 15.5 (real device testing) Simulator iOS 18.0 Build Type: Local development build using a Developer Provisioning Profile Sandbox account signed in during testing 🔑 2. Entitlements (Developer site & Xcode) In Certificates → Identifiers → App ID, both capabilities are enabled: StoreKit External Purchase StoreKit External Purchase Link The .entitlements file in Xcode includes: com.apple.developer.storekit.external-purchase = YES com.apple.developer.storekit.external-purchase-link = YES The Provisioning Profile also contains both entitlements (confirmed via codesign -d --entitlements :-). 📄 3. Info.plist Configuration Both keys are configured with correct region codes according to documentation: SKExternalPurchase SKExternalPurchaseCustomLinkRegions 🌍 4. Test Storefront Device storefront verified as United States (US) or Portugal (PT) (US = target region for External Purchase Link, PT = EU region) But despite all the above configuration, both API calls consistently return false: ExternalPurchaseLink.canOpen // false ExternalPurchaseCustomLink.isEligible // false So I cannot proceed to testing the remaining flow (token retrieval, link opening, etc.) ------ Questions ------ ❓ Q1) Local Development Build Limitation Is it expected behavior that Developer-signed local builds always return canOpen = false / isEligible = false for External Purchase Link & Custom Link? Is there a technical or policy restriction that prevents eligibility in local dev builds? ❓ Q2) App Store Connect Configuration Requirement Are there mandatory App Store Connect settings (such as external purchase URLs, support URL, disclosures, or country configuration) that must be enabled before eligibility becomes true? Currently, no External Purchase Link or Custom Link menu is visible in my App Store Connect app settings. Is this menu only available after certain approvals or under specific conditions? ❓ Q3) TestFlight Requirement Do External Purchase Link and Custom Link only return eligibility = true on: TestFlight builds, or Distribution-signed builds? Or should eligibility also work on developer builds? Formal confirmation would be helpful. ❓ Q4) Developer Account Type Limitation We are using an Individual Developer Account (not Organization). Can Individual accounts fully request, test, and ship apps using: External Purchase Link External Purchase Custom Link Or are there limitations on account type? 🙏 Request We have completed all documented setup steps (Entitlements → Provisioning → Info.plist), but eligibility remains false, blocking feature validation. Please clarify which of the following is the cause: Local development builds do not support eligibility Missing App Store Connect configuration (not visible to us) Account type restriction Region rollout or entitlement approval requirement Any additional setup not documented publicly Thank you for your assistance.
Replies
2
Boosts
1
Views
308
Activity
Nov ’25
IAP Phantom Error
Trying to test IAP in sandbox. I created the test group and tester accounts. Accepted the invite downloaded the app. Signed into to sandbox in settings with the tester account. In app the purchases are failing and throwing my catch error message product couldn't be found. I decided to test it from settings/ sandbox/ manage/ initiate purchase/ but I've been getting "can't complete transaction. Something went wrong, ant this transaction couldn't be completed. Try again later" since last week. I reached out to dev support over the phone then email and they couldn't or wouldn't provide assistance. I asked my senior at work she took a look at it and confirmed I created the IAP correctly and that my sandbox account could make test purchases in apps she make but couldn't get mine to work. The storekit test work fine in xcode I just don't know what to do now.
Replies
0
Boosts
0
Views
120
Activity
Nov ’25
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
207
Activity
Nov ’25
In-App Rating Prompt can't be dismissed in iOS 26.1
The app review prompt on iOS/iPadOS 26.1 has the "Not Now" button greyed out: On iOS/iPadOS 26.0, this was working: Before filing a radar, is there anything I'm missing? The only way to dismiss it is to tap a star rating and then a Cancel button appears which lets you dismiss it without reviewing.
Replies
1
Boosts
1
Views
223
Activity
Nov ’25
SKTestSession.setSimulatedError() not working for .loadProducts API in iOS 26.2
Description SKTestSession.setSimulatedError() does not throw the configured error when testing StoreKit with the .loadProducts API in iOS 26.2. The simulated error is ignored, and products load successfully instead. Environment iOS: 26.2 (Simulator) Xcode: 26.2 beta 2 (Build 17C5038g) macOS: 15.6.1 Framework: StoreKitTest Testing Framework: Swift Testing base project: https://developer.apple.com/documentation/StoreKit/implementing-a-store-in-your-app-using-the-storekit-api Expected Behavior After calling session.setSimulatedError(.generic(.notAvailableInStorefront), forAPI: .loadProducts), the subsequent call to Product.products(for:) should throw StoreKitError.notAvailableInStorefront. Actual Behavior The error is not thrown. Products load successfully as if setSimulatedError() was never called. Steps to Reproduce Create an SKTestSession with a StoreKit configuration file Call session.setSimulatedError(.generic(.notAvailableInStorefront), forAPI: .loadProducts) Call Product.products(for:) with a valid product ID Observe that no error is thrown and the product loads successfully Sample Code import StoreKitTest import Testing struct SKDemoTests { let productID: String = "plus.standard" @Test func testSimulatedErrorForLoadProducts() async throws { let storeKitConfigURL = try Self.getStoreKitConfigurationURL() let session = try SKTestSession(contentsOf: storeKitConfigURL) try await session.setSimulatedError( .generic(.notAvailableInStorefront), forAPI: .loadProducts ) try await confirmation("StoreKitError throw") { throwStoreKitError in do { _ = try await Self.execute(productID: productID) } catch let error as StoreKitError { guard case StoreKitError.notAvailableInStorefront = error else { throw error } throwStoreKitError() } catch { Issue.record( "Expect StoreKitError. Error: \(error.localizedDescription)" ) } } #expect(session.allTransactions().isEmpty) } static func execute(productID: String) async throws { guard let product = try await Product.products(for: [productID]).first( where: { $0.id == productID }) else { throw NSError( domain: "SKDemoTests", code: 404, userInfo: [NSLocalizedDescriptionKey: "Product not found for ID: \(productID)"] ) } _ = product } static func getStoreKitConfigurationURL() throws -> URL { guard let bundle = Bundle(identifier: "your.bundle.identifier"), let url = bundle.url(forResource: "Products", withExtension: "storekit") else { fatalError("StoreKit configuration not found") } return url } } Test Result The test fails because the expected StoreKitError.notAvailableInStorefront is never thrown. Question Is this a known issue in iOS 26.2 / Xcode 26.2 beta 2, or is there a different approach required for simulating errors with SKTestSession in this version? Any guidance would be appreciated. Feedback Assistant report: FB21110809
Replies
2
Boosts
2
Views
293
Activity
Nov ’25
StoreKit 2: currentEntitlements always returns empty on Restore...
I tried deleting the configuration file, but I ended up with an alert asking me to sign in with my sandbox ID. I did, and it returned an error: "Request Canceled". It is as if the purchase function doesn't update the currentEntitlements. This is my purchase function. Am I doing something wrong? func purchase(_ product: Product) async throws { let result = try await product.purchase() switch result { case .success(let verificationResult): switch verificationResult { case .verified(let transaction): // Successful purchase - deliver content await updatePurchasedProducts() await transaction.finish() // Go back to the map integratePlanAhead() case .unverified(_, let error): // Purchase failed verification throw error } case .userCancelled: // User cancelled the purchase break case .pending: // Purchase is pending (e.g., parental approval needed) break @unknown default: break } } It looks like purchases are never updated for my sandbox user... Thanks for any help :)
Replies
1
Boosts
0
Views
131
Activity
Nov ’25
SKAdNetwork Postback URL Check
Hi folks, How can I check the URL we have configured for SKAdNetwork install postback requests? Sadly we've lost any record of this via email on our end, and Apple developer support have asked that I reach out via the forums.
Replies
0
Boosts
0
Views
52
Activity
Nov ’25
Auto renewable subsction, auto renews to different product id
I need help understanding how the In-App purchase subscription works within the same subscription group and how the Order plays a role at the time of auto-renewal. In my case, I have 5 in-app products in the same group as given below with their Order, Order Product ---------------------- 1 Gold Annual 2 Gold Monthly 3 Silver Annual Old, 3 Silver Annual New 4 Silver Monthly One user purchased Silver annual New, at the time of expiry, after a year, it auto-renewed to Silver annual Old. My understanding is that if a user has purchased Silver annual New, at the time of renewal, it should renew with the same product, not with different product id. Is this behaviour expected? Is there any official document which can explain this behaviour? Note: There was no Order given before, recently we have changed the Order to manage Upgrade and Downgrade for In-App subscriptions.
Replies
0
Boosts
0
Views
78
Activity
Nov ’25
StoreKit 2 not loading subscription products
Hi everyone, I’m seeing a strange behavior with StoreKit 2 and I’d like to know if anyone else experienced this. My subscription group “ROTA Premium” (Monthly + Annual) is currently Waiting for Review in App Store Connect. What works In Xcode’s StoreKit sandbox, everything loads correctly: Products appear Trial starts Purchases work What doesn’t work In TestFlight and App Review, StoreKit 2 returns zero products, so my paywall shows: “No subscription options found.” There are: No geo restrictions No backend No VPN/IP filtering Paid Apps Agreement is accepted App Review said the device was online, but couldn’t give technical help. My question Has anyone seen StoreKit 2 fail to load subscription products when the subscription group is still in Waiting for Review? Do subscription groups need to be reviewed together with the app version for StoreKit 2 to return them in TestFlight/App Review? Any advice would be appreciated! Thanks.
Replies
0
Boosts
1
Views
99
Activity
Nov ’25
SubscriptionStoreView - Restoring Subscriptions
I'm using code similar to the following to conditionally show the SubscriptionStoreView and the .storeButton(.visible, for: .restorePurchases) modifier is used to allow the user to restore an existing subscription. How can I listen for events that would allow me to close this view once the subscription is restored? The .onInAppPurchaseCompletion closure does not handle this and it also appears that listening for results in Transaction.currentEntitlements also doesn't handle the fact that a subscription is restored. Any guidance on how to determine if the subscription has been restored would be greatly appreciated. Finally, how can this be tested effectively in both TestFlight and in Xcode with the simulator. if subscriptionManager.subscription == .none { SubscriptionStoreView(groupID: "1234567") { SubscriptionMarketingView(transparency: false) .containerBackground(for: .subscriptionStoreFullHeight) { GradientBackground() } } .backgroundStyle(.clear) .storeButton(.visible, for: .restorePurchases) .storeButton(.visible, for: .redeemCode) .onInAppPurchaseCompletion { product, result in Task { await subscriptionManager.entitlements() } } }
Replies
0
Boosts
1
Views
133
Activity
Nov ’25