Hi everyone,
I'm encountering an issue with StoreKit 2 and subscriptions that I hope someone can help clarify.
Here's the scenario:
A user purchases a subscription.
The user cancels the subscription in their Apple ID settings (it remains active until the end of the billing period).
While the subscription is still active, the user reopens the app and tries to repurchase the same subscription.
The problem:
The purchase() method start well a new billing flow, but once confirmed throws a StoreKitError.unknown.
Despite this error, the subscription gets re-enabled and appears active again in the currentEntitlements.
So my question is why the purchase method throw an error and how to deal with this case ?
I precise I'm currently only working in sandbox, maybe the behavior is different in production (but even in that case there is still a bug in Sandbox that should not happen).
Also in that case the Apple Server Notification API send the webhook with type DID_CHANGE_RENEWAL_STATUS (and subtype AUTO_RENEW_ENABLED), which is expected.
Thanks for help,
Gregoire.
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
According to the App Store Server API documentation
, https://developer.apple.com/documentation/appstoreserverapi/price
the price field "shows the total amount of the transaction for the quantity the customer purchased."
However, in actual transaction notifications and responses from App Store Server API,
the price field appears to represent the unit price, not the total price.
For consumable in-app purchases with quantity > 1,
the price field equals the unit price of a single item.
The total user payment is only correct after multiplying by the quantity.
When quantity > 1, the actual amount paid by the user only matches price × quantity,
which contradicts the documentation.
Please confirm whether the price field is intended to be:
The unit price of a single item (requiring multiplication by quantity), or
The total price including all quantities (as currently documented).
If the former is correct, please update the documentation to clarify that the value represents the unit price, not the total amount.
Topic:
App & System Services
SubTopic:
StoreKit
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.
Topic:
App & System Services
SubTopic:
StoreKit
I’m reaching out regarding our existing in-app subscription implementation that currently uses App Store Server Notifications version 1 (v1). Our live application has a significant number of active recurring subscriptions that are being managed through the v1 webhook integration.
We have now developed a revamped version of our application, which uses the same Apple Developer Account and App Store Connect setup, but in this new app version, we’ve implemented App Store Server Notifications version 2 (v2).
Before moving forward with the migration, I would like to clarify the following points to ensure a smooth transition and avoid any disruptions to ongoing subscriptions:
Backward Compatibility:
Will existing active subscriptions (originally created and managed via v1 notifications) continue to work seamlessly once we switch to v2, or do we need to maintain both v1 and v2 endpoints during the transition?
Notification Delivery:
If both webhook versions are configured simultaneously, will Apple send notifications to both endpoints, or only the one currently configured in App Store Connect?
Migration Strategy:
What is Apple’s recommended best practice for migrating from v1 to v2 in a scenario where the live app still has active subscriptions tied to the v1 webhook?
Potential Risks or Considerations:
Are there any known limitations, delays, or issues that we should prepare for during this migration (for example, differences in payload structure or event types between v1 and v2 that could affect subscription lifecycle management)?
I would greatly appreciate your guidance or documentation links that outline the correct migration steps and recommended approach for ensuring continuity of service for all existing subscribers.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
App Store
App Store Server Notifications
If you are experiencing an unexpected or inconsistent behavior when using the App Store Server Library, review the following resources to ensure that your implementation workflow didn’t cause the issue:
Simplifying your implementation by using the App Store Server Library
Explore App Store server APIs for In-App Purchase
Meet the App Store Server Library
If you are unable to resolve your issue using the above resources, file a GitHub issue. Alternatively, if you wish to provide specific requests, transactions, or other private information for review, submit a Feedback Assistant report with the following information:
The bundleId or appAppleId of your app
The date and time your issue occurred
The library language(s)
The version of the library
The environment (i.e., Production, Sandbox, or Xcode)
The GitHub issue for this report if available
The endpoint(s) reproducing your issue
The HTTP body and headers of the endpoint raw request
The HTTP body and headers of the endpoint response
To submit the report, perform these steps:
Log into Feedback Assistant.
Click on the Compose icon to create a new report.
Select the Developer Tools & Resources topic.
In the sheet that appears:
Enter a title for your report.
Select “App Store Server Library” from the “Which area are you seeing an issue with?” pop-up menu.
Select “Incorrect/Unexpected Behavior” from the “What type of feedback are you reporting?” pop-up menu.
Enter a description of your issue and how to reproduce it.
Add the information gathered above to the sheet.
Submit your report.
After filing your report, please respond in your existing Developer Forums post with the Feedback Assistant ID. Use your Feedback Assistant ID to check for updates or resolutions. For more information, see Understanding feedback status.
Payment completed with error: Error Domain=ASDErrorDomain Code=500 "(null)" UserInfo={client-environment-type=Sandbox, storefront-country-code=USA, NSUnderlyingError=0x2828a5950 {Error Domain=AMSErrorDomain Code=305 "Purchase Failed" UserInfo={NSLocalizedDescription=Purchase Failed, AMSURL=https://sandbox.itunes.apple.com/WebObjects/MZBuy.woa/wa/inAppBuy?guid=00008030-000164513691402E, AMSStatusCode=200, AMSServerPayload={
"cancel-purchase-batch" = 1;
customerMessage = "Bad Gateway_message";
failureType = "";
"m-allowed" = 0;
pings = (
);
}, NSLocalizedFailureReason=Server canceled the purchase}}}
Topic:
App & System Services
SubTopic:
StoreKit
A user made an in-app purchase on December 15th at around 4:00 PM Japan Standard Time (JST). However, the confirmation email sent after the purchase shows the receipt date as December 14th.
What could be causing this discrepancy in the date?
The app store's primary language is set to English.
The server region is singapore.
Topic:
App & System Services
SubTopic:
StoreKit
Currently, we are using the Apple V2 interface to develop the payment function. We generate a transaction ID on the mobile client and obtain the receipt. Now, when we call the Apple sandbox environment interface to verify the receipt, we always get a 404 error. The above is the request and response. The token used in it is also the original data after decoding, and there is no problem. Could you help me figure out what other possible reasons there might be?
Topic:
App & System Services
SubTopic:
StoreKit
So, we've implemented IAP with StoreKit2 e2e for both the client and backend and it's working mostly perfectly, however we have an issue which we can't seem to understand Apple's behavior.
So, imagine a purchase that occurred on the 10th of December in the sandbox environment through an install from TestFlight, and this same purchase keeps getting queued in the Transaction.unfinished list for some reason (today, the 17th of December, a whole week after the initial purchase!).
Here's the flow:
We iterate the list on app launch
Send the unfinishedTransaction's transactionId to our servers
The server says "hey, we could verify it with Apple but it's not longer active (expired). We can't really work with it so just finish it on your side and don't send it to me again"
The client finishes!! the transaction
On the very next app launch it keeps reappearing in the Transaction.unfinished queue
Are we doing something wrong, why doesn't it get cleaned? Is this an expected behavior?
Note, this is generally the server's logic for new purchases:
If we weren't able to contact Apple - we tell the client to not finish the transaction so that we'll be able to re-iterate it on the next app launch or retry
If the transaction is not expired and valid - we update our records and tell the client to finish the transaction
If we couldn't update our records - we tell the client to not finish the transaction so that we'll be able to re-iterate it on the next app launch or retry
If the transaction is not valid for some reason - we tell the user to finish the transaction
The server might see it as a valid transaction if we'll send the originalTransactionId instead of the 'transactionId(using it to callgetTransactionInfoinAppStoreServerLibrary`), but is this something we want to do?
This will obviously not fix the problem because the server tells the client to finish the transaction anyways, but it simply doesn't work.
Please, any advice or changes to make to either Client/Server would be greatly appreciated
Best Regards, Ofek
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
App Store Connect
In-App Purchase
Hi does anyone have trouble using expo store review package for ios apps. for some reason on our app., the review may show for certain people, but when they submit a review, it doesn't update our review count
Topic:
App & System Services
SubTopic:
StoreKit
I have several ObjC based apps in the App Store and used to validate the receipt file inside the app in my code, and then reject it with exit(173) if it's invalid, which did trigger macOS to update the receipt if possible.
This isn't working any more in recent macOS versions, where the user is instead just told that the app is damaged, and they need to re-install it manually. Which sucks.
So I wanted to update my code. I read about SKReceiptRefreshRequest, which is supposed to re-download and install the receipt file, if I understand it correctly.
I implemented the code but now have trouble verifying that it works as intended, and does this in a user friendly way.
I found in my tests that macOS now caches the receipt in ~/Library/Caches/com.apple.appstoreagent/fsCachedData and then hardlinks the file into the app.
BTW: Sadly, this also requires that the app is located on the startup volume or the system will refuse to install the receipt, which wasn't a requirement in past times.
Now, if the receipt is already present in the cache folder, then my code works - the receipt gets re-linked.
But what if the cached receipt isn't there, yet? Such as that the user had copied the app from another Mac over to a freshly installed Mac? In the past, when the user then launched the app on the new Mac, he'd be prompted to login to the MAS and if that worked, the receipt would get installed and the app launched.
Basically, the question is: What if the receipt validation fails in my app and I request a new receipt, but the user has not yet logged into MAS (e.g. new computer)?
To simulate this, I logging out of the MAS and TestFlight, deleting all copies of the app and then run the app that I had copied from another Mac where it was authorized with a valid receipt for that device.
If I do this with the old version that uses exit(173), I get these two messages in macOS 15.2:
The second one is especially terrible because it shows the translocated path, which the average user surely get quite confused, and then maybe even search in vain for the app in there and get frustrated. But that's out of my hands. Sigh.
Now, that was proving that the old method with exit(173) isn't working any more and needs to be changed in my apps.
Since I'm still developing (testing) this new behavior, the app is therefore not in the MAS yet - the only way for me to test this is to use TestFlight. However, running a Testflight app copied from another Mac leads to this error:
That is not helpful in simulating what would happen if this app was released in the MAS. This won't let me find out what happens if my app is run on a Mac where the receipt fails and I ask it to load it via SKReceiptRefreshRequest and if the user is NOT yet logged into the MAS account for this purchased app of his/hers.
That leaves only one option: Release the app with untested code and hope for the best.
Contrary to this new behavior, the old method did let me test this easily because I would just use the special App Store tester account with the MAS app, i.e. the built MAS app would, when I launched it locally, request for a login and I'd provide my tester's account. But this isn't available any more, apparently.
What a mess.
Hello,
I’m facing an issue with auto-renewable subscriptions in my React Native iOS app using react-native-iap.
Before App Store approval, everything worked perfectly — I could test in-app purchases and subscriptions locally on my iPhone through Xcode using a development build and sandbox tester.
After the app was approved and released on the App Store, I needed to make some updates. Now, when I build and run the same project again through Xcode (Debug, development-signed) on my iPhone, the subscriptions no longer load.
The same product IDs are approved and live in App Store Connect.
The live version on the App Store works fine (subscriptions load and process successfully).
But on the local Xcode build, getSubscriptions() returns invalid product identifiers or an empty list.
No changes were made to the bundle ID or product IDs
The build is signed with an Apple Development certificate and uses the same team and bundle identifier as the published app.
“In-App Purchase” capability is enabled.
I’ve also tried deleting the app, rebooting the device, and re-logging into a sandbox tester account, but the issue persists.
It looks like the sandbox environment no longer works for the app after its first App Store release.
Has anyone experienced this issue where the same approved app’s IAPs work in production but fail to load in sandbox/dev builds through Xcode after release?
Any guidance on re-enabling sandbox testing for updates would be greatly appreciated.
Environment:
Xcode 26.0.1
React Native with react-native-iap
Auto-renewable subscriptions (3 SKUs)
Thank you!
I'm using Transaction.environment to determine server behavior.
https://developer.apple.com/documentation/storekit/apptransaction/environment
https://developer.apple.com/documentation/storekit/appstore/environment
I gather this information on the app using StoreKit and then send it to the server:
originalTransactionId = transaction.originalID
originalTransactionEnvironment = transaction.environment
When testing within Xcode, on a simulator, the value sent to the server for originalTransactionEnvironment is Xcode - as expected.
When testing on a device using a TestFlight build, the value sent to the server for originalTransactionEnvironment is undefined/nil. I expected it to be Sandbox - and later in production it should be Production.
Most importantly, the value sent to the server for originalTransactionId in the TestFlight version is not undefined/nil - it is the value I expected it would be. The transaction was originally for a subscription purchase, if that makes a difference.
So the transaction is available, and information like originalID is also available. Why is transaction.environment not available? What is the behavior in production?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
In-App Purchase
TestFlight
In my understanding, with the latest court ruling in the US, iOS apps may decide to support web-based payments for subscriptions and in-app purchases. However, are we allowed to exclusively support web-based payments and not implement StoreKit at all?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
App Store Connect
In-App Purchase
Hello,
I'm encountering an issue when trying to use the subscriptionGroupLookups endpoint in the App Store Connect API.
Despite having the correct setup, I continue to receive a 404 NOT FOUND error when making requests to:
GET https://api.appstoreconnect.apple.com/v1/subscriptionGroupLookups
Here is the current state of my environment:
I am the Account Holder of the App Store Connect account
The App Store Connect API key has been successfully created
I have the correct Key ID, Issuer ID, and .p8 private key
I can authenticate and access the apps and subscriptionGroups endpoints
However, the subscriptionGroupLookups endpoint always returns:
{
"errors": [
{
"status": "404",
"code": "NOT_FOUND",
"title": "The specified resource does not exist"
}
]
}
I suspect that LookUp Keys (UUIDs) have not been assigned to our subscription groups, even though they were created and are active in App Store Connect.
There is no “Request Access” button visible under the Integrations tab (as mentioned in Apple support instructions), and my keys appear under “App Store Connect API” > “Keys” as active.
Questions:
How can I ensure that LookUp Keys are assigned to my subscription groups?
Is there a way to trigger this manually or via support?
Has anyone successfully resolved this?
Any advice or experience would be greatly appreciated.
Thank you!
Previously I could get the sub package information after each payment via webhook but today I didn't get it. What happened?
My webhook url: https://r-connect-api-dev.mystg-env.com/webhook/appstore/notification/v2
Topic:
App & System Services
SubTopic:
StoreKit
I tried to apply a promotional offer to a subscribed user.
When I tested it in the Sandbox environment, it did not show the promotional payment popup but returned a “restored” status.
However, when I tested it in the Xcode environment, it correctly displayed the payment popup, but after I tapped the Subscribe button, it showed an “Unable to Purchase” popup like this:
And in the console I could see this error:
Received error that does not have a corresponding StoreKit Error: Error Domain=AMSErrorDomain Code=305 "Server Error The server encountered an error" UserInfo={AMSURL=http://localhost:56862/WebObjects/MZBuy.woa/wa/inAppBuy, AMSDescription=Server Error, NSDebugDescription=Server Error The server encountered an error, AMSServerErrorCode=3903, AMSStatusCode=200, AMSServerPayload={
"cancel-purchase-batch" = 1;
dialog = {
defaultButton = ok;
explanation = "Contact the developer for more information.\n\n[Environment: Xcode]";
initialCheckboxValue = 1;
"m-allowed" = 0;
message = "Unable to Purchase";
okButtonString = OK;
};
dsid = 17322632127;
failureType = 3903;
jingleAction = inAppBuy;
jingleDocType = inAppSuccess;
pings = (
);
}, AMSFailureReason=The server encountered an error}
Could someone help me resolve this issue? I’ve been struggling with it for two days and feeling exhausted...
I tested a subscription with my developer account, it never charges but at the same time I can't cancel it anymore. It does not appear in the list of my official purchsed subscriptions. I tried to login to the sandbox with my developer account, but then when I click on "Manage" I just keep getting the error "Can't connect - retry".
I have already tried to logout from all the services, App store, etc. and re-login, nothing worked.
Is there anything I can do?
Thanks in advance to anyone who can give any tips.
The application is developed with Xamarin Framework and it is live now.
The customer installed the app and purchased the annual subscription.
And for some reason, they uninstall and reinstall the application on the same device.
Now user wants to restore the subscription. In the application, there is an option to Restore the subscription. But restore API not return purchase details.
But when clicking the subscription button instead of restoring the subscription, it says you subscribed to this plan".
is there any possibility of not getting VerifyRecipt even after a successful purchase?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
App Store
StoreKit Test
App Store Connect
Regarding the offer codes in https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-offer-codes, I set up some incorrect offer codes by mistake.
Currently, I can only deactivate it but I can't delete it. Is it possible to let me delete the incorrect offer codes due to the below reasons? Thank you.
I can't recreate the offer code due to error message This reference name is or has been used by another offer in this subscription group.
When I use the offer code redemption view in https://developer.apple.com/documentation/SwiftUI/View/offerCodeRedemption(isPresented:onCompletion:), it shows all the deactivated offer codes. I don't want them to be displayed in the page.