Greetings!
I was reviewing the documentation for the Apple Store Server Notification v1 APIs and saw the deprecation notice. We are currently unable to migrate to v2 in the near future. With that in mind, I want to know if there were any plans to shut off v1, and if so, was there any timeline we could expect? Thank you in advance.
Reference: https://developer.apple.com/documentation/appstoreservernotifications/app-store-server-notifications-version-1
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,
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
I am using StoreKit 2 for my products and noticed that users from Ukraine (for example) receive a wrong Product.displayPrice.
The App Store works with USD but shows the local currency UAH.
Any chance to display the correct currency (USD)?
Topic:
App & System Services
SubTopic:
StoreKit
I have implemented IAP. The purchases are successful. The refresh receipt is working fine, which then calls the requestDidFinish(_ request: SKRequest) delegate. I'm fetching the receipt url through 'Bundle.main.appStoreReceiptURL'. When I convert the receipt data in base64 string and send it to app store's sandbox api and try to validate the receipt, it fails giving status code : 21002.
This documentation describes what kind of data we should be sending to Apple server, once we are receiving CONSUMPTION_REQUEST
https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest
But, it doesn't describe what kind of data we are receiving, when we are receiving CONSUMPTION_REQUEST?
May I know, is such a document available?
Thank you.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
App Store Server Notifications
App Store Server API
App Store Server Library
Im building a small iphone app with StoreKit and currently testing it in testflight right on my mac, not on iphone. StoreKit part almost exactly copied from SKDemo from one of the Apple's WWDC. For some users and for myself Transaction.currentEntitlements always returns .unverified results. I double-checked Apple Connect settings, i checked my internet connection and everything is fine. Is there some pitfalls for testflight on mac? How can I find out what is causing this problem?
I have an app which is already on App Store with In-app purchase. Now I want to integrate In-app purchase in my another app for the same products as in the existing app. Both the apps are using same Apple Account. Can I reuse those Product Ids from the first app in the second one. If yes, what is the ways to use them.
Thank you in advance.
Hi,
I am trying to obtain the subscription expiry date or purchase date from server using Storekit2 for my project.
I have an account which is already having an active subscription but it still says no purchase found.
Thanks
Hello. My newly released app includes a 1 day free trial. I've done this by creating a non-consumable in-app purchase priced at 0. I consider the free trial active if there's a transaction (from Transaction.currentEntitlements) for that product such that transaction.originalPurchaseDate is less than 24 hours ago. This works fine locally in the simulator and also in TestFlight, however it does not seem to work in the actual app from the App Store. The user can "purchase" it fine; they see the purchase sheet with the product name and the $0.00 price, and when they double press the side button it all seems to work. However, the app then behaves as if it didn't work. The free trial product is no longer available though.
One thing is that I didn't follow the naming convention “XX-day Trial”. Could that be the problem? If so, is that meant to be for the product reference name?
Topic:
App & System Services
SubTopic:
StoreKit
I'm working on my first subscription for an app I've built, and can't seem to figure out where I'm going wrong with this one whether it's something in Xcode or App Store Connect. Any idea where to start? Somethings to check. TIA.
Topic:
App & System Services
SubTopic:
StoreKit
Hi
To test SkAdNetwork, I installed the profile from the documentation (https://developer.apple.com/documentation/storekit/testing-ad-attributions-with-a-downloaded-profile) on my ios device.
and turned off and on Allow Apps to Request to Track to change the idfa value.
In this state, I installed the app (bundle id: id436731843) using SKAdNetwork with the following values at April 8th AM 01 (UTC)
SkAdnetwork version: 3.0
fidelity
fidelity=0, nonce=b3346a51-f7b5-42a2-a508-775a62317c83, timestamp=1744076349671, signature=...
fidelity=1, nonce=b3346a51-f7b5-42a2-a508-775a62317c83, timestamp=1744076349672, signature=...
itunesitem=436731843
network=87u5trcl3r.skadnetwork
sourceapp=1220307907
I was hoping to get a postback after , but after a day, the postback is still not delivered.
Any idea why the postback is not delivered?
Thank you
Topic:
App & System Services
SubTopic:
StoreKit
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.
Hey everyone,
I'm currently preparing an older iOS app for App Store release that includes a non-consumable In‑App Purchase using StoreKit 2. Everything works perfectly in the StoreKitTest environment inside Xcode – the product loads, the purchase flow runs, the transaction verifies.
However, when I run the same app through TestFlight, I always get the error:
❌ Product not available - mapped to
Here’s what I’ve already checked:
✅ The product ID is correct and matches what’s in App Store Connect (case-sensitive).
✅ The IAP is created in App Store Connect and includes:
Title
Product ID
Price Tier
Screenshot for review
✅ The App Store "Paid Applications" agreement is active.
✅ The app is using the correct bundle ID.
✅ I'm using Product.products(for: [productID]) from StoreKit 2.
✅ I’ve implemented fallback and retry logic (e.g. reload after delay).
✅ All IAP logic is wrapped in @MainActor and async-safe.
As the App got Rejected on Review, the IAP is also now in the Rejected Status.
Now the IAP shows status:
🟠 "Developer Action Required"
And App Review rejected the IAP with the message:
"Your first In‑App Purchase must be submitted together with a new app version."
But if I add the App to the Test again and therefore the IAP, then the app will get Rejected again for App Completeness, IAP does not work...
What am I doing wrong here? :)
Thanks a lot in advance
Cheers,
Niklas
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
StoreKit Test
App Review
StoreKit
In-App Purchase
My server is able to receive notifications for successful purchases. However, we are experiencing an issue where we do not receive any server notifications when a consumable product is refunded.
Could you please help us verify if this behavior is expected? Also, is there a way to trigger a test refund notification for consumable products in the sandbox environment, so we can ensure our server is correctly set up to handle it?
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
Hi,
Using StoreKit 2 with App Store Server notifications like so:
User selects a purchase
App calls Product.purchase()
If successful, App Store notifies our backend with the transaction details, importantly with a UUID for the transaction ID.
This works fine, but when I try to test contingent pricing via the handy StoreKit config Transaction Manager in Xcode by creating a PurchaseIntent if I then complete the purchase in the app the Transaction ID is sequential, (0 for the first, 1 for the second etc), which doesn't work for us as the backend might already have that ID stored so the purchase never completes.
If I disable the config file it works fine, but then I can't use the Transaction Manager debug tool. Is there a way to override the ID of a custom transaction that's created via the StoreKit configuration?
Thanks
Cannot retrieve products for iap or subscription on simulator iPhone 16 and real device iPhone XR also.
lutter: IAPError(code: storekit2_products_error, source: app_store, message: The operation couldn’t be completed. (NSURLErrorDomain error -1009.), details: The operation couldn’t be completed. (NSURLErrorDomain error -1009.))
flutter: Error fetching IAP products: IAPError(code: storekit2_products_error, source: app_store, message: The operation couldn’t be completed. (NSURLErrorDomain error -1009.), details: The operation couldn’t be completed. (NSURLErrorDomain error -1009.))
アプリに課金を実装しようと思うのですが、もし不正利用された場合、アプリ側は基本的にApp Storeを通じて対応するよう案内するのが一般的と思いますが、Apple ID不正利用時とクレジットカード不正利用時で、アプリ側が行う標準的な対応プロセスは変わるのか教えていただきたいです。
また下記内容は標準的な対応プロセスとして問題ないでしょうか?
■Apple ID不正利用時
→ ユーザー自身がAppleサポートに連絡し、パスワード変更・二段階認証の設定・不正購入の返金申請などを行うよう案内する。
■クレジットカード不正利用時
→ まずカード会社への連絡を促すが、アプリ内決済に関してはAppleのカスタマーサポート経由で返金や調査手続きを案内する
不正利用されたユーザーへの対応に備えて、アプリ側が考慮すべきことがあれば教えてください。
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?
Hi everyone,
I’m struggling to get StoreKit 2 to fetch products in my SwiftUI app while using a sandbox user. I think I’ve followed all necessary setup steps in Xcode, App Store Connect, and my physical test device, but Product.products(for:) always returns an empty array. I’d appreciate any insights!
What I’ve Done
Local App Setup (Xcode 16.2)
Created a blank SwiftUI Xcode project.
Enabled In-App Purchase capability under Signing & Capabilities.
Implemented minimal StoreKit 2 code to fetch available products (see below).
Using the correct bundle identifier, which matches App Store Connect.
App Store Connect Configuration
Registered the app with the same bundle identifier.
Created an Auto-Renewable Subscription with:
Product ID: v1 (matches my code).
All fields filled (pricing, localization, etc.).
Status: Ready for Review.
Linked the subscription to the latest app version in App Store Connect.
Sandbox User & Testing Setup
Created a sandbox tester account.
Logged in with the sandbox user under Settings → Developer → Sandbox Apple ID. This was on my physical device (iOS 18.2).
Installed and ran the app directly from Xcode (⌘+R).
Issue: StoreKit Returns No Products
Product.products(for:) does not return any products.
There are no errors thrown, just an empty array.
I confirmed that StoreKit Configuration is set to None in Xcode.
No StoreKit-related logs appear in the Console.
Code Snippets
//StoreKitManager.swift
import StoreKit
import SwiftUI
@MainActor
class StoreKitManager: ObservableObject {
@Published var products: [Product] = []
@Published var errorMessage: String?
func fetchProducts() async {
do {
let productIDs: Set<String> = ["v1"] // Matches App Store Connect
let fetchedProducts = try await Product.products(for: productIDs)
print(fetchedProducts) // Debug output
DispatchQueue.main.async {
self.products = fetchedProducts
}
} catch {
DispatchQueue.main.async {
self.errorMessage = "Failed to fetch products: \(error.localizedDescription)"
}
}
}
}
//ContentView.swift
import SwiftUI
struct ContentView: View {
@StateObject private var storeKitManager = StoreKitManager()
var body: some View {
VStack {
if let errorMessage = storeKitManager.errorMessage {
Text(errorMessage).foregroundColor(.red)
} else if storeKitManager.products.isEmpty {
Text("No products available")
} else {
List(storeKitManager.products, id: \.id) { product in
VStack(alignment: .leading) {
Text(product.displayName).font(.headline)
Text(product.description).font(.subheadline)
Text("\(product.price.formatted(.currency(code: product.priceFormatStyle.currencyCode ?? "USD")))")
.bold()
}
}
}
Button("Fetch Products") {
Task {
await storeKitManager.fetchProducts()
}
}
}
.padding()
.onAppear {
Task {
await storeKitManager.fetchProducts()
}
}
}
}
#Preview {
ContentView()
}
Additional Information
iOS Version: 18.2
Xcode Version: 16.2
macOS Version: 15.3.1
Device: Physical iPhone (not simulator)
TestFlight Build: Not used (app is run directly from Xcode)
StoreKit Configuration: Set to None