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 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
336
Jul ’25
Transactions Finish does not work on iOS 26 beta3
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.​
4
5
590
Jul ’25
StoreKit.product.purchase returns success, but subscription does not appear in Settings
Description: We are developing an iOS app that offers only one auto-renewable subscription. Recently, a user who had not subscribed for over a year purchased the subscription again through our app. However, when they checked Settings > Subscriptions, the new subscription did not appear. Instead, only their past subscription history was visible, and there was no option to cancel the new subscription. We have verified this issue with a screenshot provided by the user. Additionally, we checked our app’s logs and confirmed that StoreKit.product.purchase successfully returned .success, indicating that the purchase was processed correctly. Code used for purchase: let result = try await product? .purchase(options: [ .appAccountToken(uuid) ]) switch result { case .success(let verificationResult): switch verificationResult { case .verified(let transaction): addPurchaseLog("verificationResult.verified.") case .unverified(_, let verificationError): addPurchaseLog("verificationResult.unverified.") case .userCancelled, .pending, .none: addPurchaseLog("verificationResult.userCancelled or .pending or .none") @unknown default: addPurchaseLog("verificationResult.unknown.") } Despite the successful purchase, the new subscription does not appear under the user's active subscriptions. Could this be a bug in StoreKit? If there are any known issues or workarounds, we would appreciate any guidance. Environment: Xcode: 16.2 iOS version: 16.0+
4
0
244
May ’25
AppTransaction.shared doesn’t return originalAppVersion for users who installed the app in 2017
Hi, I'm using the AppTransaction.shared API to retrieve the originalAppVersion, but I'm encountering issues for users who originally installed the app in 2017. Specifically, the property doesn't seem to return the expected value (or returns nil) for these older accounts. I have verified this issue using a real App Store purchase from 2017. Steps to Reproduce: Use a test account that originally downloaded the app in 2017. Call: let shared = try await AppTransaction.shared print(shared.originalAppVersion) Observe that originalAppVersion is missing or not returned correctly. Any insights on whether this is expected behavior for very old App Store purchases, or if there is a workaround to reliably detect the original app version? Thanks in advance!
4
1
135
May ’25
Server Not Receiving Apple App Store Server Notification
Hello, Our server isn't receiving Apple App Store Server Notification for in-app purchases. It works for Sandbox Server, even I sent a test notification which I received on the Production Server URL, but the real in-app payment notification isn't coming to the server. I checked this already: https://developer.apple.com/documentation/appstoreservernotifications/enabling-app-store-server-notifications and everything here has been reviewed. Transport Layer Security (TLS) version and others things mentioned have been checked, test notification was received. But the main in-app purchase notification for live transaction isn't coming. What's the issue precisely?
4
0
422
May ’25
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
391
Aug ’25
Best practice to prevent users from switching between subscriptions in the same group?
Hello everyone, For example, our app currently has one subscription group in App Store Connect with 5 plans (2 annual, 2 monthly, and 1 quarterly). By default, users can go into Apple Subscriptions in Settings and freely switch between all of these plans. However, our business requirement is to only allow users to stay on one annual plan and one quarterly plan. We don’t want them to switch to the other plans. My questions are: Is there any best practice or recommended approach to restrict subscription switching within the same group? Would removing the unwanted products from sale be the correct approach, or are there any risks/downsides with this method? Has anyone faced a similar situation and found a practical solution? Any guidance or shared experience would be greatly appreciated. Thanks!
4
0
162
Sep ’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
97
Jan ’26
Does originalTransactionId change if a user resubscribes?
Hello, For In App Purchases with a renewable subscription, does the originalTransactionId change in the following scenarios? Case 1: A user subscribes to a subscription A within a Subscription Group SG1. The user then cancels it at the end of the month. Comes back later to subscribe to the same subscription A within the same Subscription Group SG1. Case 2: A user subscribes to a subscription A within a Subscription Group SG1. The user then cancels it at the end of the month. Comes back later to subscribe to subscription B within the same Subscription Group SG1.
3
1
1.1k
Mar ’25
TestFlight user cannot re-purchase expired auto-renewable subscription – only restored purchases returned
I’m testing an auto-renewable subscription on TestFlight. Now the user can't re-purchase the same product – Apple just restores the old (expired) one, and no payment sheet appears. How can I let the same TestFlight user re-subscribe to an expired product? Do I have to create a new productId for every test cycle?
3
3
162
Jul ’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
823
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
391
Oct ’25
Storekit, how to change and retrieve current user storefront
I've been struggling to work with the Storekit framework and specifically to find the current Storefront used by the user of the app. Context : My app needs to behave differently depending on the country of the user. For me relying on Locale.current.region?.identifier does not seem very reliable, the user can change it really easily. I'm trying to use the Storekit framework like so : if let storefront = await StoreKit.Storefront.current{ return storefront.countryCode } As per Apple's Storekit documentation : Use current to determine a customer's current storefront region and offer in-app products suitable for that region. You maintain your own list of product identifiers and the storefronts in which you make them available. But I just can't find out what I need to change in my current configuration to get another country. The code keeps returning my original storefront (which is France) I've tried login in with a sandbox user defined on another country. Changed all settings on my device to another country. Changed my Apple's account region as described here. Also tried to logout from everything. The only thing that works is setting a local .storekit file as described here and changing the default storefront. Is Xcode overriding the default storefront when building on debug or TestFlight? does anyone know how can I test different storefronts with sandbox users without the local storekit file ? Thank you in advance.
3
2
591
Oct ’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
143
2w
Incorrect storefront country code
Both the legacy StoreKit API and the new StoreKit 2 API return the incorrect storefront countryCode. My actual Apple ID region is Germany, and my Sandbox test user is set to France, yet the SDK consistently returns USA. Expected Results: The returned storefront countryCode should reflect the correct region - sandbox user region if signed in and real user region if not signed in with sandbox). Actual Results: Returned country code is USA with both SKPaymentQueue.default().storefront?.countryCode and await Storefront.current?.countryCode. Signing out/in, device reboot and even reset do not help, I'm stuck with USA storefront.
3
1
335
Oct ’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
542
May ’25
original_transaction_id associated to web_order_line_item_id of auto-renewable subscription changed
Our app offers auto-renewable subscriptions using StoreKit Original API for In-App Purchase and App Store Server Notifications V1. Starting around 2025-03-15, we found some cases where original_transaction_id which was associated to web_order_line_item_id of already purchased subscription had changed in the receipt information of verifyReceipt response or App Store Server Notifications V1. The detailed steps are: Around February 2025, re-purchase from the app the same subscription product which was canceled and expired some time ago, using StoreKit Original API for In-App Purchase Receive the following 2 notifications from App Store Server Notifications V1 almost at the same time INITIAL_BUY DID_CHANGE_RENEWAL_STATUS In both notifications, latest_receipt_info contains the receipt for the re-purchased subscription period with new original_transaction_id and web_order_line_item_id pending_renewal_info contains both new original_transaction_id and original one which was generated at first purchase, and original one has "is_in_billing_retry_period": "1" Starting around 2025-03-15, the following happens When we receive another "DID_CHANGE_RENEWAL_STATUS" notification from App Store Server Notifications V1, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription period has changed back to the original one (the one which was generated at first purchase) in latest_receipt_info. When we call verifyReceipt with the receipt obtained from appStoreReceiptURL, the response does not seem to contain new original_transaction_id which was generated at re-purchase We have some questions regarding this original_transaction_id behavior. When a user re-purchase the same subscription product which was canceled and expired some time ago, it seems that new original_transaction_id is generated. Is this an expected behavior? If yes, it seems that, at some point, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription changed back to the original original_transaction_id which had been generated at first purchase. Is this an expected behavior? What triggers the original_transaction_id change to the original one? Is it related to some user actions or subscription status change?
3
0
407
Mar ’25
can not verify receipt
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) 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? 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)
3
0
156
Sep ’25
Appium can't see any locators of purchase 'Sandbox' view
Appium can't see any locators of 'Sandbox' view in case of purchase page automation try. iOS 18.x. On version 17.x the elements could be found
Replies
4
Boosts
2
Views
220
Activity
Apr ’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.
Replies
4
Boosts
0
Views
336
Activity
Jul ’25
Transactions Finish does not work on iOS 26 beta3
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.​
Replies
4
Boosts
5
Views
590
Activity
Jul ’25
StoreKit.product.purchase returns success, but subscription does not appear in Settings
Description: We are developing an iOS app that offers only one auto-renewable subscription. Recently, a user who had not subscribed for over a year purchased the subscription again through our app. However, when they checked Settings > Subscriptions, the new subscription did not appear. Instead, only their past subscription history was visible, and there was no option to cancel the new subscription. We have verified this issue with a screenshot provided by the user. Additionally, we checked our app’s logs and confirmed that StoreKit.product.purchase successfully returned .success, indicating that the purchase was processed correctly. Code used for purchase: let result = try await product? .purchase(options: [ .appAccountToken(uuid) ]) switch result { case .success(let verificationResult): switch verificationResult { case .verified(let transaction): addPurchaseLog("verificationResult.verified.") case .unverified(_, let verificationError): addPurchaseLog("verificationResult.unverified.") case .userCancelled, .pending, .none: addPurchaseLog("verificationResult.userCancelled or .pending or .none") @unknown default: addPurchaseLog("verificationResult.unknown.") } Despite the successful purchase, the new subscription does not appear under the user's active subscriptions. Could this be a bug in StoreKit? If there are any known issues or workarounds, we would appreciate any guidance. Environment: Xcode: 16.2 iOS version: 16.0+
Replies
4
Boosts
0
Views
244
Activity
May ’25
AppTransaction.shared doesn’t return originalAppVersion for users who installed the app in 2017
Hi, I'm using the AppTransaction.shared API to retrieve the originalAppVersion, but I'm encountering issues for users who originally installed the app in 2017. Specifically, the property doesn't seem to return the expected value (or returns nil) for these older accounts. I have verified this issue using a real App Store purchase from 2017. Steps to Reproduce: Use a test account that originally downloaded the app in 2017. Call: let shared = try await AppTransaction.shared print(shared.originalAppVersion) Observe that originalAppVersion is missing or not returned correctly. Any insights on whether this is expected behavior for very old App Store purchases, or if there is a workaround to reliably detect the original app version? Thanks in advance!
Replies
4
Boosts
1
Views
135
Activity
May ’25
Issue with sandbox auto renewal
is there any error in sandbox auto renewal when Im test a app subscription automatically cancelled
Replies
4
Boosts
6
Views
331
Activity
Apr ’25
Server Not Receiving Apple App Store Server Notification
Hello, Our server isn't receiving Apple App Store Server Notification for in-app purchases. It works for Sandbox Server, even I sent a test notification which I received on the Production Server URL, but the real in-app payment notification isn't coming to the server. I checked this already: https://developer.apple.com/documentation/appstoreservernotifications/enabling-app-store-server-notifications and everything here has been reviewed. Transport Layer Security (TLS) version and others things mentioned have been checked, test notification was received. But the main in-app purchase notification for live transaction isn't coming. What's the issue precisely?
Replies
4
Boosts
0
Views
422
Activity
May ’25
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.
Replies
4
Boosts
0
Views
391
Activity
Aug ’25
Best practice to prevent users from switching between subscriptions in the same group?
Hello everyone, For example, our app currently has one subscription group in App Store Connect with 5 plans (2 annual, 2 monthly, and 1 quarterly). By default, users can go into Apple Subscriptions in Settings and freely switch between all of these plans. However, our business requirement is to only allow users to stay on one annual plan and one quarterly plan. We don’t want them to switch to the other plans. My questions are: Is there any best practice or recommended approach to restrict subscription switching within the same group? Would removing the unwanted products from sale be the correct approach, or are there any risks/downsides with this method? Has anyone faced a similar situation and found a practical solution? Any guidance or shared experience would be greatly appreciated. Thanks!
Replies
4
Boosts
0
Views
162
Activity
Sep ’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.
Replies
4
Boosts
0
Views
97
Activity
Jan ’26
Does originalTransactionId change if a user resubscribes?
Hello, For In App Purchases with a renewable subscription, does the originalTransactionId change in the following scenarios? Case 1: A user subscribes to a subscription A within a Subscription Group SG1. The user then cancels it at the end of the month. Comes back later to subscribe to the same subscription A within the same Subscription Group SG1. Case 2: A user subscribes to a subscription A within a Subscription Group SG1. The user then cancels it at the end of the month. Comes back later to subscribe to subscription B within the same Subscription Group SG1.
Replies
3
Boosts
1
Views
1.1k
Activity
Mar ’25
TestFlight user cannot re-purchase expired auto-renewable subscription – only restored purchases returned
I’m testing an auto-renewable subscription on TestFlight. Now the user can't re-purchase the same product – Apple just restores the old (expired) one, and no payment sheet appears. How can I let the same TestFlight user re-subscribe to an expired product? Do I have to create a new productId for every test cycle?
Replies
3
Boosts
3
Views
162
Activity
Jul ’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?
Replies
3
Boosts
0
Views
823
Activity
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?
Replies
3
Boosts
2
Views
391
Activity
Oct ’25
Storekit, how to change and retrieve current user storefront
I've been struggling to work with the Storekit framework and specifically to find the current Storefront used by the user of the app. Context : My app needs to behave differently depending on the country of the user. For me relying on Locale.current.region?.identifier does not seem very reliable, the user can change it really easily. I'm trying to use the Storekit framework like so : if let storefront = await StoreKit.Storefront.current{ return storefront.countryCode } As per Apple's Storekit documentation : Use current to determine a customer's current storefront region and offer in-app products suitable for that region. You maintain your own list of product identifiers and the storefronts in which you make them available. But I just can't find out what I need to change in my current configuration to get another country. The code keeps returning my original storefront (which is France) I've tried login in with a sandbox user defined on another country. Changed all settings on my device to another country. Changed my Apple's account region as described here. Also tried to logout from everything. The only thing that works is setting a local .storekit file as described here and changing the default storefront. Is Xcode overriding the default storefront when building on debug or TestFlight? does anyone know how can I test different storefronts with sandbox users without the local storekit file ? Thank you in advance.
Replies
3
Boosts
2
Views
591
Activity
Oct ’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?
Replies
3
Boosts
0
Views
143
Activity
2w
Incorrect storefront country code
Both the legacy StoreKit API and the new StoreKit 2 API return the incorrect storefront countryCode. My actual Apple ID region is Germany, and my Sandbox test user is set to France, yet the SDK consistently returns USA. Expected Results: The returned storefront countryCode should reflect the correct region - sandbox user region if signed in and real user region if not signed in with sandbox). Actual Results: Returned country code is USA with both SKPaymentQueue.default().storefront?.countryCode and await Storefront.current?.countryCode. Signing out/in, device reboot and even reset do not help, I'm stuck with USA storefront.
Replies
3
Boosts
1
Views
335
Activity
Oct ’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.
Replies
3
Boosts
15
Views
542
Activity
May ’25
original_transaction_id associated to web_order_line_item_id of auto-renewable subscription changed
Our app offers auto-renewable subscriptions using StoreKit Original API for In-App Purchase and App Store Server Notifications V1. Starting around 2025-03-15, we found some cases where original_transaction_id which was associated to web_order_line_item_id of already purchased subscription had changed in the receipt information of verifyReceipt response or App Store Server Notifications V1. The detailed steps are: Around February 2025, re-purchase from the app the same subscription product which was canceled and expired some time ago, using StoreKit Original API for In-App Purchase Receive the following 2 notifications from App Store Server Notifications V1 almost at the same time INITIAL_BUY DID_CHANGE_RENEWAL_STATUS In both notifications, latest_receipt_info contains the receipt for the re-purchased subscription period with new original_transaction_id and web_order_line_item_id pending_renewal_info contains both new original_transaction_id and original one which was generated at first purchase, and original one has "is_in_billing_retry_period": "1" Starting around 2025-03-15, the following happens When we receive another "DID_CHANGE_RENEWAL_STATUS" notification from App Store Server Notifications V1, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription period has changed back to the original one (the one which was generated at first purchase) in latest_receipt_info. When we call verifyReceipt with the receipt obtained from appStoreReceiptURL, the response does not seem to contain new original_transaction_id which was generated at re-purchase We have some questions regarding this original_transaction_id behavior. When a user re-purchase the same subscription product which was canceled and expired some time ago, it seems that new original_transaction_id is generated. Is this an expected behavior? If yes, it seems that, at some point, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription changed back to the original original_transaction_id which had been generated at first purchase. Is this an expected behavior? What triggers the original_transaction_id change to the original one? Is it related to some user actions or subscription status change?
Replies
3
Boosts
0
Views
407
Activity
Mar ’25
can not verify receipt
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) 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? 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)
Replies
3
Boosts
0
Views
156
Activity
Sep ’25