hello, i am currently trying to add a hardpaywall to my app. When I test in testflight with storekit config set to "none" in scheme. I get an error saying unable to load subscriptions.
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Posts under StoreKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi, we have published a flutter app on the App Store offering additional content via one-time in-app purchases. Everything is working as expected when distributing the app via TestFlight but we're reportedly having issues with users not being able to restore purchases on some devices with the app loaded from the Apple App Store.
We noticed the issue when some user were unable to unlock the in-app purchases via promotion codes we supplied for marketing reasons. Most of them were able to unlock the purchases using the promotion codes without a problem. Some had to try several times using a new code each time but for some users (on some of their devices) it's not working at all and we can't seem to find the reason for it.
Here is one users case in detail:
the user tried to unlock our "complete bundle" using a promo code
first code did not seem to work, so I provided a new code
it seems that both codes were redeemed correctly because both of the show up in the users purchase history in his App Store profile
Now, the user is unable to unlock the content inside our app on his iPhone, he is however able to unlock it on its iPad without a problem. Both devices run the same iOS version, same Apple ID and the exact same app version. Even stranger: when using the TestFlight version of the app, again everything is working correctly even on the users iPhone.
I took a look at the device logs and here's what I found:
This is a snapshot of the users iPad. As you can see
products are found and listed correctly
storekitd seems to find and return products in receipt with the correct identifier
we get the correct information and are able to restore the correct purchase
14:48:17.032895+0200 Runner flutter: Found id: de.BUNDLEID.01, title: TITLE 1, price: €29.99
14:48:17.032922+0200 Runner flutter: Found id: de.BUNDLEID.bundle, title: TITLE Gesamtpaket, price: €59.99
14:48:17.032975+0200 Runner flutter: Found id: de.BUNDLEID.02, title: TITLE 2, price: €29.99
14:48:17.033001+0200 Runner flutter: Found id: de.BUNDLEID.extension, title: TITLE Plus, price: €9.99
14:48:20.656702+0200 storekitd [70D5C079]: Found 2 products in receipt with ID de.BUNDLEID.bundle
14:48:20.667793+0200 Runner flutter: Called purchaseListener (purchaseDetailsList: 1)
14:48:20.667838+0200 Runner flutter: Purchase restored
14:48:20.667869+0200 Runner flutter: Unlock permission TITLE_1
14:48:20.667892+0200 Runner flutter: Update TITLE_1 with true
14:48:20.672199+0200 Runner flutter: Unlock permission TITLE_2
14:48:20.672243+0200 Runner flutter: Update TITLE_2 with true
14:48:20.677849+0200 Runner flutter: Unlock permission TITLE_3
14:48:20.677897+0200 Runner flutter: Update TITLE_3 with true
14:48:20.679079+0200 Runner flutter: Calling completePurchase...
Same exact behavior can be observed on the users iPhone when running the TestFlight version of the app.
However, running the app from the Apple App Store on the users iPhone (same Apple ID, same OS and app version), the log looks like this:
14:23:26.150484+0200 Runner flutter: Found id: de.BUNDLEID.bundle, title: TITLE Gesamtpaket, price: €59.99
14:23:26.150513+0200 Runner flutter: Found id: de.BUNDLEID.02, title: TITLE 2, price: €29.99
14:23:26.150619+0200 Runner flutter: Found id: de.BUDNLEID.extension, title: TITLE Plus, price: €9.99
14:23:26.150657+0200 Runner flutter: Found id: de.BUNDLEID.01, title: TITLE 1, price: €29.99
14:23:27.125353+0200 dasd com.apple.icloud.searchpartyd.ProductInfoManager:C25423:[ (name: Thundering Herd Policy, policyWeight:
14:23:27.376336+0200 storekitd [Client] (Runner) Initialized with server Production bundle ID de.ds-infocenter.guk and request bundl
14:23:27.390026+0200 storekitd AMSURRequestEncoder: (7BA6012D] Encoding request for URL: https://mzstorekit.itunes.apple.com/inApps/
14:23:27.984831+0200 storekitd [7BA6012D]: Found 2 products in receipt with ID de.BUNDLEID.bundle
14:23:27.990235+0200 Runner flutter: Called purchaseListener (purchaseDetailsList: 0)
14:23:27.990271+0200 Runner flutter: Purchase details list is empty!
StoreKit seems to return the same exact products but for some reason the purchaseDetails list seems to be empty this time.
Here is the code responsible for restoring the purchases. Nothing fancy going on here if you ask me.
@override
void initState() {
super.initState();
db = context.read<Database>();
inAppPurchase = InAppPurchase.instance;
inAppPurchase.purchaseStream.listen(
purchaseListener,
onError: (error) {
print('Purchase stream error: $error');
showErrorDialog();
},
cancelOnError: true,
);
queryProductInformation().then((value) {
if (value == null) {
print('value in queryProductInformation is null!');
updateProcessing(false);
return;
}
setState(() {
for (var details in value.productDetails) {
products[details.id] = details;
}
});
updateProcessing(false);
});
}
Future<void> restorePurchases() async {
updateProcessing(true);
await inAppPurchase.restorePurchases();
}
void purchaseListener(List<PurchaseDetails> purchaseDetailsList) async {
print(
'Called purchaseListener (purchaseDetailsList: ${purchaseDetailsList.length})');
if (purchaseDetailsList.isEmpty) {
print('Purchase details list is empty!');
updateProcessing(false);
return;
}
for (var purchaseDetails in purchaseDetailsList) {
switch (purchaseDetails.status) {
case PurchaseStatus.purchased:
print('Purchase successful: ${purchaseDetails.productID}');
completePurchase(purchaseDetails.productID);
break;
case PurchaseStatus.canceled:
print('Purchase was canceled');
updateProcessing(false);
break;
case PurchaseStatus.restored:
print('Purchase restored');
completePurchase(purchaseDetails.productID);
break;
case PurchaseStatus.pending:
print('Purchase pending');
break;
case PurchaseStatus.error:
print('Purchase error');
showErrorDialog();
break;
}
print('Calling completePurchase...');
await inAppPurchase.completePurchase(purchaseDetails);
}
}
Could this be an issue on Apples API or flutters in_app_purchase package?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
StoreKit
In-App Purchase
TestFlight
App Store Receipts
I implemented consumable in-app purchases in an iPhone app using StoreKit's ProductView().
When I tap the payment button in ProductView(), I am taken to the payment screen and once the payment is completed, the desired code appears to be executed, so there doesn't seem to be a problem, but when I tap the payment button in ProductView() again, the desired code is executed without being taken to the payment screen.
So one payment can be used any number of times.
I thought I wrote it exactly according to the reference, but
will it be okay in a production environment?
Is there any code that is necessary?
revenuecat is asking for the in app subscriptions to be approved first in order for the pay wall to display and function properly, but apple support keeps flagging them as "developer action needed" and complaining that they can't access in app subscriptions. what do I do?
The minimum support for the project is iOS 15.2, and the subscription function is implemented using StoreKit2.
Problem: The redemption was successful within the Appstore, but the redemption item cannot be detected through code within the app.(The subscription function has been implemented and tested)
Here is my code, I am not sure if it is due to storeKit2 (as seen elsewhere) or if there is a problem with the testing method. If there is a correct testing method for the promoCode redemption scenario, please let me know.
for await verificationResult in Transaction.currentEntitlements {
switch verificationResult {
case .verified(let transaction):
if transaction.revocationDate != nil {
print("unsubscribe:\(transaction)")
break
}
if transaction.offerType == .code,let code = transaction.offerID {
print("Have promoCode")
print("promoCode: \(code)")
let dateF = DateFormatter()
dateF.dateFormat = "yyyy.MM.dd HH.mm.ss"
if let expireDate = transaction.expirationDate {
print("endTime:\(dateF.string(from: expireDate))")
}
}
//.consumable,.nonConsumable,.autoRenewable,.nonRenewable
if transaction.productType == .autoRenewable {
print("Have subscription:\(transaction)")
let dateF = DateFormatter()
dateF.dateFormat = "yyyy.MM.dd HH.mm.ss"
if let expireDate = transaction.expirationDate {
print("endTime:\(dateF.string(from: expireDate))")
}
}else{
print("\(transaction)")
}
case .unverified(let unverifiedTransaction, let verificationError):
print("checkProduct:error")
}
}
Hello,
I am consistently receiving the error message "In-app purchases are not allowed on this device" whenever I try to make an in-app purchase on my iOS device. Despite following all the recommended solutions I could find online, the issue remains unresolved.
Here is a list of the steps I have already taken:
Checked Screen Time Settings:
I navigated to Settings > Screen Time > Content & Privacy Restrictions > iTunes & App Store Purchases.
I have confirmed that "In-App Purchases" is set to "Allow." I have also tried toggling this setting off and on again.
Signed Out & In of Apple ID:
I signed out of my Apple ID via Settings > [Your Name] > Media & Purchases, restarted the device, and then signed back in.
Restarted the Device:
I have force-restarted my device multiple times.
Updated iOS:
I have ensured my device is running the latest version of iOS (checked via Settings > General > Software Update).
Verified Payment Method:
I have confirmed that my payment method on file is valid and up-to-date.
Created a New Sandbox Account:
I also created a new Sandbox Tester account in App Store Connect and tested with it, but the result was the same.
Device Information:
Device Model: iPhone 15, iPhone 13
iOS Version: iOS 17.5, iOS 18
Even after performing all of these steps, the problem persists. Has anyone else encountered such a stubborn issue, or does anyone have a different solution I could try?
Thank you in advance for your help.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit Test
StoreKit
In-App Purchase
We are facing a serious issues with in app purchases in our app.
We offer 3 IAP: auto-renewable subscription 1W, auto-renewable subscription 1Y, non-consumable one-time purchase (LifeTime access)
In our case 90-95% of transactions fail and we mostly get SKError code=2 .
Sometime purchase fails several times for the same user so it’s very hard to believe that user intentionally cancels transaction for the same product 4 or even 5 times in a row.
It happens regardless iOS version, device model, our app version.
We've checked multiple threads with the same issue but coudn't find any solution.
We do not offer any promotions, product identifiers are valid... Some users are able to make a purchases without any issues.
Hello,
I recently saw this error from StoreKit in the Console - 'Invalid value for purchase intake' - while debugging a SKPayment subscription issue (where a valid receipt should be verified and restored, but isn't for one user).
I haven't been able to find any documentation about this message and wondered if it was related at all.
There were two other logs from StoreKit right before saying:
'Found 3 products in receipt with ID'
'Processing ad attribution purchase intake'
Does anyone know what 'invalid value for purchase intake' is referencing?
We don't have the AdAttributionKit implemented. It sounds like it might be related to that instead?
Thank you
My app has a couple of consumable IAP items. I have tested this extensively and it works in all test scenarios including loads of beta testers using testflight. However, Apple's production reviewer reports that loading of the products hangs in their setup.
This is very frustrating as I have no means of recreating the problem.
My first product was tested ok an all my IAP items are approved for release. However, I did not explicitly assign them to my build. I read somewhere that you need to do that but could not find in App Store Connect after my first product was approved.
Below is the relevant code section. What am I missing?
class DonationManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
@Published var products: [SKProduct] = [] // This is observed by a view. But apparently that view never gets populated in Apple's production review setup
@Published var isPurchasing: Bool = false
@Published var purchaseMessage: String? = nil
let productIDs: Set<String> = ["Donation_5", "Donation_10", "Donation_25", "Donation_50"]
override init() {
super.init()
SKPaymentQueue.default().add(self)
fetchProducts()
}
deinit {
SKPaymentQueue.default().remove(self)
}
func fetchProducts() {
print("Attempting to fetch products with IDs: \(productIDs)")
let request = SKProductsRequest(productIdentifiers: productIDs)
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
DispatchQueue.main.async {
self.products = response.products.sorted { $0.price.compare($1.price) == .orderedAscending }
print("Successfully fetched \(self.products.count) products.")
if !response.invalidProductIdentifiers.isEmpty {
print("Invalid Product Identifiers: \(response.invalidProductIdentifiers)")
self.purchaseMessage = NSLocalizedString("Some products could not be loaded. Please check App Store Connect.", comment: "")
} else if self.products.isEmpty {
print("No products were fetched. This could indicate a problem with App Store Connect configuration or network.")
self.purchaseMessage = NSLocalizedString("No products available. Please try again later.", comment: "")
}
}
}
...and the view showing the items:
@StateObject private var donationManager = DonationManager()
var body: some View {
VStack(spacing: 24) {
Spacer()
// Donation options -------------------
if donationManager.products.isEmpty {
ProgressView(NSLocalizedString("Loading donation options...", comment: ""))
.foregroundColor(DARK_BROWN)
.italic()
.font(.title3)
.padding(.top, 16)
} else {
ForEach(donationManager.products, id: \.self) { product in
Button(action: {
donationManager.buy(product: product)
}) {
HStack {
Image(systemName: "cup.and.saucer.fill")
.foregroundColor(.pink)
Text("\(product.localizedTitle) \(product.priceLocale.currencySymbol ?? "$")\(product.price)")
}
.buttonStyle()
}
.disabled(donationManager.isPurchasing)
}
}
I'm encountering a crash on app launch. The crash is observed in iOS version 17.6 but not in iOS version 18.5. The only new notable thing I added to this app version was migrate to store kit 2.
Below is the error message from Xcode:
Referenced from: <DCC68597-D1F6-32AA-8635-FB975BD853FE> /private/var/containers/Bundle/Application/6FB3DDE4-6AD5-4778-AD8A-896F99E744E8/callbreak.app/callbreak
Expected in: <A0C8B407-0ABF-3C28-A54C-FE8B1D3FA7AC> /usr/lib/swift/libswift_Concurrency.dylib
Symbol not found: _$sScIsE4next9isolation7ElementQzSgScA_pSgYi_tYa7FailureQzYKFTu
Referenced from: <DCC68597-D1F6-32AA-8635-FB975BD853FE> /private/var/containers/Bundle/Application/6FB3DDE4-6AD5-4778-AD8A-896F99E744E8/callbreak.app/callbreak
Expected in: <A0C8B407-0ABF-3C28-A54C-FE8B1D3FA7AC> /usr/lib/swift/libswift_Concurrency.dylib
dyld config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/usr/lib/libLogRedirect.dylib:/usr/lib/libBacktraceRecording.dylib:/usr/lib/libMainThreadChecker.dylib:/usr/lib/libRPAC.dylib:/System/Library/PrivateFrameworks/GPUToolsCapture.framework/GPUToolsCapture:/usr/lib/libViewDebuggerSupport.dylib```
and Stack Trace:
```* thread #1, stop reason = signal SIGABRT
* frame #0: 0x00000001c73716f8 dyld`__abort_with_payload + 8
frame #1: 0x00000001c737ce34 dyld`abort_with_payload_wrapper_internal + 104
frame #2: 0x00000001c737ce68 dyld`abort_with_payload + 16
frame #3: 0x00000001c7309dd4 dyld`dyld4::halt(char const*, dyld4::StructuredError const*) + 304
frame #4: 0x00000001c73176a8 dyld`dyld4::prepare(...) + 4088
frame #5: 0x00000001c733bef4 dyld`start + 1748```
Note: My app is a Godot App and uses objc static libraries. I am using swift with bridging headers for interoperability. This issue wasn't observed until my last version in which the migration to storekit2 was the only notable change.
On iOS 26 beta 3, after a user purchases an item, initiating a second order for the same product fails to process payment. The system returns the same transaction ID and displays an interface message stating: "You've already purchased this In-App Purchase. It will be restored for free."
I’ve tested this – not only did the legacy StoreKit finishTransaction method fail to work, but StoreKit2 finish method also malfunctioned.
When will Apple fix this issue? If unresolved, it will prevent a large number of users from making purchases normally, leading to disastrous consequences.
We have some users who have upgraded to iOS 26 beta3. Currently, we observe that when these users make in-app purchases, our code calls [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; method, and we clearly receive the successful removal callback in the delegate method - (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray<SKPaymentTransaction *> *)transactions. However, when users click on products with the same productId again, the method - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions still returns information about previously removed transactions, preventing users from making further in-app purchases.
Hello,
Since updating to iOS 26 Beta 3, I’ve been experiencing an issue where transactions purchased through the normal in-app purchase flow continue to be reported as updated and unfinished—even after calling the finish() function. Please resolve this promptly.
有一个用户反馈7月8日充值了3笔后一直无法发起新的购买,总是提示已经购买。我们查了是之前的交易无法结束,我们使用StoreKit2,已经调用await transaction.finish()成功结束交易了,但是每次发起新支付时,Transaction.unfinished还会返回之前已完成的交易信息。
是设备或AppleID的问题么?用户尝试了重启设备、重新登录AppleID都没用。有什么办法解决呢?
用户无法结束的苹果交易id为:200002703899379、200002703900716、200002703902023。
A user reported that after making 3 purchases on July 8th, they have been unable to initiate new purchases, always receiving a prompt that the item has already been purchased. Upon investigation, we found that the previous transactions couldn't be finalized. We use StoreKit2 and have successfully called await transaction.finish() to end the transactions. However, every time a new payment is initiated, Transaction.unfinished still returns information about the previously completed transactions.
Could this be an issue with the device or Apple ID? The user has tried restarting the device and re-logging into their Apple ID, but these attempts were unsuccessful. Is there any way to resolve this?
The Apple transaction IDs that the user is unable to finalize are: 200002703899379, 200002703900716, 200002703902023.
I'm encountering an issue with the App Store Server API where the appAccountToken is not preserved when users migrate their Apple ID email addresses. I've submitted
Feedback Assistant ticket FB18709241 but wanted to check if anyone else has experienced this and get community input on best practices.
The Issue
When a user migrates their Apple ID from one email to another (e.g., from olduser@example.com to newuser@icloud.com), the App Store creates a new subscription
transaction with a different originalTransactionId, but the appAccountToken is not carried forward from the original transaction.
What I'm Seeing
note: these values are fake
When querying /inApps/v1/subscriptions/{originalTransactionId} with the either post-migration transaction ID or the pre-migration transaction ID, the API returns both transactions:
Pre-migration transaction (status: 2 - inactive):
originalTransactionId: "12345678910111"
Contains: "appAccountToken": "abc123-def456-ghi789"
Post-migration transaction (status: 1 - active):
originalTransactionId: "67891011121314"
Missing: appAccountToken entirely
The Problem
The appAccountToken is our only way to link App Store subscriptions to user accounts. Without it on the new transaction:
Users lose access to premium features despite having valid subscriptions
Server-side renewal notifications can't be matched to user accounts
Manual support intervention is required for each affected user
Questions for the Community
Has anyone else encountered this issue with Apple ID migrations?
What's the recommended approach for handling this scenario?
Is there an alternative mechanism to maintain the subscription-to-user linkage across migrations?
Questions for Apple Engineers
Is this the expected behavior, or should the appAccountToken be preserved?
Are there any planned improvements to handle this migration scenario?
What's the best practice for developers to handle this case?
Interestingly, both the old and new transaction IDs return the same JSON response from the App Store Server API, suggesting Apple maintains internal linkage between
these transactions, but the appAccountToken isn't carried forward to the active transaction.
Any insights or similar experiences would be greatly appreciated!
Thank you!!
Feedback Assistant: FB18709241
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
StoreKit
App Store Server Notifications
App Store Server API
I want to add in-app purchasing to my app, but I can't figure out what part of my workflow is wrong.
I created a product for my app in iTunes Connect (the product ID is com.mycompany.products.***) and it's in "Ready to submit" status.
I created a sandbox test user for this app.
I connected to iTunes on a real device using the sandbox AppleID.
I went back to XCode and added in-app purchasing to my app.
I turned on developer mode on the real device and logged in as the sandbox user.
I built the app and ran it on a real device (not the simulator).
I tried to get product information (com.mycompany.products.***) but nothing was returned.
In-app purchasing is registered in App Store Connect and the status is "Ready to submit".
The code only retrieves product information in a simple way, so I don't think there's a problem.
inAppPurchase.getProducts(["com.mycompany.products.***"]).then(console.log).catch(console.error);
But it only returns an empty array.
What could be wrong?
Any help would be much appreciated.
We are running into exceptions when trying to parse Purchase Date and Original Purchase Date from the base64 encoded receipt.
Expected RFC 3339 format of ASN.1 Field Value is: yyyy-MM-ddTHH:mm:ssZ but we end up getting back 2025-04-22T19.49.03Z.
Started to happen on 3rd Dec 2024.
I've been implementing in app purchases into an existing C++ app. I'm using the latest Swift StoreKit since the old ObjC interface is deprecated . There is a really weird problem where the swift/C++ bridging seems to get into a loop. After the Product structure is retrieved I have the following structure which I use to bridge to C++
public struct storeData
{
public var id : String
public var displayName : String
public var description : String
public var price : String
public var purchased : Bool = false
public var level : Int = 0
}
and this is passed back to the caller as follows
public func getProducts (bridge : StoreBridge) -> [storeData]
{
bridge.products.sort { $0.price > $1.price }
var productList : [storeData] = []
for product in bridge.products
{
let data : storeData = storeData(id: product.id,
displayName: product.displayName,
description: product.description,
price: product.displayPrice,
purchased: bridge.purchasedProductIds.contains(product.id)
)
productList.append(data)
}
return productList
}
the "bridge" variable is a bridging class where the guts of the bridge resides, and contains the "products" array as a publishable variable.
In the C++ code the data is retrieved by
outProd->id = String(inProd.getId());
outProd->displayName = String(inProd.getDisplayName());
outProd->description = String(inProd.getDescription());
outProd->price = String(String(inProd.getPrice()));
outProd->purchased = inProd.getPurchased();
The "String" is actually a JUCE string but that's not part of the problem. Testing this with a local StoreKit config file works fine but when I test with a sandbox AppStore the app hangs. Very specifically it hangs somewhere in the Swift thunk when retrieving the price. When I remove the line to retrieve the price everything works. And - and this is the weird bit - when I pad the price out with some random text, it now starts working (so I have a workaround). This is, however, slightly worrying behaviour. Ideas?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect API
Tags:
StoreKit Test
Swift
StoreKit
Hello,
i am having issues getting my iOS app through review.
The problem seems to be that the reviewer is never able to purchase my IAP.
The app has a non-consumable IAP that unlocks premium game features.
however, I have not been able to able to reproduce.
The IAP works for me in Xcode testing, as well as Sandbox (TestFlight)
I had heard initially the problem was that I submitted the IAP for review alone, instead of having it auto submit with the app itself.
but in my latest submission, I actually deleted and recreated the IAP, and allowed it to be auto submitted along with the app itself.
again, all local and sandbox testing is successful, but the app reviewer sees an carrot stating that the product could not Be loaded from the App Store.
i built the app using Capacitor, and am using revenue cat.
does anyone have any ideas where I am going wrong?
Thank you
One of our apps has 85% stuck in Billing Retry -- We are so confused. All the users are from the US, and have a one-week free trial.
We had 1,000 subscriptions expire from this issue.
So any help would be so appreciated.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
App Store Connect
App Store Server API