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

In App Purchase does not work
I read the documentation and it told I had to prepare the product on App Store connect and once it is at the state "Ready to submit" I could access it on a phone where I am connected with an Icloud account in the developper list of the apple development account. This is what I've done but when I try to fetch in my flutter code the product with the id I set in App Store connect it says "No product found" Here is where I fetch the product: Future purchaseProduct(String productId) async { try { Set<String> _pIds = {productId}; final ProductDetailsResponse response = await _iap.queryProductDetails(_pIds); if (response.productDetails.isEmpty) { throw 'Product not found'; } final ProductDetails productDetails = response.productDetails.first; final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails); _iap.buyConsumable(purchaseParam: purchaseParam); } catch (e) { Services.debugLog('Error purchasing product: $e'); throw e; } } I checked the product ID and it does not seems to be the problem. Is there some other steps I need to do ?
2
0
360
Feb ’25
StoreKit Subscription Fails to Load During App Review, Works in Sandbox/TestFlight
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!
0
0
92
Apr ’25
Guideline 2.1 - Performance - App Completeness We found that your in-app purchase products exhibited one or more bugs which create a poor user experience. Specifically, we were unable to make purchase. The Start Free Trail button was unresponsive t
I've been stuck with this rejection. Trial button 'greyed out' or non responsive. What they are seeing is my subscriptions not loading into the pay wall. We think its because the subscriptions haven't been reviewed and approved in order for them to populate the pay wall (activating the pay wall so it isn't 'greyed out'. Has anyone had and solved this issue?
0
0
86
Jun ’25
Official document for CONSUMPTION_REQUEST - What kind of data we are receiving?
This documentation describes what kind of data we should be sending to Apple server, once we are receiving CONSUMPTION_REQUEST https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest But, it doesn't describe what kind of data we are receiving, when we are receiving CONSUMPTION_REQUEST? May I know, is such a document available? Thank you.
0
0
511
Dec ’24
Store Kit Set up
I'm working on my first subscription for an app I've built, and can't seem to figure out where I'm going wrong with this one whether it's something in Xcode or App Store Connect. Any idea where to start? Somethings to check. TIA.
0
0
266
Dec ’24
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
82
May ’25
Validating receipt for iOS in-app purchase always returns error 21002
I'm receiving the following error when attempting to validate an in‑app purchase receipt: Certificate verification failed at depth 0 : forge.pki.UnknownCertificateAuthority Certificate chain validation failed: Certificate is not trusted. This error occurs during the certificate chain validation process of the receipt's PKCS#7 container. My implementation uses node‑forge to decode the receipt, extract the embedded certificate chain, and verify that the chain properly links from the leaf certificate (which directly signed the receipt) through the intermediate certificate to the trusted Apple Inc. Root certificate. What the Error Indicates: "UnknownCertificateAuthority" at depth 0: This suggests that the leaf certificate in the receipt is not being recognized as part of a valid chain because it cannot be linked back to a trusted root in my CA store. "Certificate chain validation failed: Certificate is not trusted": This means that the entire certificate chain does not chain up to a trusted certificate authority (in this case, the Apple Inc. Root certificate) as expected. Steps Taken: I verified that the receipt is a valid PKCS#7 container. I extracted the certificate chain from the receipt. However, the receipt only provided the leaf certificate. I manually added the intermediate certificate (AppleWWDRCAG5.pem) to complete the chain. I loaded the official Apple Inc. Root certificate (AppleIncRootCertificate.pem) into my CA store. Despite these steps, the validation still fails at depth 0, indicating that the leaf certificate is not recognized as being issued by a trusted authority. Request for Assistance: Could you please help clarify the following points: Is the certificate chain for receipts (leaf → intermediate → Apple Inc. Root) as expected, or has there been any change in the chain that I should account for? Is there a recommended or updated intermediate certificate I should be using for receipt validation? Are there known issues or recent changes on Apple's side that might cause the leaf certificate to not be recognized as part of a valid chain? Any guidance to resolve this certificate chain validation error would be greatly appreciated.
1
0
300
Mar ’25
[In-App Purchase] first trial but "is_trial_period" false
This question is about In-App Purchase. This is an inquiry from one of our customers. We have set up a free trial. This is your first time using the service, but you have stated that you have been charged. Document. https://developer.apple.com/documentation/appstorereceipts/is_trial_period 「You can use this value to determine whether the specific record is in a subscription trial period. If a previous subscription period in the receipt has the value "true" for either the is_trial_period or is_in_intro_offer_period keys, the user is not eligible for a free trial or introductory price within that subscription group.」 Our expectation is that is_trial_period is true. Receipt is not contain is_trial_period : true or is_in_intro_offer_period : true. Only one case has occurred. Other customers are no problem.
0
0
397
Dec ’24
How to validate Streamlined Purchasing with storekit 2
users download app with Streamlined Purchasing ,but the logic of checking subscription doesn't work. there the code: func checkSubscriptionStatus() async { for await entitlement in Transaction.currentEntitlements { guard case .verified(let transaction) = entitlement else { continue } if transaction.productID == monthlyProductID || transaction.productID == yearlyProductID { if transaction.revocationDate == nil && !transaction.isUpgraded { let activeSubscribed = transaction.expirationDate ?? .distantFuture > .now if activeSubscribed { hasActiveSubscription = activeSubscribed // other operation } } } } }
0
0
243
Mar ’25
Using child accounts with sandbox IAP testing
Hello, thank you for your time. I'm using several physical devices to test IAPs in builds from xCode. Some of my test devices are logged into child accounts from my family account. Child accounts "Ask Permission" from devices logged into adult accounts in the family. when you attempt to make a purchase. I'm hoping to be able to use these devices to test my IAPs but I get the following error after supplying the password for the sandbox account: Unable to Ask Permission You can't ask permission because you have signed in with iCloud and iTunes accounts that are not associated with each other. [Environment: Sandbox] Is there any way to make this work?
2
0
999
Jan ’25
Revoked Non-Consumable Purchases & currentEntitlements
We use Transaction.currentEntitlements in StokeKit 2 to unlock functionality based on a Non-Consumable IAP but we have a case involving a refund that seems wrong and I am trying to understand the interation between transactionId, originalTransactionId & revocationReason. The Context: We have a universal App on macOS and iOS that offers a shared Non-Consumable IAP. For this example I have named it "app.lifetime" On macOS we use StoreKit 2 and I am calling the Transaction.currentEntitlements and Transaction.all functions. On iOS we are still using StoreKit 1. This example customer: Originally purchased "app.lifetime" on 2024-10-27 Was refunded by Apple for "app.lifetime" on 2024-10-29 Re-purchased "app.lifetime on 2025-02-24 (I have seen an email receipt of this transaction but it never shows up in Transaction data) (all the above happened on the mac via StoreKit 2) The Transactions (all lightly redacted for privacy): on macOS the following is returned from Transaction.currentEntitlements... { "appTransactionId" : "...8123", "bundleId" : "app", "currency" : "USD", "deviceVerification" : "...", "deviceVerificationNonce" : "...", "environment" : "Production", "inAppOwnershipType" : "PURCHASED", "originalPurchaseDate" : 1729997808000, "originalTransactionId" : "...9955", "price" : 1, "productId" : "app.lifetime", "purchaseDate" : 1729997808000, "quantity" : 1, "signedDate" : 1740416289102, "storefront" : "USA", "storefrontId" : "143441", "transactionId" : "...7511", "transactionReason" : "PURCHASE", "type" : "Non-Consumable" } Note in the above example the originalTransactionId & transactionId are different. Transaction.all however returns both transactions: [ { "appTransactionId" : "...8123", "bundleId" : "app", "currency" : "USD", "deviceVerification" : "...", "deviceVerificationNonce" : "...", "environment" : "Production", "inAppOwnershipType" : "PURCHASED", "originalPurchaseDate" : 1729997808000, "originalTransactionId" : "...9955", "price" : 1, "productId" : "app.lifetime", "purchaseDate" : 1729997808000, "quantity" : 1, "revocationDate" : 1730224102000, "revocationReason" : 0, "signedDate" : 1740415969925, "storefront" : "USA", "storefrontId" : "143441", "transactionId" : "...9955", "transactionReason" : "PURCHASE", "type" : "Non-Consumable" }, { "appTransactionId" : "...8123", "bundleId" : "app", "currency" : "USD", "deviceVerification" : "...", "deviceVerificationNonce" : "...", "environment" : "Production", "inAppOwnershipType" : "PURCHASED", "originalPurchaseDate" : 1729997808000, "originalTransactionId" : "...9955", "price" : 1, "productId" : "app.lifetime", "purchaseDate" : 1729997808000, "quantity" : 1, "signedDate" : 1740416289102, "storefront" : "USA", "storefrontId" : "143441", "transactionId" : "...7511", "transactionReason" : "PURCHASE", "type" : "Non-Consumable" } ] Note here that the original transaction ("...9955") includes a revocationDate and revocationReason that match the expected refund but the secondary transaction that seems to match on all other details is missing the revocation info. Looking at the iOS SK1 receipt data to compare, after a receipt refresh I see only a single transaction "...9955" which includes the cancellation info and transaction "...7511" is not present at all. The impact of this is that on iOS we are considering the purchase void but on macOS we are following currentEntitlements and consdering it still valid. Calling the inApps/v1/history/... server API with the "...7511" transactionId that is shown in the currentEntitlements response returns the "...9955" transaction with the correct revocation status but "...7511" is no returned at all. To Summarise: currentEntitlements on macOS shows transaction "...7511" as active and with an originalTransactionId of "...9955" all on macOS includes both "...7511" as active and "...9955" as revoked iOS reciept data shows only "...9955" as revoked Server API shows only "...9955" as revoked event when explicitly called with "...7511" Neither of them show a more recent purchase the same customer made for the same IAP product. My questions are: Is this a StoreKit bug or am I mis-understanding something? If it's a bug how can I work around it to ensure revoked purchases aren't still appearing in currentEntitlements? Under what conditions can StoreKit generate multiple transactionIds for the same underlying originalTransactionId? I had assumed (and the docs suggest) this only happens for subscriptions but here it is happening for a Non-Consumable IAP. Why would transactionId "...7511" only be present on macOS/SK2 and not visible at all on iOS/SK1 or API? I don't understand why the latest IAP from 2025-02-24 that the customer assures me they made (and has shown me the receipt for is not showing up in the Transactions history at all. Any ideas?
2
0
334
Mar ’25
TestFlight Subscription Upgrade Handling
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.
0
0
103
May ’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
213
Mar ’25
Offer Code Transaction
Hello, We're trying to implement and test offer codes in our app. We have create all the necessary items in the App Store. The app has been reviewed and approved for release. We have not published it yet. We are redeeming the offer using a URL that opens the App Store. When I redeem, the account is updated, but the app does not see the Transaction. We implemented using this: https://developer.apple.com/documentation/storekit/transaction First, we used the Transaction.updates and then we added Transaction.all and neither return any Transaction. Any ideas with there are any other dependencies that are required here or recommendations for how to test?
5
0
425
Dec ’24
Why can't the app get the subscription status occasionally?
Hi, I have developed an app which has two in-app purchase subscriptions. During the test, the app can successfully get the status of the subscriptions. After it's released, I downloaded it from app store and subscribed it with my apple account. I found that in most cases, the app can identify that I have subscribed it and I can use its all functions. But yesterday, when I launched it again, it showed the warning that I haven't subscribed it. I checked my subscription in my account and the subscription status hasn't been changed, that is, I have subscribed it. And after one hour, I launched it again. This time the app identified that I have subscribed it. Why? The following is the code about listening to the subscription status. Is there any wrong about it? HomeView() .onAppear(){ Task { await getSubscriptionStatus() } } func getSubscriptionStatus() async { var storeProducts = [Product]() do { let productIds = ["6740017137","6740017138"] storeProducts = try await Product.products(for: productIds) } catch { print("Failed product request: \(error)") } guard let subscription1 = storeProducts.first?.subscription else { // Not a subscription return } do { let statuses = try await subscription1.status for status in statuses { let info = try checkVerified(status.renewalInfo) switch status.state { case .subscribed: if info.willAutoRenew { purchaseStatus1 = true debugPrint("getSubscriptionStatus user subscription is active.") } else { purchaseStatus1 = false debugPrint("getSubscriptionStatus user subscription is expiring.") } case .inBillingRetryPeriod: debugPrint("getSubscriptionStatus user subscription is in billing retry period.") purchaseStatus1 = false case .inGracePeriod: debugPrint("getSubscriptionStatus user subscription is in grace period.") purchaseStatus1 = false case .expired: debugPrint("getSubscriptionStatus user subscription is expired.") purchaseStatus1 = false case .revoked: debugPrint("getSubscriptionStatus user subscription was revoked.") purchaseStatus1 = false default: fatalError("getSubscriptionStatus WARNING STATE NOT CONSIDERED.") } } } catch { // do nothing } guard let subscription2 = storeProducts.last?.subscription else { // Not a subscription return } do { let statuses = try await subscription2.status for status in statuses { let info = try checkVerified(status.renewalInfo) switch status.state { case .subscribed: if info.willAutoRenew { purchaseStatus2 = true debugPrint("getSubscriptionStatus user subscription is active.") } else { purchaseStatus2 = false debugPrint("getSubscriptionStatus user subscription is expiring.") } case .inBillingRetryPeriod: debugPrint("getSubscriptionStatus user subscription is in billing retry period.") purchaseStatus2 = false case .inGracePeriod: debugPrint("getSubscriptionStatus user subscription is in grace period.") purchaseStatus2 = false case .expired: debugPrint("getSubscriptionStatus user subscription is expired.") purchaseStatus2 = false case .revoked: debugPrint("getSubscriptionStatus user subscription was revoked.") purchaseStatus2 = false default: fatalError("getSubscriptionStatus WARNING STATE NOT CONSIDERED.") } } } catch { // do nothing } if purchaseStatus1 == true || purchaseStatus2 == true { purchaseStatus = true } else if purchaseStatus1 == false && purchaseStatus2 == false { purchaseStatus = false } return }
0
0
198
Mar ’25
Migrating to StoreKit 2
Hi Friends, I have an iOS app, which uses around 500 in app purchases for various modules. I am using StoreKit for in app purchase, now trying to migrate this to StoreKit 2. I am using Product.products(for:) method to fetch all the products by sending identifiers of all the 500 In app purchases. In response, I am getting details of only 160 products, the method is not returning remaining in app purchases. What could be the reason for this behaviour, how to get rid of the issue? May be is this the issue will happen only on TestFlight? If someone from Apple assures about it, we have plan to submit the app. Please advise, Thank you.
0
0
87
May ’25