The same store kit configuration file works in iOS and iPadOS, but not in macOS for the same multi platform application project with a single scheme.
Here’s a more detailed write up with the sample code and screenshots. When the simple app is run on
https://www.reddit.com/r/SwiftUI/s/KJsYcggWOa
EDIT: I’m using Xcode 16.4
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
We sell magazines through a third party app platform called Pocketmags and our website. The magazines have Print, Digital and Combo options available for purchase. Also, this third party app provides the platform to read the digital version of the magazines.
Once a user buys a subscription on the website, he/she receives the email with the login information on PocketMags, where he registers his login details and can start reading his subscription. With us, the customer shares his billing/shipping address along with their email id while they make payment.
Now we have our own app where through which we want to sell these magazines and have to integrate In-App purchase for selling these digital subscriptions. How do we send the 3rd party subscription access details on email to the user if they do in app purchase?
Hello,
I have a question regarding the App Store Server API's getTransactionInfo endpoint.
Previously, the official documentation for getTransactionInfo mentioned that:
“This endpoint doesn’t support an app transaction. To get information about an app transaction, decode the signed app transaction received from the device.”
However, as of June 2025, I can no longer find this sentence in the current documentation (link). Now, the docs state that all in-app purchase transaction IDs are supported (consumable, non-consumable, auto-renewable subscriptions, etc.).
But in practice, when I call getTransactionInfo with an AppTransactionId (extracted from a signed App Transaction JWS), I receive this error: apiErrorCode: 4000048
“Invalid request. App transactions aren’t supported by this endpoint.”
Is this endpoint supposed to support AppTransactionId now, or is the restriction still in place (but not mentioned in the docs)?
Is there any official statement about when this restriction was added/removed?
Can you clarify if only in-app purchase transaction IDs (and not AppTransactionIds) are supported for this endpoint, or has the policy changed recently?
Any clarification or historical context would be greatly appreciated.
Additionally, I would like to know about the behavior of an App Transaction in the event of a refund.
If a user receives a refund for the app itself (not an in-app purchase), how can changes to the AppTransaction be detected?
Does the App Store Server Notification v2 provide notifications for app-level refunds, or are such events only visible by decoding the latest App Transaction JWS on the device?
Is there any way to receive app-level refund information server-side, or must we always rely on the device to provide the updated signed app transaction?
Any clarification on this refund flow and notification coverage would also be appreciated.
Thank you!
users download app with Streamlined Purchasing ,but the logic of checking subscription doesn't work. there the code:
func checkSubscriptionStatus() async {
for await entitlement in Transaction.currentEntitlements {
guard case .verified(let transaction) = entitlement else { continue }
if transaction.productID == monthlyProductID || transaction.productID == yearlyProductID {
if transaction.revocationDate == nil && !transaction.isUpgraded {
let activeSubscribed = transaction.expirationDate ?? .distantFuture > .now
if activeSubscribed {
hasActiveSubscription = activeSubscribed
// other operation
}
}
}
}
}
Unsure if this has been reported before, but I'm seeing a specific scenario where Apple is sending back faulty information in App Store Server Notifications.
When users have payment failures that result in the membership expiring, and then reactivate later on with a different subscription, they are given a new originalTransactionId, yet we have three cases where we receive messages about the old originalTransactionId, indicating that after the user recovers their subscription, Apple is resurrecting the old subscription and treating it as if it is active BUT ultimately decides to deactivate it.
Here is a sample screenshot of an impacted user. We only have three month and annual plans.
Timeline:
March 21st:
This user signed up for a 3 Month Plan
June 21st:
This user fails to pay
July 7th:
After our 16 day grace period, this user loses access
July 29th:
This user sees they lost access and repurchase
Augsut 19th:
Their membership is deactivated (long before their 3 Month Subscription is up)
For further verification I've also attached a record of all the payloads we've received from Apple for this user.
Please let me know if you need any more details to fix this bug OR if it has already been fixed! Thank you.
user_webhook_data_sanitized.csv
Strange issue with currency display in subscription products
Hi everyone,
I'm facing a strange issue in my app where I use a subscription-based in-app purchase model.
The products I created in App Store Connect are all in "Approved" status.
I've tested with both RevenueCat and StoreKit, but the result is the same.
Here are the products being loaded:
Product loaded: weekly_product_id
Display name: Weekly Pro
Description: Weekly Pro Subscription
Price: ₺229,99
Product loaded: annual_product_id
Display name: Annual Pro
Description: Annual Pro Subscription
Price: ₺1.799,99
Even though I can see the correct prices and currency (Turkish Lira) in the Xcode debug console, on my real device the currency appears as Philippine Peso, as shown in the attached screenshot.
Interestingly, in the iOS simulator, it's displayed in USD.
I've double-checked and my device's region settings are set to Turkey.
Any ideas on what could be causing this? And more importantly, how can I fix it?
Thanks in advance!
I have an App Clip that uses SKOverlay.AppClipConfiguration to install the full app. Before I added a Live Activity call (Activity.request), the user could see “Install,” then “Open.” Now, once “Get” is tapped, the Clip immediately closes—no “Open” button appears. If I remove the Live Activity code, it works again.
I’ve confirmed that parent/child entitlements match, and tested via TestFlight. Is there a known issue or recommended workaround for combining SKOverlay + Live Activities in an App Clip so it doesn’t dismiss prematurely? Any insights are appreciated!
Note live activity is for App Clip only.
I am shown as being subscribed to our service in the Subscriptions list in settings yet when going to the Storekit2 page in my app it shows me as NOT being subscribed and is unresponsive. I select Restore Subscription, that grays briefly, asks for a password, then returns to blue and nothing else happens. Bouncing back and forth between monthly and yearly likewise gives no response.
The Transaction.currentEntitlements seems to be empty so it thinks the user is not subscribed.
I have unsubscribed, and resubscribed via the Settings page to no avail.
Topic:
App & System Services
SubTopic:
StoreKit
I have an auto-renewable subscription. I have two methods helping me keep track of when they are expired
@MainActor public func isPurchased(product: Product) async -> Bool {
guard let state = await product.currentEntitlement else {
return false
}
switch state {
case .unverified(_, _):
return false
case .verified(let transaction):
await transaction.finish()
return isTransactionRelevant(transaction)
}
}
private func isTransactionRelevant(_ transaction: Transaction) -> Bool {
if let revocationDate = transaction.revocationDate {
logger.error("Transaction verification failed: Transaction was revoked on \(revocationDate)")
return false
}
if let expirationDate = transaction.expirationDate,
expirationDate < Date()
{
logger.error("Transaction verification failed: Transaction expired on \(expirationDate)")
return false
}
if transaction.isUpgraded {
logger.error("Transaction verification failed: Transaction was upgraded")
return false
}
logger.info("Transaction verification succeeded")
return true
}
I also have this that I can call to get the latest state of purchases
@MainActor public func updateStoreKitSubscriptionStatus() async {
var currentProductsPurchased: [Product] = []
for await result in Transaction.currentEntitlements {
if case .verified(let transaction) = result {
if isTransactionRelevant(transaction) {
if let product = products.first(
where: { $0.id == transaction.productID
})
{
currentProductsPurchased.append(product)
}
}
await transaction.finish()
}
}
self.purchasedProducts = currentProductsPurchased
}
Right now when a subscription expires the user needs to manually do some action that triggers updateStoreKitSubscriptionStatus() as it appears that expirations do not come through in Transaction.updates.
I am surprised there does not seem to be a better way. Does StoreKit not notify you somewhere that an auto-renewable subscription has expired? Can you observe it in an ObservableObject? Or do I need to just frequently poll Transaction.currentEntitlements even if I dont expect frequent updates?
Topic:
App & System Services
SubTopic:
StoreKit
Hi,
I have developed an app which has two in-app purchase subscriptions. During the test, the app can successfully get the status of the subscriptions. After it's released, I downloaded it from app store and subscribed it with my apple account. I found that in most cases, the app can identify that I have subscribed it and I can use its all functions. But yesterday, when I launched it again, it showed the warning that I haven't subscribed it. I checked my subscription in my account and the subscription status hasn't been changed, that is, I have subscribed it. And after one hour, I launched it again. This time the app identified that I have subscribed it. Why? The following is the code about listening to the subscription status. Is there any wrong about it?
HomeView()
.onAppear(){
Task {
await getSubscriptionStatus()
}
}
func getSubscriptionStatus() async {
var storeProducts = [Product]()
do {
let productIds = ["6740017137","6740017138"]
storeProducts = try await Product.products(for: productIds)
} catch {
print("Failed product request: \(error)")
}
guard let subscription1 = storeProducts.first?.subscription else {
// Not a subscription
return
}
do {
let statuses = try await subscription1.status
for status in statuses {
let info = try checkVerified(status.renewalInfo)
switch status.state {
case .subscribed:
if info.willAutoRenew {
purchaseStatus1 = true
debugPrint("getSubscriptionStatus user subscription is active.")
} else {
purchaseStatus1 = false
debugPrint("getSubscriptionStatus user subscription is expiring.")
}
case .inBillingRetryPeriod:
debugPrint("getSubscriptionStatus user subscription is in billing retry period.")
purchaseStatus1 = false
case .inGracePeriod:
debugPrint("getSubscriptionStatus user subscription is in grace period.")
purchaseStatus1 = false
case .expired:
debugPrint("getSubscriptionStatus user subscription is expired.")
purchaseStatus1 = false
case .revoked:
debugPrint("getSubscriptionStatus user subscription was revoked.")
purchaseStatus1 = false
default:
fatalError("getSubscriptionStatus WARNING STATE NOT CONSIDERED.")
}
}
} catch {
// do nothing
}
guard let subscription2 = storeProducts.last?.subscription else {
// Not a subscription
return
}
do {
let statuses = try await subscription2.status
for status in statuses {
let info = try checkVerified(status.renewalInfo)
switch status.state {
case .subscribed:
if info.willAutoRenew {
purchaseStatus2 = true
debugPrint("getSubscriptionStatus user subscription is active.")
} else {
purchaseStatus2 = false
debugPrint("getSubscriptionStatus user subscription is expiring.")
}
case .inBillingRetryPeriod:
debugPrint("getSubscriptionStatus user subscription is in billing retry period.")
purchaseStatus2 = false
case .inGracePeriod:
debugPrint("getSubscriptionStatus user subscription is in grace period.")
purchaseStatus2 = false
case .expired:
debugPrint("getSubscriptionStatus user subscription is expired.")
purchaseStatus2 = false
case .revoked:
debugPrint("getSubscriptionStatus user subscription was revoked.")
purchaseStatus2 = false
default:
fatalError("getSubscriptionStatus WARNING STATE NOT CONSIDERED.")
}
}
} catch {
// do nothing
}
if purchaseStatus1 == true || purchaseStatus2 == true {
purchaseStatus = true
} else if purchaseStatus1 == false && purchaseStatus2 == false {
purchaseStatus = false
}
return
}
Topic:
App & System Services
SubTopic:
StoreKit
We're planning on increasing the price of our ios in-app subscription. We will select the option "Keep the current price for existing subscribers"
Reading this https://developer.apple.com/help/app-store-connect/manage-subscriptions/manage-pricing-for-auto-renewable-subscriptions/, it's not clear if existing subscribers will be notified of the change in pricing (even though that change won't impact them) or not?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
App Store
StoreKit
In-App Purchase
I have been receiving beta software from the iPad App Store, despite not being enrolled in a beta program. Additionally, I do not have TestFlight or the Feedback app installed on my device. There are no certificates or profiles displayed either. I am using the App Store app that comes preinstalled on my device (note that I am not located in Europe).
My iPad has been experiencing significant bugs, including numerous screen glitches and periods of sluggishness. Furthermore, numerous applications have crashed frequently. I was able to confirm that I was receiving beta software because the crash reports include beta identifier numbers. According to Apple documentation regarding analytic reports, a beta identifier will only be visible for beta applications.
anyone know what could be going on or how to fix this?
Topic:
App & System Services
SubTopic:
StoreKit
Hello all,
Posting here before I put in a support ticket to see if there are any ideas.
The previous beta issues seem to have been resolved, but now we are having intermittent problems with sandbox purchases. We do not know if this will affect real purchases. This is happening on beta 9 in both public and dev channels for us, most often on iPad Pro 4th. gen (Though idk if that is relevant).
Sometimes running TestFlight builds on iOS 26 beta 9 devices we will have attempts to make sandbox purchases just go into a black hole.
We do not get a "Do you want to buy this" popup, or the credentials screen. It just pauses for a bit in the section of our code that would be akin to:
let result = try await product.purchase( options: [.appAccountToken(accountUUID) ] )
Then wait a couple seconds, and then nothing. The game returns to normal flow as if it was a pending purchase, but nothing more ever happens. We have not been able to get a local debug build to do this, so it's hard for us to tell if it is going into the pending bucket, the userCancelled bucket, or the unverified bucket, etc.
If we take a device in this state and remove the app and reinstall from TestFlight we will get a credentials popup on the first attempt after install to buy, and after putting in our info we will get the " "You've already purchased this In-App Purchase...", but nothing ever his our listener and we return to the broken state.
Has anyone else seen issues like this?
P.S. Our StoreKit logic code is currently widely distributed, so if it was reproducible in the live version on iOS 18 we would know about it.
Thanks, Chris
Topic:
App & System Services
SubTopic:
StoreKit
代码块
让购买结果=尝试等待购买(产品,选项:[选项])
//处理支付结果
开关购买结果{
案例让.success(验证结果):
如果案例让.verified(交易)=验证结果{
await transaction.finish()case .userCancelled:
自我.取消回调?()
案例.pending:
/// 交易可能在未来成功,通过Transaction.updates进行通知。
打印(“苹果支付中待定”)
默认:
打破
}
} 抓住 {
自我失败回电话?(”产品购买失败:\(错误)")
打印(“产品购买失败:\(错误)”)
}
凭证相关信息如下:
transactionid:1230000065994257
appAccountToken:D613C126-4142-4BFF-9960-00AE3F5A6F83
"jwsInfo": ["header": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlFTURDQ0E3YWdBd0lCQWdJUWZUbGZkMGZOdkZXdnpDMVlJQU5zWGpBS0JnZ3Foa2pPUFFRREF6QjFNVVF3UWdZRFZRUURERHRCY0hCc1pTQlhiM0pzWkhkcFpHVWdSR1YyWld4dmNHVnlJRkpsYkdGMGFXOXVjeUJEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURUxNQWtHQTFVRUN3d0NSell4RXpBUkJnTlZCQW9NQ2tGd2NHeGxJRWx1WXk0eEN6QUpCZ05WQkFZVEFsVlRNQjRYRFRJek1Ea3hNakU1TlRFMU0xb1hEVEkxTVRBeE1URTVOVEUxTWxvd2daSXhRREErQmdOVkJBTU1OMUJ5YjJRZ1JVTkRJRTFoWXlCQmNIQWdVM1J2Y21VZ1lXNWtJR2xVZFc1bGN5QlRkRzl5WlNCU1pXTmxhWEIwSUZOcFoyNXBibWN4TERBcUJnTlZCQXNNSTBGd2NHeGxJRmR2Y214a2QybGtaU0JFWlhabGJHOXdaWElnVW1Wc1lYUnBiMjV6TVJNd0VRWURWUVFLREFwQmNIQnNaU0JKYm1NdU1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCRUZFWWUvSnFUcXlRdi9kdFhrYXVESENTY1YxMjlGWVJWLzB4aUIyNG5DUWt6UWYzYXNISk9OUjVyMFJBMGFMdko0MzJoeTFTWk1vdXZ5ZnBtMjZqWFNqZ2dJSU1JSUNCREFNQmdOVkhSTUJBZjhFQWpBQU1COEdBMVVkSXdRWU1CYUFGRDh2bENOUjAxREptaWc5N2JCODVjK2xrR0taTUhBR0NDc0dBUVVGQndFQkJHUXdZakF0QmdnckJnRUZCUWN3QW9ZaGFIUjBjRG92TDJObGNuUnpMbUZ3Y0d4bExtTnZiUzkzZDJSeVp6WXVaR1Z5TURFR0NDc0dBUVVGQnpBQmhpVm9kSFJ3T2k4dmIyTnpjQzVoY0hCc1pTNWpiMjB2YjJOemNEQXpMWGQzWkhKbk5qQXlNSUlCSGdZRFZSMGdCSUlCRlRDQ0FSRXdnZ0VOQmdvcWhraUc5Mk5rQlFZQk1JSCtNSUhEQmdnckJnRUZCUWNDQWpDQnRneUJzMUpsYkdsaGJtTmxJRzl1SUhSb2FYTWdZMlZ5ZEdsbWFXTmhkR1VnWW5rZ1lXNTVJSEJoY25SNUlHRnpjM1Z0WlhNZ1lXTmpaWEIwWVc1alpTQnZaaUIwYUdVZ2RHaGxiaUJoY0hCc2FXTmhZbXhsSUhOMFlXNWtZWEprSUhSbGNtMXpJR0Z1WkNCamIyNWthWFJwYjI1eklHOW1JSFZ6WlN3Z1kyVnlkR2xtYVdOaGRHVWdjRzlzYVdONUlHRnVaQ0JqWlhKMGFXWnBZMkYwYVc5dUlIQnlZV04wYVdObElITjBZWFJsYldWdWRITXVNRFlHQ0NzR0FRVUZCd0lCRmlwb2RIUndPaTh2ZDNkM0xtRndjR3hsTG1OdmJTOWpaWEowYVdacFkyRjBaV0YxZEdodmNtbDBlUzh3SFFZRFZSME9CQllFRkFNczhQanM2VmhXR1FsekUyWk9FK0dYNE9vL01BNEdBMVVkRHdFQi93UUVBd0lIZ0RBUUJnb3Foa2lHOTJOa0Jnc0JCQUlGQURBS0JnZ3Foa2pPUFFRREF3Tm9BREJsQWpFQTh5Uk5kc2twNTA2REZkUExnaExMSndBdjVKOGhCR0xhSThERXhkY1BYK2FCS2pqTzhlVW85S3BmcGNOWVVZNVlBakFQWG1NWEVaTCtRMDJhZHJtbXNoTnh6M05uS20rb3VRd1U3dkJUbjBMdmxNN3ZwczJZc2xWVGFtUllMNGFTczVrPSIsIk1JSURGakNDQXB5Z0F3SUJBZ0lVSXNHaFJ3cDBjMm52VTRZU3ljYWZQVGp6Yk5jd0NnWUlLb1pJemowRUF3TXdaekViTUJrR0ExVUVBd3dTUVhCd2JHVWdVbTl2ZENCRFFTQXRJRWN6TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd0hoY05NakV3TXpFM01qQXpOekV3V2hjTk16WXdNekU1TURBd01EQXdXakIxTVVRd1FnWURWUVFERER0QmNIQnNaU0JYYjNKc1pIZHBaR1VnUkdWMlpXeHZjR1Z5SUZKbGJHRjBhVzl1Y3lCRFpYSjBhV1pwWTJGMGFXOXVJRUYxZEdodmNtbDBlVEVMTUFrR0ExVUVDd3dDUnpZeEV6QVJCZ05WQkFvTUNrRndjR3hsSUVsdVl5NHhDekFKQmdOVkJBWVRBbFZUTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVic1FLQzk0UHJsV21aWG5YZ3R4emRWSkw4VDBTR1luZ0RSR3BuZ24zTjZQVDhKTUViN0ZEaTRiQm1QaENuWjMvc3E2UEYvY0djS1hXc0w1dk90ZVJoeUo0NXgzQVNQN2NPQithYW85MGZjcHhTdi9FWkZibmlBYk5nWkdoSWhwSW80SDZNSUgzTUJJR0ExVWRFd0VCL3dRSU1BWUJBZjhDQVFBd0h3WURWUjBqQkJnd0ZvQVV1N0Rlb1ZnemlKcWtpcG5ldnIzcnI5ckxKS3N3UmdZSUt3WUJCUVVIQVFFRU9qQTRNRFlHQ0NzR0FRVUZCekFCaGlwb2RIUndPaTh2YjJOemNDNWhjSEJzWlM1amIyMHZiMk56Y0RBekxXRndjR3hsY205dmRHTmhaek13TndZRFZSMGZCREF3TGpBc29DcWdLSVltYUhSMGNEb3ZMMk55YkM1aGNIQnNaUzVqYjIwdllYQndiR1Z5YjI5MFkyRm5NeTVqY213d0hRWURWUjBPQkJZRUZEOHZsQ05SMDFESm1pZzk3YkI4NWMrbGtHS1pNQTRHQTFVZER3RUIvd1FFQXdJQkJqQVFCZ29xaGtpRzkyTmtCZ0lCQkFJRkFEQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqQkFYaFNxNUl5S29nTUNQdHc0OTBCYUI2NzdDYUVHSlh1ZlFCL0VxWkdkNkNTamlDdE9udU1UYlhWWG14eGN4ZmtDTVFEVFNQeGFyWlh2TnJreFUzVGtVTUkzM3l6dkZWVlJUNHd4V0pDOTk0T3NkY1o0K1JHTnNZRHlSNWdtZHIwbkRHZz0iLCJNSUlDUXpDQ0FjbWdBd0lCQWdJSUxjWDhpTkxGUzVVd0NnWUlLb1pJemowRUF3TXdaekViTUJrR0ExVUVBd3dTUVhCd2JHVWdVbTl2ZENCRFFTQXRJRWN6TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd0hoY05NVFF3TkRNd01UZ3hPVEEyV2hjTk16a3dORE13TVRneE9UQTJXakJuTVJzd0dRWURWUVFEREJKQmNIQnNaU0JTYjI5MElFTkJJQzBnUnpNeEpqQWtCZ05WQkFzTUhVRndjR3hsSUVObGNuUnBabWxqWVhScGIyNGdRWFYwYUc5eWFYUjVNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVFzd0NRWURWUVFHRXdKVlV6QjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkpqcEx6MUFjcVR0a3lKeWdSTWMzUkNWOGNXalRuSGNGQmJaRHVXbUJTcDNaSHRmVGpqVHV4eEV0WC8xSDdZeVlsM0o2WVJiVHpCUEVWb0EvVmhZREtYMUR5eE5CMGNUZGRxWGw1ZHZNVnp0SzUxN0lEdll1VlRaWHBta09sRUtNYU5DTUVBd0hRWURWUjBPQkJZRUZMdXczcUZZTTRpYXBJcVozcjY5NjYvYXl5U3JNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEZ1lEVlIwUEFRSC9CQVFEQWdFR01Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01RQ0Q2Y0hFRmw0YVhUUVkyZTN2OUd3T0FFWkx1Tit5UmhIRkQvM21lb3locG12T3dnUFVuUFdUeG5TNGF0K3FJeFVDTUcxbWloREsxQTNVVDgyTlF6NjBpbU9sTTI3amJkb1h0MlFmeUZNbStZaGlkRGtMRjF2TFVhZ002QmdENTZLeUtBPT0iXX0", "payload": "eyJ0cmFuc2FjdGlvbklkIjoiMTIzMDAwMDA2NTk5NDI1NyIsIm9yaWdpbmFsVHJhbnNhY3Rpb25JZCI6IjEyMzAwMDAwNjU5OTQyNTciLCJidW5kbGVJZCI6ImNvbS5taWd1LmNsb3VkYXZwIiwicHJvZHVjdElkIjoibWlndS52aXNpb24uTW92aWUuOCIsInB1cmNoYXNlRGF0ZSI6MTc0NDgwNzYzMjAwMCwib3JpZ2luYWxQdXJjaGFzZURhdGUiOjE3NDQ4MDc2MzIwMDAsInF1YW50aXR5IjoxLCJ0eXBlIjoiTm9uLVJlbmV3aW5nIFN1YnNjcmlwdGlvbiIsImRldmljZVZlcmlmaWNhdGlvbiI6IjdIdUtPRUhRdVd2L0hKZjdLdlBzQnJOWUNoc2V3c3k3enpPZ2k1YjE3UW8wVnd2clhhQ3B5TTNmZTN3cFBqRUwiLCJkZXZpY2VWZXJpZmljYXRpb25Ob25jZSI6ImQ3YzgwOWI2LTFjNDMtNDIwOC1iZWVmLWVhZDUwYzY1ZGIwZCIsImFwcEFjY291bnRUb2tlbiI6ImQ2MTNjMTI2LTQxNDItNGJmZi05OTYwLTAwYWUzZjVhNmY4MyIsImluQXBwT3duZXJzaGlwVHlwZSI6IlBVUkNIQVNFRCIsInNpZ25lZERhdGUiOjE3NDU4MjM1MTU5OTUsImVudmlyb25tZW50IjoiUHJvZHVjdGlvbiIsInRyYW5zYWN0aW9uUmVhc29uIjoiUFVSQ0hBU0UiLCJzdG9yZWZyb250IjoiQ0hOIiwic3RvcmVmcm9udElkIjoiMTQzNDY1IiwicHJpY2UiOjgwMDAsImN1cnJlbmN5IjoiQ05ZIiwiYXBwVHJhbnNhY3Rpb25JZCI6IjcwNDQxMzM2NTEzNjUyNzAzMyJ9", "signature": "SXieZGabBt6xHoSaBsZ1k4AexqkNYzwZel0BEhGqc3mxrd4kzOR5wERRATXySqbqfT3WJzkDAsr9jmCdoz_7-g"], "status": "normal", "transactionId": "1230000065994257"]","Band_Phone_Num":"18653588566","Platform":"124","Oper_Time":"1745823519","verification_time":"1745823519115"},"ISP":"移动","OETM":"1745823519116","CLIENTID":"","CPURATE":"0.257","AMBERUDID":"1f72113ecc704ce4a4cc135e8af71ee6","ANAME":"","MEMRATE":"0.02346919","CITY":"北京","PROMOTION":"\\","CLIENTIP":"192.168.31.74","CLIENTIPV6":"fe80::4e3:40a8:51c3:dbf5","DB":"Apple","APN":"com.migu.cloudavp","ETM":"2025-04-28 14:58:39 116"}
请帮我查一下 是这个订单没关闭成功吗?为什么出现购买新的产品 返回的永远是这个支付凭证。
Topic:
App & System Services
SubTopic:
StoreKit
I'm currently working on transitioning to StoreKit 2. In order to see if my users are legacy users who purchased the app before I implemented an in-app purchase, I am trying to use the original purchase date for the app. Unfortunately, it's returning 0 seconds since 1970.
func updateOriginalPurchaseStatus() async throws {
let transaction = try await checkVerified(AppTransaction.shared)
self.originalPurchaseVersion = transaction.originalAppVersion
self.originalPurchaseDate = transaction.originalPurchaseDate
}
This is from the transaction:
[3] = {
key = "originalPurchaseDate"
value = number (number = 0)
}
Currently trying to figure out when I actually purchased the app, but it might be as early as 2012. And I likely used a download code.
How can I get the region region currently used in the macOS App Store? Preferably via Swift libraries, but any command / function will suffice.
The following StoreKit property seems to always return the region for the Apple Account associated with my macOS user.
await Storefront.current?.countryCode
See the Apple docs.
My macOS Apple Account region is US; in the App Store, when I sign into a different Apple Account whose region is GB (UK), Storefront.current?.countryCode continues to return US, not GB (or UK).
I correctly see prices in pounds instead of in dollars, British spelling instead of American spelling, apps listed in my purchased tab for the UK (not the US) Apple Account, and, in the Account Settings dialog, the UK Apple Account email address, billing address & Country/Region set to United Kingdom.
I didn't get any relevant results from the following command lines:
defaults find GB
defaults find UK
defaults find uk-apple-id@example.com
defaults find uk-apple-id
The following didn't change after I signed into the UK Apple Account in the App Store:
$ defaults read com.apple.AppStoreComponents
{
ASCLocaleID = "en-US@calendar=gregorian";
}
Maybe Storefront.current?.countryCode only specifies the country code for the Storefront that will be used for in-app purchases, instead of for purchasing new apps from the App Store; maybe the former is tied to the Apple Account for the macOS user, instead of to the Apple Account for the App Store. If that's the case, what other mechanism can I use to obtain the country code for the App Store storefront?
Hello Apple Support Team,
We're a developer team that has created an app with subscription-based features, and we've been using App Store Server Notifications to receive updates about user subscription status changes. I'm reaching out to inquire about potential modifications to the App Store Server Notifications approach that might have improved notification delivery times for my app.
So on our appstore app, when a user purchases a subscription, the apple server notifications reach our server and send us the complete detail of that user’s purchase for eg he upgraded or downgraded etc. And then based on the data we receive from app store server notifications, we save it in our database, along with updating the users subscription table in the database. Previously, we experienced delays in receiving the real time notifications from apple on our server, sometimes taking a few minutes, while other times they would arrive immediately. And because of this issue, the users faced delay in seeing their subscription updates, as our db was updated only after the app store server notification reached our server. However, recently, we've noticed a significant improvement, and notifications are now being delivered still in real-time, but without any noticeable delays.
I'm wondering if Apple has made any changes to the App Store Server Notifications system that might have resolved the delay issue. Could you please confirm if any modifications were made in 2025, specifically from January onwards, that might have improved notification delivery times?
Additionally, I'd like to know if these changes apply to both sandbox testing and production environments. If possible, could you please provide more information about the changes or direct me to a resource that might explain the updates?
I'd appreciate your assistance in confirming this information, and I'm looking forward to hearing back from you.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
App Store Connect
App Store Server Notifications
Looking for assistance in managing subscription upgrades for TestFlight users.
I have a few monthly subscriptions, 30days, each with a different set of available features, 1 with all, and 1 with fewer. (All are in proper order and grouped in App Store connection subscriptions)
subscribing seems to be working fine, and purchasing an upgrade is going ok.
what is not: reflecting the upgraded plan in app (currently reflects it will start in 30days when current subscription expires)
I’m lead to believe this will be resolved with a live app in App Store, that will then handle prorating, terminate the old plan and immediately start the new one.
looking for help getting TestFlight to show immediate upgrades.
We are using consumable in-app purchases. Starting from May 27th, we began receiving refund callbacks with the notificationType set to ONE_TIME_CHARGE immediately after users successfully completed a payment.
{
"notificationType": "ONE_TIME_CHARGE",
"signedPayload": "..."
}
During this period, we did not make any changes to our App release or server-side purchase handling logic.
Could this issue result in actual refunds being processed? What steps should we take to resolve this issue?
We also noticed in your changelog that a new notification type ONE_TIME_CHARGE has been introduced.
Can we safely ignore callbacks with the ONE_TIME_CHARGE notification type without affecting refund processing or user experience?
Topic:
App & System Services
SubTopic:
StoreKit
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!