The same store kit configuration file works in iOS and iPadOS, but not in macOS for the same multi platform application project with a single scheme.
Here’s a more detailed write up with the sample code and screenshots. When the simple app is run on
https://www.reddit.com/r/SwiftUI/s/KJsYcggWOa
EDIT: I’m using Xcode 16.4
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
For years I've been using Receigen for receipt verification for the Mac App Store build of my application. However, with the deprecation of exit code 173, I am moving to StoreKit-based verification and have a couple of questions.
I have followed the instructions from https://developer.apple.com/documentation/storekit/apptransaction/shared and have something like this (simplified):
Swift:
@objc class ValidateReceipt: NSObject {
@objc func validate() async -> Bool {
do {
let verificationResult = try await AppTransaction.shared
switch verificationResult {
case .verified(_ /*let appTransaction*/):
// StoreKit verified that the user purchased this app and
// the properties in the AppTransaction instance
return true;
default:
// The app transaction didn't pass StoreKit's verification
return false;
}
}
catch {
// Handle errors
return false;
}
}
}
Objective-C:
ValidateReceipt *validateReceipt = [[ValidateReceipt alloc] init];
[validateReceipt validateWithCompletionHandler:^(BOOL result) {
if (result)
{
// Successful app purchase validation
}
else
{
// App purchase validation failure
}
}];
Thing is, I always get a valid result, i.e., in ValidReceipt.validate(), the case .verified block always runs. Even when exporting a new release build of my app and running it (without any _MASReceipt).
When using exit code 173, an .app without a _MASReceipt would prompt for app store login. Nothing of the sort happens now.
Am I misunderstanding the documentation / doing something wrong / missing something obvious?
Unsure if this has been reported before, but I'm seeing a specific scenario where Apple is sending back faulty information in App Store Server Notifications.
When users have payment failures that result in the membership expiring, and then reactivate later on with a different subscription, they are given a new originalTransactionId, yet we have three cases where we receive messages about the old originalTransactionId, indicating that after the user recovers their subscription, Apple is resurrecting the old subscription and treating it as if it is active BUT ultimately decides to deactivate it.
Here is a sample screenshot of an impacted user. We only have three month and annual plans.
Timeline:
March 21st:
This user signed up for a 3 Month Plan
June 21st:
This user fails to pay
July 7th:
After our 16 day grace period, this user loses access
July 29th:
This user sees they lost access and repurchase
Augsut 19th:
Their membership is deactivated (long before their 3 Month Subscription is up)
For further verification I've also attached a record of all the payloads we've received from Apple for this user.
Please let me know if you need any more details to fix this bug OR if it has already been fixed! Thank you.
user_webhook_data_sanitized.csv
I would like to know if it is allowed to offer the user to either unlock the app immediately or partake in a 3-day trial period before making a purchase.
I created 2 IAP non-consumable products; 1 for the immediate [which is at a discount] and for the after trial period ends [this is at a higher cost].
Is this something that Apple allows or is frowned upon?
Our app cannot retrieve in-app purchase products from the App Store. We're getting a "storekit_no_response" error when attempting to fetch product information, despite having all products properly configured in App Store Connect.
Error: IAPError(code: storekit_no_response, source: app_store, message: StoreKit: Failed to get response from platform., details: null)
Verified product IDs match exactly what's in App Store Connect
Confirmed we're using a Sandbox Test Account
Checked that In-App Purchase capability is enabled
Waited over 24 hours for product availability
Tried multiple product ID formats
This issue is preventing us from implementing subscription functionality in our app. We need assistance determining why StoreKit isn't responding to our product queries.
Thank you for your help.
Topic:
App & System Services
SubTopic:
StoreKit
I want to test the "Remove from Sale" scenario in Sandbox. I set my subscription to "Remove from Sale" for all territories in App Store Connect, but I can still make new purchases and auto-renewals continue in the Sandbox environment.
Is this a known limitation? Or is there a specific way to make this work for testing?
If it can't be tested, I'd like to know the expected production behavior. What changes occur in the App Receipt and what App Store Server Notification is sent?
My app has in app purchase for subscriptions, available in many countries. When using Sandbox App Store accounts on TestFlight with a locale different from my own in the iOS 26 RC, I'm getting incorrect currency coming back from Product.products(for: identifiers), and so my app displays the wrong price for the locale. However, the actual Apple Pay buy sheet shows the proper currency symbol and currency amount. This did not happen on prior versions of iOS.
Is anyone else experiencing this?
The development subscription management screen for managing your sandbox account subscriptions is today showing products that belong to other apps.
Is there a known issue right now?
Created a FB with screenshots
FB FB20199893
Topic:
App & System Services
SubTopic:
StoreKit
What is the expected behavior for App Receipts and ASSN v2 notifications when a subscription is set to "Remove from Sale"?
I tried to test this in Sandbox, but the "Remove from Sale" setting in App Store Connect doesn't seem to affect the Sandbox environment.
For existing subscribers, what happens in the receipt? Does auto_renew_status change to 0 and is expiration_intent populated immediately?
Also, which notificationType is sent via ASSN v2?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
In-App Purchase
App Store Server Notifications
App Store Receipts
What platform are you targeting? And what version?
iOS, testing in Sandbox on a physical device.
What version of Xcode are you using?
[Xcode __]
What version of the OS are you testing on?
iOS 18 on iPhone 15 pro.
What specific API are you using?
StoreKit 2 via Flutter’s in_app_purchase plugin (Dart), which uses in_app_purchase_storekit under the hood.
What are the exact steps you took?
In App Store Connect, I created several Consumable IAPs (status “Ready to Submit”).
Example product IDs:
USD3.99TenMinuteCoffeePlan (Consumable)
USD24.99OneHourDinnerPlan (Consumable)
USD14.99InviteAFriendAsGenie (Consumable)
Signed in as a Sandbox tester on device (Settings → App Store → Sandbox Account).
App queries products with InAppPurchase.instance.queryProductDetails(ids) — products load successfully.
Call buyConsumable(purchaseParam: PurchaseParam(productDetails: ...)).
Listen to purchaseStream and log PurchaseDetails.
If something failed, what are the symptoms?
The purchase sheet often does not appear.
The purchase stream reports PurchaseStatus.restored, immediately, for SKUs that are marked Consumable.
Example log lines (from Dart):
Products loaded: 6
Product: id=USD3.99TenMinuteCoffeePlan, price=3.99
Product: id=USD24.99OneHourDinnerPlan, price=24.99
Product: id=USD14.99InviteAFriendAsGenie, price=14.99
Purchase update: productID=USD3.99TenMinuteCoffeePlan,
status=PurchaseStatus.restored, pendingComplete=false, purchaseID=2000000991974131
Purchase update: productID=USD24.99OneHourDinnerPlan,
status=PurchaseStatus.restored, pendingComplete=false, purchaseID=2000000992079251
Purchase update: productID=USD14.99InviteAFriendAsGenie,
status=PurchaseStatus.restored, pendingComplete=false, purchaseID=2000000999910991
Purchase update: productID=USD29.99InviteAFriendAsGenie,
status=PurchaseStatus.restored, pendingComplete=false, purchaseID=2000001003571920
If nothing failed, what results did you see? And what were you expecting?
Actual: restored events (no sheet) for items configured as Consumable.
Expected: For Consumables, a purchase sheet followed by purchased status. Consumables shouldn’t “restore”.
What else have you tried?
Verified every SKU shows Type = Consumable and Ready to Submit in App Store Connect; “Cleared for Sale” enabled; pricing/localization filled.
Created new product IDs (to avoid any prior non-consumable history).
Verified I’m not calling restorePurchases.
In the listener, I only grant benefits on PurchaseStatus.purchased (not on restored).
Observed that queryProductDetails succeeds; some IDs that aren’t fully configured return “not found,” as expected.
Minimal code (core bits):
final _iap = InAppPurchase.instance;
Future<void> init() async {
final resp = await _iap.queryProductDetails({
'USD3.99TenMinuteCoffeePlan',
'USD24.99OneHourDinnerPlan',
'USD14.99InviteAFriendAsGenie',
'USD29.99InviteAFriendAsGenie',
});
_products = resp.productDetails;
_sub = _iap.purchaseStream.listen(_onUpdates);
}
Future<void> buy(ProductDetails p) async {
final param = PurchaseParam(productDetails: p);
await _iap.buyConsumable(purchaseParam: param); // iOS SK2 path
}
void _onUpdates(List<PurchaseDetails> list) async {
for (final pd in list) {
print('status=${pd.status}, id=${pd.productID}, pending=${pd.pendingCompletePurchase}, purchaseID=${pd.purchaseID}');
switch (pd.status) {
case PurchaseStatus.purchased:
// deliver & (if pendingCompletePurchase) completePurchase
break;
case PurchaseStatus.restored:
// for consumables, I do not deliver here
break;
default:
break;
}
}
}
Questions for the community/Apple:
Under what conditions would StoreKit 2 return restored for a SKU that’s set to Consumable?
Is there any server-side caching of old product type or ownership tied to a product ID that could cause this in Sandbox?
Is “Ready to Submit” sufficient for Sandbox testing of IAPs, or must the SKUs be attached to a submitted build before StoreKit treats them as consumable?
If a product ID was ever created/purchased as Non-Consumable historically, does creating a new ASC entry with the same string ID as Consumable still cause restored for that tester?
Besides creating brand-new product IDs and/or resetting the Sandbox tester’s purchase history, is there any other recommended way to clear this state?
Happy to provide a device sysdiagnose or a stripped test project if that helps. Thanks!
Hello I am trying to add payments on my app. I have added all products I need in subscriptions. I also tried by using storekit but from my understanding testing with storekit is nothing to rely on. My app works on Android (with the same product IDs same unction call) iOS is not why is that?
Hello,
Our app has been released in Korea with an external payment feature.
The function that must display the required modal for external payments is as follows:
let result = try await ExternalPurchase.presentNoticeSheet()
guard result != .cancelled else {
return
}
However, while testing in the development environment, the API returns a result of continuedWithExternalPurchaseToken(token: String), but in the version distributed through the App Store, it returns cancelled.
We would like to know how we can receive the continuedWithExternalPurchaseToken result in the App Store version.
Thank you for your guidance. If anyone here has experienced a similar issue or found a solution, I would greatly appreciate your insights as well.
The phone is set up with the developer program to cancel subscriptions from the app we developed. However, after the OS update on the phone, the subscriptions no longer appear in the developer program, although the subscription does exist in the app itself. We are attaching the log.
🔖 8/9/2025, 10:59:44 AM
["expires_date_pst": 2025-09-08 21:58:36 America/Los_Angeles, "original_purchase_date_ms": 1753167687000, "original_purchase_date_pst": 2025-07-22 00:01:27 America/Los_Angeles, "purchase_date_ms": 1757307516000, "purchase_date_pst": 2025-09-07 21:58:36 America/Los_Angeles, "product_id": com.topwall.premium_trial.monthly.trial, "in_app_ownership_type": PURCHASED, "web_order_line_item_id": 2000000111040333, "purchase_date": 2025-09-08 04:58:36 Etc/GMT, "is_trial_period": false, "original_purchase_date": 2025-07-22 07:01:27 Etc/GMT, "expires_date_ms": 1757393916000, "expires_date": 2025-09-09 04:58:36 Etc/GMT, "transaction_id": 2000001002316107, "is_in_intro_offer_period": false, "subscription_group_identifier": 21733009, "original_transaction_id": 2000000966725103, "quantity": 1]
🔹🔹🔹🔹🔹🔹🔹🔹🔹🔹
🟢 8/9/2025, 10:59:44 AM
StoreKit isActive: true до 2025-09-09 07:58:36
Why do you think the subscription created in the app doesn’t show up in the sandbox?
Topic:
App & System Services
SubTopic:
StoreKit
We have received reports from users that their in-app purchases suddenly appear as unpurchased.
We would like to know the cause of this issue.
Our implementation does not use a server; purchases are determined solely on the client side.
These reports often occur after updating the app version,
but we have been unable to reproduce the issue in our development environment.
Topic:
App & System Services
SubTopic:
StoreKit
I have implemented in-app-purchase in one of my iOS application.
I generated the consumable products and these are approved by Apple Showing with Green check.
I used StoreKit-2 and locally testing with store sync configuration file.
The products I have created on developer accounts automatically synced by Store Configuration file and showing no the screen and I can purchase the product with Xcode environment in development.
When uploaded app to test flight, I am not getting products with sandbox email id.
Cases I have tries:
-Remove my original Apple ID from device and just testing with Apple Sandbox email id -> Not getting products.
-Remove configuration file while uploading to test flight -> not fetching products.
-Checked the archive build and its in Release mode.
Note: I am as a (Admin) team member, not account holder.
Issue:
Not fetching products on Test flight with Sandbox & in live app.
Is there something I have to track here:
Agreements for Free Apps Agreement with EFFECTIVE DATE showing 3 Jul 2025 - 20 Sep 2025 & STATUS is Active
Agreements for Paid Apps Agreement with EFFECTIVE DATE showing nothing & STATUS is New
I’m implementing subscriptions and running tests, and I noticed a behavior I’d like to confirm.
Plans in the app
Basic — Monthly
Basic — Annual
Premium — Monthly
Premium — Annual
Test environment
Sandbox (where ~1 day ≈ under 1 minute of real time)
steps
Start Basic (Monthly) using an introductory offer (free trial).
Create a crossgrade to Basic (Annual) (scheduled/queued).
3.After receiving a RENEWAL App Store Server Notification indicating the plan will move from trial to paid Basic (Annual), but before the trial actually expires, upgrade the user to Premium (Monthly).
Observed behavior (Sandbox) & questions
Even though there is still up to ~1 day of trial remaining (≈ under 1 minute in Sandbox), upgrading to Premium (Monthly) immediately ends the trial and activates the paid Premium plan right away.
Will this same behavior occur in Production?
If yes, is this the expected/acceptable behavior when upgrading during an active trial after a pending crossgrade?
Note: If we upgrade to Premium before the RENEWAL notification arrives, the remaining trial time is carried over in our tests.
In this flow, we see a RENEWAL notification for Basic (Annual) (moving from trial → paid), but then the user immediately upgrades to Premium (Monthly) and the trial ends at that moment.
In Production, would the charge for Basic (Annual) be refunded automatically since the user effectively switches to Premium immediately (and Basic Annual does not remain active)?
In Sandbox there’s no real charge, but I want to ensure we won’t see a situation in Production where Basic (Annual) is billed and not refunded, even though the subscription effectively moved to Premium right away.
Thanks in advance!
Can you implement storekit2 for in app purchases for a flutter project?
Topic:
App & System Services
SubTopic:
StoreKit
In my app’s IAP products, before enabling free trials, the App Store Server Notifications V2 callbacks all returned the correct notificationType.
For auto-renewable subscriptions, when they were about to expire, the notificationType was either DID_RENEW or EXPIRED. A small number of cases(DID_FAIL_TO_RENEW) failed to renew due to billing issues, which was expected.
However, after I enabled a 7-day free trial for the auto-renewable products, I noticed that in the App Store Server Notifications V2 callbacks, almost all users (except those who manually turned off auto-renewal) received notificationType = DID_FAIL_TO_RENEW.
According to the documentation, DID_FAIL_TO_RENEW indicates a billing issue renewal failure, but in this case it seems like all renewals are being marked as failed.
I’ve observed that for users who cancel during the free trial, the callbacks look normal: first a DID_CHANGE_RENEWAL_STATUS notification, then an EXPIRED notification when the trial ends. That flow seems correct.
However, for users who do not cancel the trial, almost all callbacks show DID_FAIL_TO_RENEW. Does this mean every remaining user has a billing issue?
I also noticed on the Developer Forums that other developers have reported the same issue — receiving a large number of DID_FAIL_TO_RENEW notifications specifically when free trials convert to paid subscriptions:
https://developer.apple.com/forums/search?q=DID_FAIL_TO_RENEW
Could someone clarify: under normal circumstances, when a free trial transitions to a paid subscription and fails, should the App Store Server Notifications V2 notificationType indeed be DID_FAIL_TO_RENEW, or should it be a different type(e.g. EXPIRED)?
And is it expected behavior that almost all free trial conversions return DID_FAIL_TO_RENEW?
When trying to login with sandbox account in my simulator, nothing happens, it just become inactive for few seconds and then it become active again prompting that I can login, again and again.
Product Timeout, In App purchase is approved in App Store Connect. The Product ID and Bundle ID match.
Environment
macOS App in TestFlight
Bundle ID: com.streamtime.StreamTime
App Version: 1.1 (Build 51)
StoreKit 2
Product ID: com.streamtime.premium
Status: App & Subscription Approved
Issue
StoreKit product request (Product.products(for:)) consistently times out after 60 seconds in TestFlight, despite all connectivity checks passing. The same code works perfectly in Xcode with local StoreKit configuration.
Diagnostic Results
✅ Successful checks:
App Store connectivity (HTTP 200 from buy.itunes.apple.com)
Backend API connectivity (HTTP 200)
StoreKit 2 API available
AppStore.canMakePayments: true
Valid receipt exists
Bundle ID matches
Product ID matches approved subscription
❌ Failing:
Product request times out after 60 seconds
No products returned
Code Implementation
// Direct product request (fails in TestFlight)
let products = try await Product.products(for: ["com.streamtime.premium"])
Logs
🔍 App Bundle ID: com.streamtime.StreamTime
🔍 Product ID: com.streamtime.premium
🔍 AppStore.canMakePayments: true
🔍 Apple Store connectivity: HTTP 200
🔵 Direct request for product ID: 'com.streamtime.premium'
⏱️ Direct request start time: 2025-08-30 10:21:32 +0000
❌ TIMEOUT: Product request took longer than 60 seconds
What I've Tried
Removed manual in-app-purchase entitlement (per Apple's guidance)
Using automatic signing
Verified subscription is approved in App Store Connect
Using Sandbox Apple ID in TestFlight
Verified all network connectivity
Questions
Why does StoreKit timeout only in TestFlight when all other connectivity works?
Are there additional configuration steps needed for macOS apps vs iOS?
Could this be related to the automatic in-app purchase entitlement?
Any guidance would be greatly appreciated as this is blocking our TestFlight validation.
Topic:
App & System Services
SubTopic:
StoreKit