Hello!
We are implementing consumable IAP for iOS using StoreKit 2 together with our own server backend.
Our happy path looks like this:
1. Call /prepare on our server
• We only allow one purchase at a time, so this fails if a pending transaction already exists.
2. Call /purchase via StoreKit
3. If successful, call /complete on our server
4. Call .finish() on the Transaction
⸻
The Problem
Some users report being charged by Apple but not receiving coins.
I suspect this happens in rare cases where the purchase flow throws an exception:
• Every time we throw, we immediately cancel the transaction on our server.
• However, some errors may actually be temporary. StoreKit seems to recover by later sending an update through Transactions.updates.
• When that happens, since the transaction was already canceled on our server, we cannot match it. As a result, we just call .finish() without granting consumables.
⸻
Additional Observations
From user logs, the issue tends to appear when the following errors are reported:
• リクエストを完了できません。
• Triggered by: StoreKit.notEntitled
• Triggered by: StoreKit.unknown
• ヘルパーアプリケーションと通信できませんでした。
I was not able to reproduce the last one, even when testing all possible StoreKit configuration errors. Some sources suggest this may be a rare case where the app cannot communicate with the App Store itself.
Additionally, affected users often seem to be using non-standard payment methods (PayPay, gift cards, carrier billing, etc.) rather than credit cards.
⸻
My Question
What is the best practice for handling StoreKitError and PurchaseError?
Specifically:
• Should some of these errors be treated as temporary instead of final?
• How should we ensure users always receive their consumables in such cases?
⸻
Code
do {
let result = try await wrapper.product.purchase()
switch result {
case .success(let result):
let transaction = try StoreKitVerifier.checkVerified(result)
let iOSPurchase = IOSPurchase(transaction: transaction, jws: result.jwsRepresentation)
return .Success(purchase: iOSPurchase)
case .userCancelled:
return .Canceled()
case .pending:
return .Pending()
@unknown default:
return .Error(
message: "Purchase result doesn't match with anything. This must not be executed")
}
} catch {
return .Error(message: error.localizedDescription)
}
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
I cannot test IAP using sandbox account that I logged on from settings, it keeps show my regular Apple ID when I try to test IAP from TestFlight
This issue frustrate me and bunch of my colleagues, we cannot manage our subscription when sandbox account is default choosing Apple ID
I've seen people complaining about this issue a lot
Any help on resolving this issue would be really appreaciated
Looking for assistance in managing subscription upgrades for TestFlight users.
I have a few monthly subscriptions, 30days, each with a different set of available features, 1 with all, and 1 with fewer. (All are in proper order and grouped in App Store connection subscriptions)
subscribing seems to be working fine, and purchasing an upgrade is going ok.
what is not: reflecting the upgraded plan in app (currently reflects it will start in 30days when current subscription expires)
I’m lead to believe this will be resolved with a live app in App Store, that will then handle prorating, terminate the old plan and immediately start the new one.
looking for help getting TestFlight to show immediate upgrades.
We are currently integrating In-App Purchases for our app and have configured App Store Server Notifications (v2) in the Sandbox environment.
During testing, we observed the following issue:
When a transaction is cancelled, declined, or pending (e.g., Ask to Buy flows or authorization pending),
No App Store Server Notification is sent to our webhook endpoint.
We only receive webhook events where the status is "purchased".
This becomes a critical problem for us because our backend must accurately track transaction states including failed and pending purchases, especially for wallet top-up use cases.
Additionally, we tried mocking failed transactions (via Xcode local environment and turning off In-App Purchases from Developer Settings) to simulate a technical failure scenario.
Even in these cases, no webhook notification was received when the purchase failed server-side.
Is it expected behavior in Sandbox that only successful transactions ("purchased") trigger webhooks?
Are failed or pending transactions suppressed in Sandbox intentionally?
Will webhook behavior be different in Production (i.e., will we receive webhook notifications for failures there)?
Is there any extra configuration or entitlement needed to fully test failure scenarios via webhooks in Sandbox?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
In-App Purchase
App Store Server Notifications
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
I noticed a very weird behavior for refunds. When a user refunds an up-front paid app, they still have access to the app. How can I detect such a case and block access to the app?
In general, I think it should be handled by Apple, but for some reason, they don't do it.
Hello everyone!
We are observing a significant number of failures in the fetch of the products with StoreKit1, meaning that in a completely random way, some product identifiers are considered invalid in the response that we receive from Apple, and after some minutes these products are considered once again valid.
The issue started on Thursday 04/24 around 12.00 am (UTC + 02.00) and from our dashboard we can clearly see the trend of these failures has some spikes at precise times. I am attaching a view that we use for monitoring purposes showing this trend, considering the data of this week.
We are noticing this problem on multiple developer accounts and on multiple apps, which is leading us to think it could be an issue in the Apple backend processing the request.
In our case, the apps are not launched correctly until all the products are fetched, and therefore the impact of this problem is very high.
Is anyone experiencing something similar or do you have logs which allows you to identify such issues?
The issue happens only in production, while in debug and TestFlight environment everything works well.
Thank you for your support
Network
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
App Store Connect
In-App Purchase
Graphical Debugger
After creating a new weekly subscription option, I get inconsistent results for subscriptionPeriod. In local testing with a synced or a un-synced StoreKit file I am getting unit == .week (as expected) whereas in TestFlight I am getting unit == .day. This makes unit.localizedDescriptionsomewhat unusable in the paywall.
Am I missing something? Or is this bug or a limitation of StoreKit and/or TestFlight and/or newly created subscription options?
Affected code (in a custom SubscriptionStoreControlStyle):
private func priceDisplay(for pickerOption: Configuration.PickerOption) -> String {
var result = ""
if pickerOption.introductoryOffer != nil {
result += NSLocalizedString("then", comment: "") + " "
}
result += pickerOption.displayPrice
if let unit = pickerOption.subscriptionPeriod?.unit {
result += " / " + unit.localizedDescription
}
return result
}
private func percentageSaved(for pickerOption: Configuration.PickerOption, allOptions: [Product]) -> Int? {
guard let subscriptionPeriod = pickerOption.subscriptionPeriod, subscriptionPeriod != .weekly else {
return nil
}
let weeklyOption = allOptions.first { otherOption in
otherOption.subscription?.subscriptionPeriod == .weekly
}
guard let weeklyOption, weeklyOption.price > 0 else {
return nil
}
let percentageSaved = 100 - (pickerOption.price / (weeklyOption.price * 52)) * 100
return Int((percentageSaved as NSNumber).doubleValue)
}
We're experiencing an issue with in-app purchases in our React Native iOS app where RNIap.getProducts() is consistently returning an empty array, preventing users from making purchases.
Technical Details:
Using react-native-iap library
Product ID: '[REDACTED]'
Platform: iOS
Product Type: Consumable (one-time payment, NOT subscription)
Error in logs: "No products returned from App Store. Check App Store Connect."
Debugging shows: Products Fetched: []
Steps to Reproduce:
Open app and navigate to the quiz feature
Attempt to purchase additional quiz attempts
Modal opens but fails to load product information
What We've Confirmed:
IAP Connection initializes successfully
No error is thrown during product fetch, just an empty array returned
App is configured with correct Bundle ID
Using Apple Sandbox test account
We are implementing consumable purchases (one-time payments)
Potential Issues to Investigate:
Product configuration in App Store Connect
Ensure product is set as "Consumable" type in App Store Connect
Sandbox tester account permissions/activation
Bundle ID matching between app and App Store Connect
Product ID case sensitivity or typos
FB19377002
I am looking to improve and review my subscription purchase handling logic, for the best user experience.
Considering that StoreKit2 caches local raw transactions (in case user is offline), is it really necessary to persist "unlocked status" in UserDefaults or SwiftData Model or AppStorage? Are there significant delays when reading Transaction.currentEntitlements from locally stored cache, versus reading it from UserDefaults; or, as in the latest SKDemo example, even reading it from stored in SwiftData ?
https://developer.apple.com/forums/thread/706450
I only have subscriptions ( I don't have noncosumable or consubale products). Do I still need to persist subscription status?
Hi everyone,
I’m facing a recurring issue with my macOS app being rejected during App Store review, and I’d really appreciate any guidance.
The subscription flow in my app is implemented using StoreKit, and everything works perfectly in our development environment using a StoreKit configuration file. It also behaves as expected in Sandbox testing and TestFlight — I even had few beta testers confirm that the subscription information is displayed correctly and the purchase flow completes without issues.
All required subscription details are configured in App Store Connect:
• Subscription duration and the description of the services offered
• Price and price per unit where applicable
• Paid apps agreement and related forms are correctly filled
However, when the app is submitted for review, the subscription screen fails to display the expected information. From what I can tell, the product information fails to load from the App Store in the review environment — even though everything is working fine on our side.
We’ve already submitted a video to Apple showing the subscription UI working in the Sandbox environment, but the app continues to be rejected under guideline 3.1.2 due to missing subscription info in the binary.
Is anyone else experiencing similar behavior during review? Could there be a caching issue or delay in StoreKit syncing for newly configured products?
Any help or suggestions are very welcome. Thanks in advance!
FB19376771
Transactions monitoring. If I only have subscriptions, do I really need to "bother" with any sort of monitorTransactions() or just rely on subscription status (subscribed, revoked, cancelled ...) ?
This is in line with Apple SKDemo and recommendation:
// Only handle consumables and non consumables here. Check the subscription status each time
// before unlocking a premium subscription feature.
switch transaction.productType {
ref: [https://developer.apple.com/documentation/storekit/implementing-a-store-in-your-app-using-the-storekit-api)
The "Only handle consumables and non consumables here" recommendation by Apple in ref to the process transaction code above is nuanced and confusing if we know what was with other external experts recommendation saying when using only SK2 Views :
"This is where most developers trip up in trying to get an experience that App Review is happy" ...
continuing :
"Be careful: that Purchase View code alone isn’t enough, because one of the possible completion status is .pending: the purchase is in the process of happening but hasn’t completed yet, so you still need to watch the transaction queue manually to be absolutely sure of handling the process completely."
Does this holds true for the new SubscriptionStoreView ?
We are not sure with quite obscure Apple documentation what SubscriptionStoreView handles, other than purchase (and now subscribe) function, and we do not know what diverse type of error handling messages it can return. Moreover, Apple documents: "Only handle consumables and non consumables here" ?
@Apple can you please share more insights on Purchase button on SubscriptionStoreView e.g
A) does it close ( finish). the purchase transaction ?
B) What error results can it return ?
C) What .onInAppPurchaseCompletion can handle as result ?
Hello 👋! I'm trying to switch the business model in my app from premium to freemium, gracefully so that existing users aren't bothered. I'd like to provide newly-paywalled content for original paid users. For this to work, I need to use originalAppVersion in AppTransaction, and support iOS 16 at minimum. I've asked about originalAppVersion earlier here.
I've upped to iOS 16 already, but I don't exactly know how to call AppTransaction.shared to get originalAppVersion. The issue lies in the fact that my app is based on SpriteKit, so the operative areas I have available to call AppTransaction are ostensibly limited to AppDelegate and GameViewController.
I'm using the code from Supporting business model changes by using the app transaction, but if I place it in either GameViewController or AppDelegate, for example in application(_:didFinishLaunchingWithOptions:) or viewDidLoad(), I get an error concerning async/await. Now, I understand the gist of it: these are not asynchronous methods. So I'm trying to understand how to do it perhaps outside of these methods.
How do I call AppTransaction.shared (and fetch originalAppVersion) in a SpriteKit based app?
Topic:
App & System Services
SubTopic:
StoreKit
I am handling the buy subscription with this function
const handleBuySubscription = async (productId) => {
try {
await requestSubscription({
sku: productId,
});
setLoading(false);
} catch (error) {
setLoading(false);
if (error instanceof PurchaseError) {
errorLog({ message: [${error.code}]: ${error.message}, error });
} else {
errorLog({ message: "handleBuySubscription", error });
}
}
};
but the
requestSubscription({
sku: productId,
})
does not return anything, and it is stuck at await
Hi! I’m new in programming apps for Apple Store and I’m creating my first app. I already send my for review but I get an answer of problems with the subs flow. If there’s anyone who can help me fix this problem and implement my subscriptions in my app and test it out I would be thankful, I want the flow work like in the image!
We’re testing SKAN postbacks via AdAttributionKit but aren’t receiving any requests on our server even after generating development impressions and triggering a postback.
Setup:
Domain: https://linkrunner-skan.com
Configured in Info.plist as:
<key>NSAdvertisingAttributionReportEndpoint</key>
<string>https://linkrunner-skan.com</string>
<key>AttributionCopyEndpoint</key>
<string>https://linkrunner-skan.com</string>
Apple automatically appends the .well-known paths:
/.well-known/private-click-measurement/report-attribution/
/.well-known/skadnetwork/report-attribution/
ATS diagnostics for the domain: PASS for all tests (TLS 1.0–1.3, PFS disabled, arbitrary loads allowed, etc.)
Both .well-known paths are publicly accessible and return 200 OK
Testing Flow:
Enabled Developer → AdAttributionKit Developer Mode on iOS (15+)
Followed Apple’s official guide: Testing AdAttributionKit with Developer Mode
Generated test impression using:
createAdAttributionKitDevelopmentImpression implemented in SKANManager.swift
Called Postback.updateConversionValue with lockPostback: true
Created Development Postback from Developer Settings
Waited 30+ minutes while intercepting server requests (proxy + backend logs)
What We’ve Tried So Far:
Confirmed ATS compliance with nscurl --ats-diagnostics (all PASS)
Verified .well-known paths are accessible publicly without redirects
Tested endpoints manually with a POST request – server responds 200 OK
Confirmed Info.plist entries exactly match Apple’s required keys
Double-checked iOS device is running iOS 15+ with Developer Mode enabled
Repeated test flow multiple times with fresh impressions and postbacks
Waited up to 1 hour for postback (in case of delays)
Issue:
No POST requests are being received from Apple to either .well-known endpoint, even though the setup appears correct and ATS tests pass.
References Used:
Configuring an Advertised App
Generating JWS Impressions
Question:
Has anyone faced a similar issue where AdAttributionKit Development Postbacks are not firing despite correct Info.plist setup, ATS compliance, and reachable .well-known endpoints?
Any insight into possible missing configuration steps or testing nuances would be greatly appreciated.
I'm using the SwiftUI view SubscriptionStoreView (https://developer.apple.com/documentation/storekit/subscriptionstoreview/) with a subscription group that has 2 subscriptions. I set up a free trial offer in App Store Connect (https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-introductory-offers-for-auto-renewable-subscriptions/). The storekit file in Xcode is synced with the App Store.
In debug build, this works and appears correctly, showing the free trial offer:
But in release build, the free trial offer is not shown:
The code is very simple:
SubscriptionStoreView(productIDs: [
"[PRODUCT ID FOR ANNUAL SUBSCRIPTION]",
"[PRODUCT ID FOR BIMONTHLY SUBSCRIPTION]"
])
Does anyone have a solution? Thank you.
(Xcode 16.3, macOS 15.5, iOS 18.5)
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
Hi, all!
I have an AppStore Server-side question. User sends up an AppReceipt that I am validating. What's the best way to tell the receipt belongs to said user? I want to make sure that the source of the AppReceipt was actually the original purchaser of the item. Is fetching Transaction + AppAccountToken the only way? AppAccountToken can only be utilized if the original purchase used it, and it is associated with the user's data. Is there another way?