Hi Apple Support,
I am encountering an issue while testing in-app purchases in the sandbox environment.
I have created a sandbox tester account
Logged out of the App Store and System Settings on my Mac.
My main developer account is signed in under Sign In & Capabilities in Xcode.
The Bundle ID matches the one configured in App Store Connect.
The Product ID I am querying also matches the configuration.
Deleting the app and reinstalling.
Restarting my Mac.
When running my code in debug mode, I observe the following:
Running debug build
App Store environment: Production
[1b294b55] Error updating Storefront: Error Domain=StoreKit_Shared.StoreKitInternalError Code=7 "(null)"
Valid products: []
Invalid product IDs: ["com.x.x.x.monthly"]
No products found
The Product ID (com.x.x.x.monthly) matches the one I have configured in App Store Connect.
The bundle id matches.
When I create a StoreKit Configuration file in Xcode and sync it with my app, I can see the product IDs correctly.
Below are the relevant code snippets for fetching and handling products:
func fetchProducts() {
guard !productIDs.isEmpty else {
print("No product IDs configured")
return
}
let request = SKProductsRequest(productIdentifiers: productIDs)
request.delegate = self
print("Starting product request...")
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
DispatchQueue.main.async {
print("Valid products: \(response.products)")
print("Invalid product IDs: \(response.invalidProductIdentifiers)")
self.products = response.products
if self.products.isEmpty {
print("No products found")
} else {
print("products not empty")
for product in self.products {
print("Fetched product: \(product.localizedTitle) - \(product.priceLocale.currencySymbol ?? "")\(product.price)")
}
}
}
}
func debugStoreSetup() {
if let receiptURL = Bundle.main.appStoreReceiptURL {
if receiptURL.lastPathComponent == "sandboxReceipt" {
print("App Store environment: Sandbox")
} else {
print("App Store environment: Production")
}
} else {
print("No receipt found")
}
}
Could you help identify why my app is not recognizing the Product ID in the sandbox environment?
Thank you for your assistance.
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
Dear my friends,
I have set up two subscriptions (monthly and annual) in App Store Connect. By configuring with StoreKit, I can import the configurations from App Store Connect into the local .storekit file, and the program can
run normally. However, when the StoreKit configuration is set to NONE, I am unable to retrieve product information from App Store Connect.
The code for fetching the product list is as follows. Could you please provide suggestions on how to proceed? Thank you very much!
private let productIds: [String] = ["subscription.year", "subscription.monthly"]
subscriptions = try await Product.products(for: productIds)
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?
Hi All,
We are developing our app with an approved External Link Account Entitlement.
During the development process (such as installing from Xcode or creating an Ad-hoc build and installing it on a phone), the open() function of the External Link Account API displays the modal our native language. The app only localized to that language.
However, after uploading the app with the same configuration to TestFlight, the modal somehow appears in English instead.
What could be causing this issue with the External Link Account modal? How can the open() function display the modal in another language when installed from Xcode or an Ad-hoc release build, but in English when installed from TestFlight? How can we show only our native lanugage version only to our Users?
Thank you in advance
With the imminent suspension of SHA-1 on App Store receipts, we desperately need an objective C code sample demonstrating how to calculate the same SDH-256 hash on device to compared with the hash from the App Store receipt.
The forced migration to SHA256 for app store receipts this month mean we have to rewrite our on device receipt validation code. However there is no documentation or objC sample code on how to validate the SHA256 hash from MAS receipts. Thje documentation at
https://developer.apple.com/documentation/technotes/tn3138-handling-app-store-receipt-signing-certificate-changes/ does not give any detail on how to validate SHA256. All my 100+ hours of experimentation and trial and error attempting to create a matching SHA256 has on device have failed.
We desperately need some ObjC Sample code to validate the SHA256 hash on device. Our existing SHA1 code is still working but we expect SHA1 hashes to disappear from MAS Receipts any day now.
Tnanks for any advice !
I ran into a problem. When using Storekit1 to purchase an SKU, the user payment was successful, but StoreKit1 did return paymentCancelled to my App. I would like to know under what circumstances this problem may occur? How do I fix it? Thank you
Hello,
I’m integrating promotional offers for auto-renewable subscriptions using StoreKit 2.
The offer is displayed correctly, the Apple purchase sheet appears, and I can start the payment flow. The sheet shows the correct discounted price and the end date of the offer. However, after confirming the purchase, an alert appears saying “Unable to Purchase - Contact the developer for more information”
When dismissing the alert, Xcode logs the following:
Purchase did not return a transaction:
Error Domain=ASDServerErrorDomain Code=3902
"No se ha podido realizar la compra"
UserInfo={
NSLocalizedFailureReason=No se ha podido realizar la compra,
client-environment-type=Sandbox,
AMSServerErrorCode=3902,
storefront-country-code=ESP
}
Test environment:
App installed from Xcode on a real iPhone
Logged in with a Sandbox Apple ID
Using StoreKit 2
Promotional offer applied using:
Product.PurchaseOption.promotionalOffer(_:compactJWS:)
On the server side, I generate the promotional offer signature exactly as described in Apple’s documentation:
https://developer.apple.com/documentation/storekit/generating-a-signature-for-promotional-offers
The signature is generated using a Subscription Key
Signed with ECDSA + SHA256
Uses the correct invisible separator (U+2063)
The signature is validated locally using the derived public key and verifies correctly
The sandbox user has had previous subscriptions, which is why this promotional offer is eligible and shown.
Given that:
The offer is displayed correctly
The purchase sheet shows the discounted price and duration
The signature validates locally
The error occurs only after confirming the purchase
My question is:
Is this a known limitation or issue with promotional offers in the Sandbox environment?
Should promotional offers be tested exclusively via TestFlight instead of Sandbox?
Any clarification would be greatly appreciated.
Thank you!
This is a hybrid app built with JavaScript (Vue) + Capacitor. It is a reader app and has been authorized by Apple to use the External Link Account Entitlement, allowing users to manage their subscriptions outside of the app.
I have implemented the External Link Account API. When I click on "Gerenciar Assinatura em...", I use the External Link Account API to check if the modal is available (using ExternalLinkAccount.canOpen()). I always get "false".
my plugin in swift:
my app:
I believe this is due to the fact that I am in a development environment. My project is configured correctly in the following files: info.plist and App.entitlements. I also have the authorization in my profile visible in Xcode. I have attached screenshots for validation. The question is: should the External Link Account API work in a test environment? I am testing the build in Xcode with a physical iPhone with iOS 18.
file info.plist:
file App.entitlements:
xcode with authorization in my profile:
If you could let me know if I am doing something wrong, I would greatly appreciate it.
I've been testing the offer code feature for my non consumable in app purchase using a sandbox account, with sandbox offer codes and in the sandbox environment. However, the codes don't appear to work despite everything being in the sandbox.
Any idea what I'm missing?
The documentation mentions the following:
Verify your receipt first with the production URL; then verify with the sandbox URL if you receive a 21007 status code. This approach ensures you don’t have to switch between URLs while your app is in testing, in review by App Review, or live in the App Store.
This way, you can use one server environment to handle both Sandbox and Production environments. It is necessary to pass App Review.
However, I'm not manually hitting these URLs - I'm using Apple's libraries.
Specifically, the environment is used in SignedDataVerifier and AppStoreServerAPIClient.
(I can't link to these because, for some reason, the domain apple.github.io is not allowed. The documentation for these is only found there. You can find it quickly by searching these terms and the domain.)
Here is how SignedDataVerifier is being used:
const verifier = new SignedDataVerifier(
appleRootCertificates,
APPLE_ENABLE_ONLINE_CHECKS,
APPLE_ENVIRONMENT,
APPLE_BUNDLE_ID,
APPLE_APP_ID
)
const verifiedNotification: ResponseBodyV2DecodedPayload = await verifier.verifyAndDecodeNotification(signedPayload)
if (!verifiedNotification)
{
// Failure
return
}
Here is how AppStoreServerAPIClient is being used:
const appStoreServerAPIClient = new AppStoreServerAPIClient(
SIGNING_KEY,
APPLE_IAP_KEY_ID,
APPLE_IAP_ISSUER_ID,
APPLE_BUNDLE_ID,
APPLE_ENVIRONMENT
)
const statusResponse: StatusResponse = await appStoreServerAPIClient.getAllSubscriptionStatuses(originalTransactionId, [Status.ACTIVE])
In the source code for SignedDataVerifier.verifyAndDecodeNotification, I can see that it throws a VerificationException(VerificationStatus.INVALID_ENVIRONMENT) error .
So for SignedDataVerifier is it as simple as wrapping my code in a try/catch and checking that the error's status code is 21007? I'm unsure about this because if you scroll to the bottom of the linked source code file, you can see the enumeration VerificationStatus, but it's unclear if this member has a value of 21007.
The source code for AppStoreServerAPIClient only says that it throws an APIException if a response could not be processed, so I'm not too sure about how to handle this one.
I use [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]. Works on my App which is in the store (compiled pre-iOS 26).
If I compile the same App now, same codebase with Xcode Version 26.0, restore does not work. Nothing happens. Tested on real device (iOS 26).
Documentation says its deprecated, but my deployment target is iOS 12.
Anyone has similar issues? Any recommendations?
Topic:
App & System Services
SubTopic:
StoreKit
I am an app developer, and I have implemented in-app purchases in my application. When a user completes a purchase, Apple displays a success popup. After the user taps "OK", I send the receiptData to my server to add points to their account.
However, I have encountered cases where users either exit the app before tapping "OK" or experience network issues, preventing the receipt from being sent to my server. As a result, they do not receive their points.
Later, some users send me a receipt from Apple Pay, claiming that the payment was successful. These receipts include details such as the orderId, email, and other transaction information. However, I am not certain whether the user actually completed the payment but encountered an issue, or if they are providing a fraudulent receipt.
My question:
How can I verify the authenticity of these receipts? Is there an official way to check if a given Apple Pay invoice corresponds to a real in-app purchase in my app?
Any guidance or best practices would be greatly appreciated!
is there a way to make a test subscription in-app purchase expire immediately, for faster testing? it seems exceedingly complicated to test subscriptions if we have to a) wait until the next day for expiry, or b) keep on creating new apple ids to get into a fully unsubscribed state? it is still kind of madness testing this stuff, after all the years it has been available.
Hello,
We are having an issue with the RequestReview API and were hoping to get some help. We know that there is no guarantee that the in-app review modal will show and we know that there are 3 circumstances in which it will definitely not appear:
if the user has turned off in-app review/ratings in their settings
if the user has submitted a review for that app on that device within the last 365 days
if the user has been asked for a review >3 times in the last 365 days
When testing our implementation, every single one of our testers did not receive the rating modal despite the fact that we had all our testers turn on the app rating setting and that we have never asked for reviews from our app before. So that seems suspicious. While it is possible that something is up with our code (and I have provided some snippets below) we are also concerned that apple maybe is suppressing it for another reason. We really want to go live with our app review code but unfortunately we are not able to get confidence that it will ever appear for the user. Can you please help us understand why this isn't working.
The code: We are using the SwiftUI approach to requesting review. Here are some relevant code snippets
Important to note, we have a modal that appears when the user is in our list of active, targeted users. If they tap yes on this modal, it should show the in app rate the app system modal. If they tap no, we present them with an airship survey so that they can give feedback. Here is the code for the Yes button action:
@Environment(\.requestReview) private var requestReview
private var yesButton: some View {
Button(
action: {
dismiss()
requestReview()
},
label: {
Text(Lingua.General.appRateFirstButton)
.regularParagraph()
.frame(width: 180, height: 35)
}
)
.customButtonStyle(
foregroundColor: .black,
backgroundColor: Color(.powderBlue),
radius: 36
)
}
and this is the logic we use to determine whether we want to show them the modal in the first place. Obviously, a lot of this code leads to deeper areas in our logic and code but to give an idea...
private func showAppRateModalIfNeeded() {
if preferencesManager.appRateReviewShown == nil,
accountManager.userAccount?.permissions.rateTheApp == true {
let appReviewModalVC = UIHostingController(rootView: AppReviewModal())
appReviewModalVC.view.backgroundColor = .init(white: 0, alpha: 0.6)
appReviewModalVC.modalPresentationStyle = .overFullScreen
appReviewModalVC.modalTransitionStyle = .crossDissolve
parentVC?.navigationController?.present(appReviewModalVC, animated: true)
preferencesManager.appRateReviewShown = true
}
}
When testing in debug, we do find that the modal appears and works as expected. However, on release builds nobody is able to trigger it. Why? Are we doing something wrong here or is Apple just suppressing it. We are thinking about implementing the button taking the user directly into the app store review but we'd prefer to do the lower-friction dialog in-app if we can get it work so the user doesn't get sent out of the app.
Topic:
App & System Services
SubTopic:
StoreKit
I'm getting really frustrated with emails from my App users who believe they've been charged for a free in-app purchase when they haven't.
My App offers many in-app purchases of digital items and I give 4 of these away for free to let users get comfortable with how it works in-app.
Over the last couple of years I've had a steady increase in angry emails from users who accuse me of fraud by charging them for a free item. I couldn't figure out for a while what this was as they would leave a 1 star rating, delete the app and ignore my emails for more information.
Recently I had someone a bit more patient engage and explain it to me.
The purchase for some reason popped up on my notifications right when I bought the [Free Item in my app]. It was from a movie I bought and the bill was delayed.
The timing of that notification is what is misleading users about the free in-app purchase.
Can someone take note of this please and perhaps delay any payment notifications so they aren't sent when the in-app purchase is for FREE?
Thanks!
When creating a subscription charging system for an iOS app, I am trying to change the display to yen, dollars, or euros depending on the user's country.
I am using [priceLocale] of [SKProduct] in [StoreKit] to obtain currency information linked to the Apple account from the App Store and change the display.
The smartphone I am testing on uses an Apple account created in Japan, and the nationality of the App Store is also set to Japan, so I expect the display to be in yen.
As a result, the TestFligh version displayed dollars, but the official release version displayed yen.
Why doesn't the TestFligh version display yen?
Yesterday I noticed that if I purchase a free trial subscription in my app using a sandbox account, when the subscription expires I see a “Billing Problem” message every time I open the app.
”allow purchases & renewals“ setting is ON so this shouldn’t happen.
has anyone else seen this or knows how to resolve?
observed on iOS 18.3.2 & 16.7.10
thanks
We got Advanced Commerce API and the generic product identifiers approved. When I was try to migrate a sandbox subscription to ACA enabled subscription I hit an error
Request payload
(Hid some info but the requestReferenceId is the real)
{
"descriptors": {
"description": "Migrated",
"displayName": "Migration"
},
"items": [
{
"sku": "product_1mo_999",
"description": "description",
"displayName": "Product"
}
],
"requestInfo": {
"requestReferenceId": "3b0b8e67-d8a0-45f4-8f6d-06bffa9a2c08"
},
"storefront": "USA",
"targetProductId": "com.company.generic.subscription",
"taxCode": "C003-00-1"
}
Response
{
"errorCode": 5000000,
"errorMessage": "An unknown error occurred."
}
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
In-App Purchase
App Store Server API
Advanced Commerce API
Hello,
We have been approved for the Advanced commerce API and we are trying to implement dynamically created subscriptions via the SubscriptionCreateRequest.
We followed the Sending Advanced Commerce API requests from your app (https://developer.apple.com/documentation/storekit/sending-advanced-commerce-api-requests-from-your-app) documentation but we are not able to make it work correctly.
We created a generic subscription in the Appstore connect, product ID: com.example.subscription
Then in the app we load the subscription:
try await Product.products(for: ["com.example.subscription"])
We do the JWS serialization on our backend and then we wrap the jwt and convert it to Data in the app as this:
let request = """
{
"signatureInfo": {
"token": "\(result.signedPayload)"
}
}
"""
let advancedCommerceRequestData = Data(request.utf8)
Lastly, we apply the purchase options on the generic product as this:
try await product.purchase(
options: [
Product.PurchaseOption.custom(
key: "advancedCommerceData",
value: advancedCommerceRequestData
)
]
)
It doesn't show any error, but on the payment sheet it shows the data from the generic subscription and not the data that was in the SubscriptionCreateRequest.
Here is an example of the generated jwt:
eyJraWQiOiI4V0tNQjhLWTI0IiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiI0MDZkYmEyOS04ZjIyLTQ3ZDUtYWI1Mi1kY2M2NTQ5OTE1Y2MiLCJiaWQiOiJjby5oZXJvaGVyby5IZXJvaGVybyIsImlhdCI6MTc0NjQzNTcxNCwiYXVkIjoiYWR2YW5jZWQtY29tbWVyY2UtYXBpIiwibm9uY2UiOiJhMzY2MGIwMS1kMDcyLTRlZDYtYmYyMS01MWU1Y2U5MDRmYTUiLCJyZXF1ZXN0IjoiZXlKdmNHVnlZWFJwYjI0aU9pSkRVa1ZCVkVWZlUxVkNVME5TU1ZCVVNVOU9JaXdpY21WeGRXVnpkRWx1Wm04aU9uc2ljbVZ4ZFdWemRGSmxabVZ5Wlc1alpVbGtJam9pTVdSaVlqZG1ZbVl0WWpFNE55MDBZMlJoTFRrNE16WXRNalUzTTJZeU1UaGpOekZpSW4wc0luTjBiM0psWm5KdmJuUWlPaUpEV2tVaUxDSjJaWEp6YVc5dUlqb2lNU0lzSW1OMWNuSmxibU41SWpvaVExcExJaXdpZEdGNFEyOWtaU0k2SWxNd01qRXRNRGd0TVNJc0ltUmxjMk55YVhCMGIzSnpJanA3SW1ScGMzQnNZWGxPWVcxbElqb2lVM1ZpYzJOeWFYQjBhVzl1SUZCbGRISWc0b0tzSURVaUxDSmtaWE5qY21sd2RHbHZiaUk2SWxOMVluTmpjbWx3ZEdsdmJpQlFaWFJ5SU9LQ3JDQTFJbjBzSW5CbGNtbHZaQ0k2SWxBeFRTSXNJbWwwWlcxeklqcGJleUprYVhOd2JHRjVUbUZ0WlNJNklsTjFZbk5qY21sd2RHbHZiaUJRWlhSeUlPS0NyQ0ExSWl3aVpHVnpZM0pwY0hScGIyNGlPaUpUZFdKelkzSnBjSFJwYjI0Z1VHVjBjaURpZ3F3Z05TSXNJbkJ5YVdObElqb3hOVEF3TUN3aWMydDFJam9pY1dkeGIzUnNlSEY1WVdGaFlsOTRiV3RvWlhWdGFHWjJhbXhtWDBWVlVqQTFJbjFkZlE9PSJ9.kJ0f_q2A11Mn9OBmvX6SRmtW5P--volFTVcq_Gohs3N51ECfZqS3WHOxOZc7aojq_qiUHGFp_evmHP51f3LzSw
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
In-App Purchase
Advanced Commerce API
New subscriptions have been failing to renew in the sandbox for 3 days. I am seeing multiple posts and comments from people that appear to be experiencing the same issue. But I haven't seen any feedback from Apple representatives.
I really do not want to launch a new app without seeing functioning renewals in the sandbox.
Is there somewhere else we are intended to seek assistance?