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

Activity

Mismatch between App Store Server API `expiresDate` (July 23) and iOS UI “Expires on” date (July 22) for 1-month subscription
Hi everyone, I’m seeing a consistent one-day discrepancy between the expiresDate returned by the App Store Server API and the “Expires on” date shown in the iOS Settings / App Store subscription list. I’d like to confirm whether this behavior is expected or if I’m misunderstanding the way Apple rounds dates. Reproduction steps Step Action Result 1 Purchase a 1-month auto-renewable subscription on 23 June 2025 14:00 JST (UTC+9) Transaction succeeds 2 Immediately fetch the transaction with GET /inApps/v1/subscriptions/{transactionId} Response contains "expiresDate": "2025-07-23T05:00:00Z" (= 23 July 2025 14:00 JST) 3 On the same device open Settings › Apple ID › Subscriptions (or App Store › Account › Subscriptions) UI shows Expires on: 22 July 2025 The same happens for every monthly renewal and on multiple devices. Region is Japan, device time zone Asia/Tokyo. What I understand so far (and my hypothesis) Apple’s docs say a monthly subscription renews “on the same calendar date” of the next month, so renewal in this example is 23 July. If the renewal is scheduled for 23 July at 14:00 JST, the subscription is fully usable until the end of 22 July in calendar terms, because the new billing period starts the moment the 23rd begins in Apple’s canonical time zone. Therefore, it might be intentional for the UI to display 22 July—i.e., “you can keep using it through the 22nd; on the 23rd it renews.” This hypothesis makes sense internally, yet it still looks confusing to end users who read “Expires on 22 July” and assume access ends at 00:00 on the 22nd, a whole day earlier than in reality. Questions Is showing the day before the renewal date the official/expected behavior? If so, could Apple clarify that the “Expires on” label represents the last full calendar day rather than the exact expiry timestamp? Which value should we surface in-app when telling users “Your subscription is valid until …”? The server’s expiresDate (precise to the second, converted to user time zone), or A UI-style date that’s one day earlier, matching Settings / App Store? Does Apple have a public document describing this rounding/visual convention? Have other developers encountered user confusion about the apparent 1-day “shortening” and, if so, how did you word your in-app messaging? Any insight from Apple engineers or fellow developers would be greatly appreciated. Thank you!
0
1
275
Jun ’25
InApp purchases ok and ko at the same time (?!)
I'm working on an app the has implemented inapp purchases. They have been working so far, and they keep working currently. But just a couple of days ago, a specific user sent us a support ticket stating that when he purchases and item the bank charges it for the purchase, but within the app, the purchase fails and he doesn't receive the item. He sent us screenshots showing: The iOS native modal when a purchases has been finished correctly ("You're all set - Your purchase was successful "). Right after that modal, the app shows an internal modal showing "The purchase failed, please, try again later". Checking the app logs, that failure modal was triggered by "The operation couldn’t be completed. (StoreKit.StoreKitError error 1.)". Reading docs about this error leads me to think about device or user restrictions (parental controls, usage limits, etc...). It seems that in theses cases the bank charge could be issued but refunded later once Apple ultimately declines the purchase. However the user says that he doesn't have any kind of restriction. The only related thing is a "this device is also restricted by a profile" message, but everyone seems to have this message. What could it be causing this issue? In what scenariowould the app show a native OK modal but a storekit error 1? I'm pretty sure the app is well configured because I keep receiving purchases of all kind, from different users with any problem.
0
0
341
Mar ’25
Show Price Increase Consent
I'm currently still on StoreKit 1, and am testing the paymentQueueShouldShowPriceConsent delegate function. In my local .storekit file, I have a renewable subscription set up with a promotional offer. My test flow is as follows: User subscribes to renewable subscription Let subscription auto-renew once or twice User subscribes to renewable subscription with promotional offer with significant price reduction Promotional offer lapses and price increases to normal Expect paymentQueueShouldShowPriceConsent delegate function to trigger However, #5 never does get invoked, despite re-trying the subscription and promotional offers in various configurations. Manually triggering the Request Price Increase Consent option in the Xcode StoreKit transactions list does invoke the delegate function, but letting the promotional offer lapse does not. My storefront is set to Korea, and my simulator region is set to Korea as well. According to the documentation here and here, consent is required for all price increases in Korea. Is there some way I could check if things are working as intended?
0
0
82
Apr ’25
My Subscription Screen
Hey everyone, This might be a simple fix that I’m just overlooking, but I’ve been stuck on it for the past 48 hours. The issue is on my subscription screen — after a user completes a successful in-app purchase, the app doesn’t navigate to the main app like it’s supposed to. I’ve added logs, tried various fixes, and even asked AI for help, but nothing has worked. From what I can tell, it seems like my listeners aren’t being registered properly after the transaction. I’ve tried reinitializing them, moving them around, and testing different flows, but still no luck. If anyone has insight into how they’ve set this up or any suggestions I might not have considered, I’d really appreciate it. Thanks in advance!
0
0
64
Aug ’25
StoreKit returns restored for SKUs marked Consumable (no purchase sheet); Flutter in_app_purchase + SK2
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!
0
0
181
Sep ’25
Unexpected Change in Apple Refund Handling CONSUMPTION_REQUEST - Impact on Subscription App with AI Backend
We offer a 3-day free trial, and our paywall clearly states that users will be charged after the trial ends. However, some users request refunds after the charge - even after fully using our app for days or even weeks. In some cases, refunds are approved despite the users having consumed our AI processing services for up to a month. Since our app relies on backend AI processing, each user session incurs a real cost. To prevent losses, we utilize RevenueCat’s CONSUMPTION_REQUEST system and have set our refundPreference to: "2. You prefer that Apple declines the refund". Until recently, Apple typically respected this preference, and 90% of refund requests were declined as intended. However, starting about a week ago, we observed a sudden reversal: Apple is now approving around 90% of refund requests, despite our refund preference. As a result, we are operating at a loss and have had to halt both our marketing campaigns and our 3-day free trial. We’re trying to understand whether this shift is due to a change in Apple’s refund policy, or if we need to handle CONSUMPTION_REQUEST differently on our end. Has anyone else experienced similar changes? Any insights would be greatly appreciated.
0
1
358
May ’25
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
29
Nov ’25
Duplicate In-App Order with two Different Transaction ID
User Initiated a Single Consumable Purchase but Was Charged Twice A user initiated a single in-app purchase for a consumable item, but they were charged twice. Both transactions have the same purchase token. Additional details: After the user successfully completed the in-app purchase, the completeTransactions callback was triggered again. This was called at app launch using SwiftyStoreKit.completeTransactions to finish any pending transactions. Could this be causing the duplicate charge? Any insights would be appreciated.
0
0
237
Mar ’25
Can't fetch products
Use the following method to fetch: let appProducts = try await Product.products(for: productIdentifiers) The following checks have been carried out ✅ Must-check points App ID capabilities Subscription product status (ready to submit) Why The result is an empty array?
0
0
60
Sep ’25
StoreKit 2: jwsRepresentation Validation, Rate-Limit Relief, and Send Consumption Info Effectiveness
Hi everyone, We operate an online game where all in-app assets are stored server-side and require a logged-in account (no device binding). I’d like guidance on four areas: Do we really need deviceVerification / deviceVerificationNonce? – Because every purchase is tied to an account and we enforce a global transactionId UNIQUE constraint, replay or cross-account reuse appears infeasible. Under these conditions, is omitting device verification acceptable, or are there situations where Apple still recommends it? Permanent rate-limit increase for the App Store Server API – During anniversary events we saw bursts of ~18 000 requests per hour, breaching the current hourly cap on the App Store Server API (verifyTransaction, getNotificationHistory, etc.). Is there a formal process to request a long-term rate-limit expansion (or an alternative tier) from Apple? When is an App Store Server API call required for a StoreKit 2 jwsRepresentation? Docs say “call the API if you’re unsure,” but there’s no clear cut-off. Because we fully validate the JWS signature plus the entire certificate chain (including CRL/OCSP checks) on our server, local cryptographic validation seems sufficient for consumables. For subscriptions we still plan to hit the API to fetch the latest status. Does this separation match Apple’s best practice? If Apple does recommend hitting the API for consumables as well, we’d like a concrete rule of thumb—e.g. “if the item price is USD 50 or higher, always use the API.” Is establishing such thresholds consistent with Apple’s intent? Refund-risk reduction from Send Consumption Info – Adapty reports a 40–60 % refund-rate drop for subscriptions when using Send Consumption Info (blog reference). Can we expect similar reduction for consumable IAP in social/online games? Any real-world results would be helpful. Thanks in advance for any guidance!
0
0
190
Apr ’25
in-app purchases
I implemented consumable in-app purchases in an iPhone app using ProductView(). When I tap the payment button in ProductView(), I am taken to the payment screen and once the payment is completed the next code seems to be executed, so there doesn't seem to be a problem, but if I tap the payment button in ProductView() again, the next code is executed without taking me to the payment screen. This means that a single payment can be made multiple times. Can someone help? ProductView(id: "geminiOneMatch") .productViewStyle(.compact) .padding() .onInAppPurchaseCompletion { product, result in if case .success(.success(_)) = result { // 課金が成功した場合の処理 gemini.addOneMatch(amount: 20) popUpVM.geminiOneMatchPopUp = false dataManageVM.generateRespons(locale: locale) } }
0
0
243
Jul ’25
Regarding the pattern of multiple original transaction IDs being linked
In the app we're distributing, we've identified a user where the Get All Subscription Statuses API returns two original transaction IDs in the data response. This user has gone through cancellations and re-subscriptions since their initial purchase. Meanwhile, despite maintaining a continuous subscription, a notification suddenly arrives on the renewal date with original_transaction_id2. +---------------------------+---------------------------+---------------------+ | original_transaction_id | notification_type | subtype | +---------------------------+---------------------------+---------------------+ | original_transaction_id1 | SUBSCRIBED | INITIAL_BUY | ~ Repeated cancellations and re-subscriptions ~ | original_transaction_id1 | SUBSCRIBED | RESUBSCRIBE | | original_transaction_id2 | SUBSCRIBED | INITIAL_BUY | +---------------------------+---------------------------+---------------------+ Although it can be inferred from the interface definition of the API itself that multiple original transaction IDs may be returned, what causes multiple original transaction IDs to be returned? Furthermore, is it possible to reproduce the case where multiple original transaction IDs are returned in the sandbox environment provided by Apple? As for this app, it: Uses subscriptions through in-app purchases. Does not offer upgrades, downgrades, or crossgrades, having only one product. Has never undergone price increases or decreases. Is distributed exclusively in Japan.
0
0
89
Jun ’25
Subscription Cancellation
Hi Team, I’ve successfully implemented the subscription flow for my app. However, I’m currently facing challenges related to testing the cancellation behavior for auto-renewable subscriptions. Specifically: I’m unable to locate the correct payload structure for the following test endpoint: https://api.storekit-sandbox.itunes.apple.com/inApps/v1/notifications/test I’m also unclear on how to simulate or complete the full lifecycle of a subscription (including cancellation) using Apple’s sandbox environment or APIs. Could you please guide me on how to: Retrieve or construct the proper payload for the test notification API? Simulate a cancellation flow end-to-end in the sandbox for auto-renewable subscriptions?
0
0
106
May ’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
219
Nov ’25
How to test each status of Get All Subscription Statuses of App Store Server API
I am currently using the App Store Server API Get All Subscription Statuses in the app I am in charge of. Please let me confirm the following regarding Get All Subscription Statuses. ■Prerequisites The language used is Objective-c, and I am using both XCode 15 and 16. I also have an App Store Connect account. ■Questions Is it possible to set and test each status of the App Store Server API Get All Subscription Statuses with TestFlight?
0
0
68
Mar ’25
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
2
82
Nov ’25
(verifyreceipt) I cannot verify from the server whether the user's iap payment is successful or not
I have three questions about verify receipt I use this api (https://buy.itunes.apple.com/verifyReceipt)to verify receipt is success or not. But since last month, this interface has started to return an error(21002). I see this document (https://developer.apple.com/documentation/appstorereceipts/verifyreceipt) say its Deprecated. My question is, is the error suddenly returned recently because the interface has been deprecated or for some other reason? (I haven't modified my code about this recently) 2. I can not understand this document: (https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device) Does this mean that in the new version, as long as the app returns a payment success (purchaseDetails.status == PurchaseStatus.purchased), the payment is guaranteed to be successful, and my server does not need to request payment result verification from Apple's server? 3. I try to use this (https://github.com/apple/app-store-server-library-java) to get TransactionInfo, but I dont konw to get Transaction status to know is success or not. my java server code : AppStoreServerAPIClient client = new AppStoreServerAPIClient(encodedKey, keyId, issuerId, bundleId, environment); TransactionInfoResponse response = client.getTransactionInfo(transactionId); (bug i can note get transaction status, how do i konw this Transaction is success or not)
0
0
76
Aug ’25