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

StoreKit 2 - Is it necessary to finish unverified transactions?
The sample code provided in https://developer.apple.com/wwdc21/10114 doesn't appear to call finish() on unverified transactions, and I haven't been able to find any documentation regarding what to do with unfinished transactions. However, Apple has always emphasized the importance of finishing transactions, and since a transaction object is provided even with the unverified state, I'd love some guidance!
4
1
2.8k
May ’25
In app purchases
Hey guys, This is a general question, but I have been working on an app for a while and I would like to to introduce IAP to the app. I have no clue where to start and chat GPT is no help. I also tried to vibe coding the IAP function and that didn't work out well. Any material or advice would help.
4
0
91
Jan ’26
Xcode 26 beta 3: StoreKit Testing broken
It seems that beta 3 broke StoreKit Testing when running against an iOS 26 simulator device. Specifically, when validating product IDs, the debug console displays messages like the following: [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) [492a4cfa_SK1] Could not parse product: missingValue(for: [StoreKit.ProductResponse.Key.price], expected: StoreKit.BackingValue) In addition, the SKProductsResponse (I am using the original StoreKit API), lists all requested product IDs in invalidProductIdentifiers. The products array is empty. StoreKit Testing behaves as expected when Xcode 26 beta 3 is run against an iOS 18.4 simulator device.
4
0
373
Aug ’25
In iOS 26 beta3 version, the finishTransaction method is unable to remove transactions from the SKPaymentQueue, causing transactions to remain in the queue even after being processed.
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.
4
0
323
Jul ’25
How to change promotional image of in-app purchase
My apps stuck on review stage. Reason of it is Guideline 2.3.2 - Performance - Accurate Metadata We noticed that your promotional image to be displayed on the App Store does not sufficiently represent the associated promoted in-app purchase. Specifically, we found the following issue with your promotional image: – Your promotional image is the same as your app’s icon. The problem is i can't change this image. My subscription is still in 'in review' stage and I don't have option like delete image or change image. I replied to the review explaining that I cannot change it as long as the subscription is under review, but I haven’t received any meaningful reply, except that I need to change promotion image to be eligible for further review(which i cant do because i haven't option to change this image). Has anyone had such a problem before?
4
2
2.0k
Oct ’25
StoreKit2: appAccountToken in purchase() always returns first value instead of updated UUID
Hello, I’m experiencing an issue with StoreKit 2 when passing a new appAccountToken for each purchase request. Case-ID: 15948169 (for DTS reference) Description of the Problem When initiating a purchase, I generate a new UUID to use as the appAccountToken: let serverTransactionId = UUID() let options: Set<Product.PurchaseOption> = [ .appAccountToken(serverTransactionId) ] let result = try await product.purchase(options: options) Expected Behavior: Each new purchase should return the updated appAccountToken that I pass into the purchase options. Actual Behavior: The payload response after success always contains the same appAccountToken from the very first transaction. It ignores subsequent UUIDs I pass and keeps reusing the original one. This causes issues because the same identifier is being reused across multiple transactions, making it difficult to map purchases to the correct user session. Steps to Reproduce Generate a fresh UUID using UUID(). Pass it as .appAccountToken when calling purchase(). Complete the transaction in the sandbox environment. Inspect the payload response → The appAccountToken value is always the same as the first one used, not the newly provided one. Additional Info I do have a focused test project that reproduces this issue. The issue appears specific to appAccountToken persistence across multiple transactions. Has anyone else experienced this behavior with StoreKit 2? Is this expected (Apple caching the first token) or could this be a bug?
3
1
373
Nov ’25
Not able to renew membership
You can still renew your membership within the next 8 days and your apps will remain available on the App Store during this time. Open the Apple Developer app on your iPhone, iPad, or Mac. Sign in to your account, tap/click Renew, and follow the prompts. I'm getting this message but renew button is not visible in Developer App or on website. How to to renew?
3
0
809
Oct ’25
Unable to Authenticate with App Store Server API in Production (401 Error)
Our application is currently under review, and we are still facing issues because we receive a 401 Unauthorized response from the App Store Connect API when using the production environment. Our app integrates with Chargebee for subscription management, and in production, Chargebee is unable to authenticate with the App Store Server API. This results in a 401 Unauthorized error, preventing the user’s subscription from being synced correctly into our system. Interestingly, the same configuration works in the sandbox environment, but fails in production. We’ve tried authenticating using JWTs generated from multiple keys (including App Store Connect API / Team Keys with both Admin and App Manager access, and also In-App Purchase keys), all with the same result — sandbox access works, production does not. Here is our example code for testing with JWT token: const jwt = require('jsonwebtoken'); const fs = require('fs'); const https = require('https'); const config = { keyId: '<key_id>', issuerId: 'issuer_id', bundleId: 'bundle_id', privateKey: fs.readFileSync('path_to_key') }; const { keyId, issuerId, bundleId, privateKey } = config; const now = Math.floor(Date.now() / 1000); const jwtToken = jwt.sign( { iss: issuerId, iat: now, exp: now + 60 * 10, // 10 minutes is fine for test aud: 'appstoreconnect-v1', bid: bundleId }, privateKey, { algorithm: 'ES256', header: { alg: 'ES256', kid: keyId, typ: 'JWT' } } ); console.log('Generated JWT:\n', jwtToken); // prod const originalTransactionId = '<prod_transaction_id>'; const hostname = 'api.storekit.itunes.apple.com'; // sandbox // const originalTransactionId = '<sandbox_transaction_id>'; // const hostname = 'api.storekit-sandbox.itunes.apple.com' const options = { hostname, port: 443, path: `/inApps/v1/history/${originalTransactionId}`, method: 'GET', headers: { Authorization: `Bearer ${jwtToken}`, 'Content-Type': 'application/json', }, }; const callAppStoreConnectApi = async () => { const req = https.request(options, (res) => { console.log(`\nStatus Code: ${res.statusCode}`); let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { console.log('Response Body:\n', data || '[Empty]'); }); }); req.on('error', (e) => { console.error('Request Error:', e); }); req.end(); }; callAppStoreConnectApi(); With this code, we were able to authenticate successfully in the sandbox environment, but not in production. I read in this discussion: https://developer.apple.com/forums/thread/711801 that the issue was resolved once the app was published to the App Store, but I haven’t found any official documentation confirming this. Does anyone know what the issue could be?
3
2
375
Oct ’25
Unexpected notificationType in App Store Server Notifications V2 when free trial ends
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?
3
0
182
Sep ’25
StoreKit doesn't always work correctly in sandbox environment
There is an issue with StoreKit. The line let products = try await StoreKit.Product.products(for: ids) doesn't always work correctly. Sometimes it returns an array with the correct data, and sometimes it returns an empty array. I'm passing the correct ids to products(for:). This problem only occurs when using the sandbox environment (in TestFlight builds). In the App Store version, everything works fine. StoreKit configuration is none. All IAPs are approved. Everything was working fine before this. The problem was discovered on May 1, 2025.
3
15
538
May ’25
HELP WITH SUBSCRIPTIONS
Hey everyone, I really need help. My app versions keep getting approved for distribution and my subscriptions and business agreements are all approved. Yet, when the paywall in my app appears, and someone clicks the subscribe button to pay, the IAP isn't appearing. It just loads forever. When I tested in Xcode it just kept saying products not found. Id's are the same, bundle id is the same, ive done everything. Can someone help pls.
3
0
204
Jan ’26
Transaction ID Misassociation in IAP Subscription API
Dear Apple Support Team, Hello! I am currently developing the in-app subscription functionality using Apple IAP API and have encountered a serious technical issue while processing subscription data. I would like to report this issue to you. Issue Description: When calling the subscription API endpoint, the same OriginalTransactionId returns inconsistent results. Specifically, a particular transaction ID (let's call it TransactionId_A) should belong to the subscription order with OriginalTransactionId_A, but it is currently incorrectly associated with OriginalTransactionId_B. This issue severely affects our ability to accurately manage and process subscription data. Here are the relevant log details for your reference: API Endpoint Requested: https://api.storekit.itunes.apple.com/inApps/v1/subscriptions/{TransactionId_A} (Note: The link is a placeholder for the actual API endpoint.) Log Information on February 21, 2025, at 09:40:09: { "AppAccountToken": "{AppAccountToken}", "BundleId": "{BundleId}", "Currency": "CNY", "Environment": "Production", "ExpiresDate": {ExpiresDate}, "InAppOwnershipType": "PURCHASED", "IsUpgraded": false, "OfferDiscountType": "", "OfferIdentifier": "", "OfferType": 0, "OriginalPurchaseDate": {OriginalPurchaseDate}, "OriginalTransactionId": "{OriginalTransactionId_A}", "Price": {Price}, "ProductId": "{ProductId}", "PurchaseDate": {PurchaseDate}, "Quantity": 1, "RevocationDate": 0, "RevocationReason": 0, "SignedDate": {SignedDate}, "Storefront": "CHN", "StorefrontId": {StorefrontId}, "SubscriptionGroupIdentifier": "{SubscriptionGroupIdentifier}", "TransactionId": "{TransactionId_A}", "TransactionReason": "PURCHASE", "Type": "Auto-Renewable Subscription", "WebOrderLineItemId": "{WebOrderLineItemId}" } Log Information on March 21, 2025, at 09:38:49: { "AppAccountToken": "{AppAccountToken}", "BundleId": "{BundleId}", "Currency": "CNY", "Environment": "Production", "ExpiresDate": {ExpiresDate}, "InAppOwnershipType": "PURCHASED", "IsUpgraded": false, "OfferDiscountType": "", "OfferIdentifier": "", "OfferType": 0, "OriginalPurchaseDate": {OriginalPurchaseDate}, "OriginalTransactionId": "{OriginalTransactionId_B}", "Price": {Price}, "ProductId": "{ProductId}", "PurchaseDate": {PurchaseDate}, "Quantity": 1, "RevocationDate": 0, "RevocationReason": 0, "SignedDate": {SignedDate}, "Storefront": "CHN", "StorefrontId": {StorefrontId}, "SubscriptionGroupIdentifier": "{SubscriptionGroupIdentifier}", "TransactionId": "{TransactionId_A}", "TransactionReason": "PURCHASE", "Type": "Auto-Renewable Subscription", "WebOrderLineItemId": "{WebOrderLineItemId}" } From the above logs, it is evident that the same transaction (TransactionId_A) returns different OriginalTransactionId values at different times, which is clearly not expected and severely impacts our ability to correctly process and manage subscription data. I hope you can address and investigate this issue as soon as possible. If you need any further information or assistance, please feel free to contact me. Thank you for your support! Best regards!
3
3
440
Mar ’25
Unknown Error when Trying to Add New Offer Codes
Hi there! Whenever I try to add a new Offer Code for my app's subscription, I get an unknown error. When I get to the last step of the "Create Offer for Codes" flow, I get an error that error reads "An error has occurred. Try again later." I have been getting this same error for over a week now, so any help figuring out how to add new offer codes would be greatly appreciated!
3
1
635
Dec ’25
StoreKit Sandbox – Unfinished Consumable Transaction Across Devices
I’d like to confirm the expected behavior of StoreKit 2 in the Sandbox environment regarding unfinished consumable transactions across devices. Scenario: Device A and Device B are signed in with the same Sandbox Apple ID A consumable in-app purchase is completed on Device A The transaction may be verified or unverified, but transaction.finish() is not called The app is then launched on Device B and listens for Transaction.updates Question: In this scenario, is it expected that Device B will or will not receive a callback for this unfinished consumable transaction? Or is it by design that unfinished consumable transactions are not guaranteed to be delivered across devices, regardless of verification state?
3
0
109
6h
StoreKit2, IAP not instantly shared with Family
Hey folks! In one of our apps we're using the FamilyControls framework to manage the screentime for the child. The app requires the Guardian to activate a subscription on his/her device to enable the functionality for the Child on the child device. We're currently using StoreKit 2 to get notified when there is an active subscription. The issue we're seeing (and our users) is that an activated subscription isn't instantly propagated to the Family members, in this case the device belonging to the child. Is this a known bug, and are the possible any workarounds? Currently we have to ask our users to "Restore Purchase" or wait minutes/hours for the app to active, which isn't a viable solution. We want it to "just work" :) Sincerely, César Pinto Castillo Ambi Studio
3
0
117
May ’25
Notification Received on Consumable Purchase
Hello, I am encountering an issue where I receive an App Store Server Notification V2 upon the purchase of a consumable item. I have configured the App Store Server Notification V2 endpoint to handle notifications related to subscription products. However, I did not expect to receive notifications for consumable purchases. The notification includes the following signedPayload decoded into the ResponseBodyV2DecodedPayload object with the following values: notificationUUID: 3cd6410b-0c89-4247-aba5-20710e79895e notificationType: null subtype: null The transaction information decoded from the ResponseBodyV2DecodedPayload object is as follows: transactionId: 2000000633622618 webOrderLineItemId: null productId: heart_2 To debug, I called the Get Notification History API of the App Store Server API, and the mentioned notification for the consumable product purchase is not included in the history. Only notifications related to subscription product purchases are retrieved. According to the notification type documentation, there is no explanation for cases where both notificationType and subtype are null, nor is there any mention of receiving notifications for consumable purchases. Therefore, I am uncertain how to interpret and handle this notification. Could you please provide an explanation or guidance on this issue? Thank you. References: https://developer.apple.com/forums/thread/737592 https://developer.apple.com/documentation/appstoreservernotifications/notificationtype
3
0
1.2k
May ’25
Transaction.updates sending me duplicated transactions after marking finished()
Hey y'all, I'm reaching out because of an observed issue that I am experience both in sandbox and in production environments. This issue does not occur when using the Local StoreKit configurations. For context, my app only implements auto-renewing subscriptions. I'm trying to track with my own analytics every time a successful purchase is made, whether in the app or externally through Subscription Settings. I'm seeming too many events for just one purchase. My app is observing Transaction.updates. When I make a purchase with Product.purchase(_:), I successfully handle the purchase result. After a few seconds, I receive 2-3 new transactions in my Transaction.updates, even though I already handled and finished the Purchase result. The transactions seem to have the same transactionId, and values such as revocationDate, expirationDate, and isUpgraded don't seem to change between any of them. For purchases made outside the app, I get the same issue. Transaction gets handled in updates several times. Note that this is not an issue if a subscription renews. I use `Transaction.reason
3
0
120
1w