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

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
18
16h
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.
0
0
25
1d
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?
0
0
18
1d
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
0
1
16
5d
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
39
5d
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
33
1w
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
42
1w
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
71
1w
In-App Purchases rejected + Reviewer cannot complete purchase although sandbox works fine (StoreKit2)
Hi everyone, I’m experiencing an issue with In-App Purchases during App Review. What works My consumable IAP products load correctly using StoreKit2. TestFlight (sandbox) purchases work perfectly. Localizations are filled in and valid. Paid Apps Agreement, banking, and tax forms are active. IAP products are properly created in App Store Connect and marked as “Developer Action Needed” only because they wait for approval with the new binary. What fails During review I received: “We found that your in-app purchase products exhibited one or more bugs which create a poor user experience. Specifically, we were not able to complete a purchase.” They didn’t provide any more technical details. Additional context The StoreKit configuration file is not included in the app archive. Product identifiers perfectly match those in App Store Connect. StoreKit2 purchase() works as expected on TestFlight. The app does not use server-side receipt validation - purchases are handled purely through StoreKit2 APIs, as recommended. My questions What could cause a situation where TestFlight purchases work but App Review cannot complete a purchase? Does Apple expect server-side receipt validation even for simple one-time consumables? Could there be a delay or sync issue causing IAP products to not be available to the reviewer yet? Is there anything I should check on the App Store Connect side beyond what I already verified? Any help or hints would be greatly appreciated - I’m stuck because everything works in sandbox but fails only for reviewers. Thanks!
0
0
75
1w
In app purchase related doubts
My app offers auto renewable subscriptions, I have couple of questions regarding how to model the subscriptions at server side, Is originalTransactionId will ever change for a subscription? Will it stay same in case of subscription upgrade/downgrade/crossgrade? If it changes on product change then how do i keep track that the subscription was a continuous subscription and not a new one? Is the webhook payload contains any identifier of which apple account purchase the subscription? I am having issues maintaining sync between the app account's current subscription and the local apple account's subscription, is there any doc regarding this? Will be really helpful
0
0
24
1w
verifyReceipt endpoint failing on occassion
I am finding that the verifyReceipt endpoint used to verify a receipt is failing on occassion starting around October 27, 2015. I realize this API is deprecated. I am using cURL to call verifyReceipt. The specific errors are 52 - Empty reply from server and 56 - Connection closed abruptly. This indicates an issue with Apple's server as I understand it. Is anyone else experiencing this as well?
0
0
32
1w
What happens on device after RESCIND_CONSENT notification?
In a recent update to developer news, Apple posted more details about compliance tools for the new laws coming into effect in Texas on Jan 1. https://developer.apple.com/news/?id=2ezb6jhj It is not explicitly stated in the news update or documentation but when the new RESCIND_CONSENT notification is sent to the developer, what happens on the child account devices? Does the app just disappear. Does the developer need to take any action in the App itself? https://developer.apple.com/documentation/appstoreservernotifications/notificationtype Thanks, Eric
0
1
55
2w
StoreKit v2: autoRenewStatus returns 0 right after purchase on iOS 26.1
Hi everyone, I’m implementing subscriptions using StoreKit v2, and I’ve noticed a behavior change starting with iOS 26.1. I’d like to ask if anyone else has experienced the same issue. ■ Issue Immediately after purchasing a new subscription, the value of auto_renew_status (or autoRenewStatus) returned in the receipt is 0 (auto-renew OFF). This issue occurs on iOS 26.1. On iOS 26.0 and earlier, the same parameter returned 1 (auto-renew ON) right after purchase. Sometimes, after executing a “restore” operation, the value changes to 1 later. Since we’ve been using this parameter to determine whether a user’s subscription is active or not, the current behavior is causing some difficulties on our end. ■ Questions Has anyone else observed this issue (where autoRenewStatus is 0 immediately after purchase on iOS 26.1 or later)? How are you handling or working around this behavior in your implementation? If autoRenewStatus is unreliable, we’re considering determining the subscription state based on receipt fields instead. Would this approach be reasonable? "status" is 1 (indicates active subscription) "expire_time" is in the future "deleted_at" is null If anyone has encountered the same behavior or knows of any Apple-recommended implementation approach, I’d really appreciate your insights. Thank you! 🙏
0
0
48
2w
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
79
2w
Delete TestFlight in-app purchase record by using a real ID.
Hey guys, somehow I used my real ID(not sandbox test ID) to purchase a non-consumable item in the TestFlight package, no actual payment was made, but this payment record cannot be erased. Even though I know the transaction ID, I cannot initiate a refund like using refundRequestSheet(). Does anyone know how to deal with this, or there is no way to solve it?
0
0
97
2w
in-App Purchase - Showing Product Not available
Hello Fellow Developers, I recently built a simple craft related app called "Genie Crystals" with a landing page. there is a button on landing page which redirects to a main template generator page. Here the user can play with the parameters and create an output which can be exported. to export there is an unlock button which is linked to the in-app purchase configured in the app. Initially it was not capturing price properly so I modified the code slightly to keep the button in disabled state until the product details got fetched in background asynchronously. But when I released the app and downloaded it on a different device at the time of load itself, I am getting the alert - product not available. I have used correct product Id in the program. I have confirmed that. I think I am missing something. Any help will be appreciated. I am new to this so if I need to share any additional information kindly let me know. Thanks.
1
0
32
2w
Is the following subscription cancellation flow possible for an iOS in-app subscription?
Is the following subscription cancellation flow possible for an iOS in-app subscription? (Note: This is during the feature planning stage, not actual app deployment.) Planned user flow: User taps the “Cancel Subscription” button Display a “Wait a moment!” screen showing how much the user has enjoyed BFLIX content (to encourage retention) User taps “Proceed to Cancel” Collect cancellation reason from the user Redirect the user to the Apple subscription management page to complete cancellation Can this flow be implemented under Apple’s current in-app purchase and App Store Review guidelines?
0
0
15
2w