iOS Storekit2 Appstore production environment, some user feedback in app purchase faliure, What our log records is StoreKitError.unknown,please How to solve problem, thanks
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
Hello, I’m trying to change my business model within the app, and following Apple’s documentation guidelines HERE I created this task in the main view of the app. It seems to work perfectly in the simulator, on physical devices, and on TestFlight. However, after releasing it to production and uploading the new version to the App Store, it doesn’t work, and all users, whether new or existing, are asked to subscribe. In the console, it appears to retrieve the transactions correctly, but in production, I’m not sure how to view the console or see what it’s retrieving.
Here the sandbox receipt I obtained
AppTransaction.shared obtained: {
"applicationVersion" : "1",
"bundleId" : "com.anestesiaIB.Drugs-Infusion-Calc",
"deviceVerification" : "6M0Nnw14nSEOBVTPE\/\/EfnWSwLm7LFSlrpFEwxgH74SBHp5dSzBEm896Uvo42mwr",
"deviceVerificationNonce" : "8a8238c0-0aee-41e6-bfb0-1cfc52b70fb6",
"originalApplicationVersion" : "1.0",
"originalPurchaseDate" : 1375340400000,
"receiptCreationDate" : 1737577840917,
"receiptType" : "Sandbox",
"requestDate" : 1737577840917
}
This are the processing log while verified the receipt
New business model change: 1.7
Original versionéis components: ["1", "0"]
Major version: 1, Minor version: 0
This user is premium. Original version: 1.0
This is my task...
.task {
do {
let shared = try await AppTransaction.shared
if case .verified(let appTransaction) = shared {
let newBusinessModelVersion = (1, 7) // Representado como (major, minor)
let versionComponents = appTransaction.originalAppVersion.split(separator: ".")
if let majorVersion = versionComponents.first.flatMap({ Int($0) }),
let minorVersion = versionComponents.dropFirst().first.flatMap({ Int($0) }) {
if (majorVersion, minorVersion) < newBusinessModelVersion {
self.premiumStatus.isPremium = true
isPremium = true
} else {
let customerInfo = try await Purchases.shared.customerInfo()
self.premiumStatus.isPremium = customerInfo.entitlements["premium"]?.isActive == true
isPremium = self.premiumStatus.isPremium
}
} else {
print("Error: obteining version components")
}
} else {
print("Not verified")
}
} catch {
print("Error processing transaction: \(error.localizedDescription)")
}
}
I am currently developing an auto-renewal subscription in-app purchase for my app.
Currently, the subscription items have already been approved in appStoreConnect, and the .store file is synced with appStoreConnect, so the subscription items are displayed well and the test is also progressing well.
However, when I build without using the .store file to perform sandbox testing, the subscription items do not appear and response.invalidProductIdentifiers appears.
Is there anything I need to do additionally so that the subscription items can appear in response.products?
ps. The bank account item in the contract is in 'processing' status, and the paid app contract status is 'waiting for user information'.
I implemented consumable in-app purchases in an iPhone app using ProductView().
When I tap the payment button in ProductView(), I am taken to the payment screen and once the payment is completed the next code seems to be executed, so there doesn't seem to be a problem, but if I tap the payment button in ProductView() again, the next code is executed without taking me to the payment screen.
This means that a single payment can be made multiple times.
Can someone help?
ProductView(id: "geminiOneMatch")
.productViewStyle(.compact)
.padding()
.onInAppPurchaseCompletion { product, result in
if case .success(.success(_)) = result {
// 課金が成功した場合の処理
gemini.addOneMatch(amount: 20)
popUpVM.geminiOneMatchPopUp = false
dataManageVM.generateRespons(locale: locale)
}
}
Sorry but I'm not good at English.
Is the originalTransactionId received for the same subscription by the same user the same in Store Kit v1 and Store Kit 2?
Also, will the originalTransactionId be the same even if the subscription price is changed?
https://developer.apple.com/documentation/appstoreserverapi/get-v2-history-_transactionid
I would like to inquire about the detailed triggers for updating receipts in this API specification.
Recently, I was using this API with sort=DESCENDING&revoked=false to retrieve the expiration date of the most recent receipt and determine the subscription status. However, for some reason, an old receipt with an earlier expiration date appeared as the first receipt, and I would like to know the reason for this.
Can you provide information on what specific events or actions trigger the updating of receipts in this API?
Also, regarding https://developer.apple.com/documentation/appstoreserverapi/status, will statuses 3 and 4 not be returned in the response unless the billing grace period is enabled in the App Store?
Hello Developers!
I am trying to run a test In-App Purchase (IAP) for a renewable subscription product in the sandbox environment. I have set up everything required for sandbox testing, but it’s unclear whether the subscription product needs to be pre-approved by Apple for testing.
If approval is required, I have already added the necessary metadata, but the status still shows "Ready for Submit." Additionally, when I save the page, a "Submit for Review" button briefly appears for a fraction of a second on the subscription page before disappearing.
Is this button missing, or is there a known issue with this process? This is my first time running this test, and I would appreciate any pointers or suggestions. Thanks!
Hello,
I am consistently receiving the error message "In-app purchases are not allowed on this device" whenever I try to make an in-app purchase on my iOS device. Despite following all the recommended solutions I could find online, the issue remains unresolved.
Here is a list of the steps I have already taken:
Checked Screen Time Settings:
I navigated to Settings > Screen Time > Content & Privacy Restrictions > iTunes & App Store Purchases.
I have confirmed that "In-App Purchases" is set to "Allow." I have also tried toggling this setting off and on again.
Signed Out & In of Apple ID:
I signed out of my Apple ID via Settings > [Your Name] > Media & Purchases, restarted the device, and then signed back in.
Restarted the Device:
I have force-restarted my device multiple times.
Updated iOS:
I have ensured my device is running the latest version of iOS (checked via Settings > General > Software Update).
Verified Payment Method:
I have confirmed that my payment method on file is valid and up-to-date.
Created a New Sandbox Account:
I also created a new Sandbox Tester account in App Store Connect and tested with it, but the result was the same.
Device Information:
Device Model: iPhone 15, iPhone 13
iOS Version: iOS 17.5, iOS 18
Even after performing all of these steps, the problem persists. Has anyone else encountered such a stubborn issue, or does anyone have a different solution I could try?
Thank you in advance for your help.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit Test
StoreKit
In-App Purchase
I cannot test IAP using sandbox account that I logged on from settings, it keeps show my regular Apple ID when I try to test IAP from TestFlight
This issue frustrate me and bunch of my colleagues, we cannot manage our subscription when sandbox account is default choosing Apple ID
I've seen people complaining about this issue a lot
Any help on resolving this issue would be really appreaciated
When simulating a Storekit error like an invalid device verification or others of that type, should we finish a failed transaction? When I test with a Storekit configuration file, all failed transactions persist after every restart. The Apple-provided sample code for Storekit 2 has transactions finished only when they are successful.
I am currently using the App Store Server API Get All Subscription Statuses in the app I am in charge of.
Please let me confirm the following regarding Get All Subscription Statuses.
■Prerequisites
The language used is Objective-c, and I am using both XCode 15 and 16. I also have an App Store Connect account.
■Questions
Is it possible to set and test each status of the App Store Server API Get All Subscription Statuses with TestFlight?
Hi All,
We are trying to integrate Promotional Offer in our app, We have a React Native app and are using react-native-iap for handling our in app purchases, as per the documentation we are generating signature in our BE and passing the proper details to the function as well, but for subscription request which have offer applied we are getting the apple pop up properly as well with offer details but when trying to subscribe it gives us SKErrroDomain: 12,
for subscription without applying offer the subscription goes through but when we apply the offer we get the above error.
Our app is currently in Development Stages and has not been sent for review sam for our subscription plans as well.
Please let me know what could be the probable cause for this and help us resolve the issue.
This is the code snippet of ours for the front end :
export const buySubscription = async (subscriptionData: any) => {
try {
if (subscriptionData.offer_id) {
const response = await getSubscriptionSignature(
subscriptionData.productId,
subscriptionData.offer_id,
);
const offerData = response?.data;
const offer = {
identifier: offerData?.offer_id,
keyIdentifier: offerData?.key_id,
nonce: offerData?.nonce,
signature: offerData?.signature,
timestamp: Number(offerData?.timestamp),
};
await requestSubscription({
sku: subscriptionData.productId,
withOffer: offer,
});
} else {
await requestSubscription({ sku: subscriptionData.productId });
}
} catch (err) {
logger.error('Subscription error: ' + JSON.stringify(err));
throw err;
}
};
and
from my python Backend which generates the signature:
def generate_signature(self, product_id: str, offer_id: str) -> dict:
"""
Generate signature for Apple StoreKit promotional offers.
Args:
product_id: The product identifier from App Store Connect
offer_id: The promotional offer identifier
Returns:
dict: Contains signature and required metadata
Reference: https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/implementing_promotional_offers_in_your_app
"""
try:
# Generate UUID without dashes and use as nonce
nonce = str(uuid.uuid4())
timestamp = get_current_time_ms() # milliseconds
# Create the payload string in exact order required by Apple
payload_components = [
self.bundle_id, # App Bundle ID
self.key_id, # Key ID from App Store Connect
product_id, # Product identifier
offer_id, # Promotional offer identifier
nonce, # UUID without dashes
str(timestamp) # Current timestamp in milliseconds
]
payload_str = "\u2063".join(payload_components) # Use Unicode separator
logger.debug(f"Signing payload: {payload_str}")
# Create SHA256 hash of the payload
digest = hashes.Hash(hashes.SHA256())
digest.update(payload_str.encode('utf-8'))
payload_hash = digest.finalize()
# Sign the hash using ES256 (ECDSA with SHA-256)
signature = self.private_key.sign(
data=payload_hash,
signature_algorithm=ec.ECDSA(hashes.SHA256())
)
# Encode signature in base64
signature_b64 = base64.b64encode(signature).decode('utf-8')
logger.info(f"Generated signature for product {product_id} and offer {offer_id}")
return {
"key_id": self.key_id, # Changed to match Apple's naming
"nonce": nonce, # UUID without dashes
"timestamp": timestamp, # As integer
"signature": signature_b64, # Base64 encoded signature
"product_id": product_id, # Changed to match Apple's naming
"offer_id": offer_id # Changed to match Apple's naming
}
except Exception as e:
logger.error(f"Failed to generate signature: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Failed to generate signature: {str(e)}"
)
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
App Store Connect
Advanced Commerce API
My server's access to Apple's payment interface (buy. itunes. apple. com/verifiyReceipt) has been unresponsive since the end of March, and I have been searching for a long time without finding any issues. Normally, even if the data is incorrect, there is still a {"status": 21000} response. We are using Alibaba Cloud's virtual servers here. I don't know if Apple has made any adjustments to the interface. If anyone has encountered this problem, please kindly help to answer it. Thank you all.
Topic:
App & System Services
SubTopic:
StoreKit
Dear Apple Developer Support,
Our iOS application offers subscriptions with a free trial period. We understand that in South Korea, due to local subscription regulations, users must explicitly provide consent for recurring payments before the subscription converts from a free trial to a paid period.
We have the following questions regarding how StoreKit handles this scenario:
When a free trial is about to convert to a paid subscription for a user in South Korea, does StoreKit send a StoreKit.Message (or SKStorefront.Message) to the application to obtain the required consent for recurring payments?
If such a message is sent, would the Reason for this message be StoreKit.Message.Reason.priceIncreaseConsent, or would it be another specific reason related to initial recurring payment consent after a trial?
If our application receives such a message and we choose to defer its display, what is the maximum recommended or permissible deferral period?
Is it possible to save the data of a received StoreKit.Message and display it to the user at a later time, for instance, after the application has been closed and subsequently reopened? Are there any best practices or limitations regarding this?
We need this information to ensure our application correctly handles these consent requirements in compliance with South Korean policies and provides a smooth user experience.
Thank you for your guidance.
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
Is there an API Endpoint that I can call to check if user still have valid subscription?
I want to be sure that his subscription renewal was succesful (ie: I dont want to give him another month/year/.. if his latest renewal wasnt successful)
Would GET https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId} be the correct API endpoint to call?
But I wonder, after subscription auto-renews, do we still use the same transactionId to check whether his subs is still valid?
Topic:
App & System Services
SubTopic:
StoreKit
I noticed a very weird behavior for refunds. When a user refunds an up-front paid app, they still have access to the app. How can I detect such a case and block access to the app?
In general, I think it should be handled by Apple, but for some reason, they don't do it.
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!
Dear community,
Context
My company operates in the European Union, where not so long ago there appeared the possibility to accept an ["Alternative Terms Addendum for Apps in the EU"] (https://developer.apple.com/contact/request/download/alternate_eu_terms_addendum.pdf), which, among others, gives us the possibility to use an alternative payment provider, other than Apple's In App Purchase PSP system (ref: Apple docs). My company did accept it and was granted the StoreKit External Purchase Entitlement (com.apple.developer.storekit.external-purchase) entitlement, with which we integrated a different PSP, so now we want to incorporate the reporting to Apple's External Purchase Server API. We are currently integrating with the External Purchase Server API and have encountered a couple of issues I would appreciate clarification on:
Question 1
Is there a way to retrieve an overview or summary of the current subscription states on Apple’s servers as a result of the submitted reports to External Purchase Server API? Specifically, I would like to verify the expected outcomes before the monthly invoice is issued by Apple and to understand the subscription states for the test users I used during this process and for future reference as well.
Question 2
In one scenario, I initiated a one-year subscription, and in the middle of its period, I submitted a RENEWAL for one month with a higher price.
I expected the request to fail due to overlapping periods and/or pricing conflicts, but both submissions were accepted without error.
Do you have an idea about:
What happens at the end of the renewed month?
Will the subscription continue with the renewed (higher) amount, revert to the original (lower) annual rate, or be canceled?
Where can I view the final state and billing plan for that subscription?
Thank you for your assistance, we are looking forward for any kind of help or information regarding this topic.
Issue Description
When using the App Store Server API endpoint GET v2/history/{transactionId} to retrieve transaction history for a specific transaction, I'm observing unexpected changes in the appTransactionId field across related transactions in the same subscription group.
Important Context: This is a "clean" auto-renewable subscription with no user intervention - the user has had continuous auto-renewals without any upgrades, downgrades, cancellations, or resubscriptions. The subscription has been renewing automatically and successfully throughout the entire period.
API Call
GET v2/history/1000000000000001
Response Data
The API returns the following transaction history, where I notice the appTransactionId values are inconsistent across what should be a straightforward auto-renewal sequence:
Note: The data below has been sanitized for privacy protection (IDs, bundle identifiers, etc. have been replaced with example values), but the logical relationships, date sequences, and the core issue remain identical to the original data.
Array
(
[0] => Array
(
[transactionId] => 1000000000000001
[originalTransactionId] => 1000000000000001
[webOrderLineItemId] => 1000000000000001
[bundleId] => com.example.myapp
[productId] => MonthlySubscription
[subscriptionGroupIdentifier] => 20000000
[purchaseDate] => 1743784032000
[originalPurchaseDate] => 1743784034000
[expiresDate] => 1746376032000
[quantity] => 1
[type] => Auto-Renewable Subscription
[inAppOwnershipType] => PURCHASED
[signedDate] => 1751868174651
[environment] => Production
[transactionReason] => PURCHASE // Original purchase
[storefront] => USA
[storefrontId] => 143441
[price] => 100000
[currency] => USD
[appTransactionId] => 700000000000000001 // Different value
)
[1] => Array
(
[transactionId] => 1000000000000002
[originalTransactionId] => 1000000000000001
[webOrderLineItemId] => 1000000000000002
[bundleId] => com.example.myapp
[productId] => MonthlySubscription
[subscriptionGroupIdentifier] => 20000000
[purchaseDate] => 1746376032000
[originalPurchaseDate] => 1746347349000
[expiresDate] => 1749054432000
[quantity] => 1
[type] => Auto-Renewable Subscription
[inAppOwnershipType] => PURCHASED
[signedDate] => 1751868174651
[environment] => Production
[transactionReason] => RENEWAL // First auto-renewal
[storefront] => USA
[storefrontId] => 143441
[price] => 100000
[currency] => USD
[appTransactionId] => 700000000000000002 // Same for renewals
)
[2] => Array
(
[transactionId] => 1000000000000003
[originalTransactionId] => 1000000000000001
[webOrderLineItemId] => 1000000000000003
[bundleId] => com.example.myapp
[productId] => MonthlySubscription
[subscriptionGroupIdentifier] => 20000000
[purchaseDate] => 1749054432000
[originalPurchaseDate] => 1749025657000
[expiresDate] => 1751646432000
[quantity] => 1
[type] => Auto-Renewable Subscription
[inAppOwnershipType] => PURCHASED
[signedDate] => 1751868174651
[environment] => Production
[transactionReason] => RENEWAL // Second auto-renewal
[storefront] => USA
[storefrontId] => 143441
[price] => 100000
[currency] => USD
[appTransactionId] => 700000000000000002 // Same as previous renewal
)
[3] => Array
(
[transactionId] => 1000000000000004
[originalTransactionId] => 1000000000000001
[webOrderLineItemId] => 1000000000000004
[bundleId] => com.example.myapp
[productId] => MonthlySubscription
[subscriptionGroupIdentifier] => 20000000
[purchaseDate] => 1751646432000
[originalPurchaseDate] => 1751617840000
[expiresDate] => 1754324832000
[quantity] => 1
[type] => Auto-Renewable Subscription
[inAppOwnershipType] => PURCHASED
[signedDate] => 1751868174651
[environment] => Production
[transactionReason] => RENEWAL // Third auto-renewal
[storefront] => USA
[storefrontId] => 143441
[price] => 100000
[currency] => USD
[appTransactionId] => 700000000000000002 // Same as previous renewals
)
)
Questions
Is this behavior expected? Should the appTransactionId change between the original purchase and subsequent renewals within the same subscription group, especially when there are no user actions (upgrades/downgrades/cancellations/resubscriptions)?
What determines the appTransactionId value? The documentation doesn't clearly explain when this identifier might change or what triggers a new value. This is particularly puzzling since this is a straightforward auto-renewal scenario.
How should we handle this in our backend logic? Should we treat transactions with different appTransactionId values as separate entities, or should we rely on originalTransactionId for grouping related subscription transactions?
Is this a known issue? We've seen similar concerns in the community regarding transaction ID inconsistencies, but this specific case involves a clean auto-renewal flow without any complicating factors.