StoreKit

RSS for tag

Support in-app purchases and interactions with the App Store using StoreKit.

StoreKit Documentation

Posts under StoreKit subtopic

Post

Replies

Boosts

Views

Activity

StoreKit2: appAccountToken in purchase() always returns first value instead of updated UUID
Hello, I’m experiencing an issue with StoreKit 2 when passing a new appAccountToken for each purchase request. Case-ID: 15948169 (for DTS reference) Description of the Problem When initiating a purchase, I generate a new UUID to use as the appAccountToken: let serverTransactionId = UUID() let options: Set<Product.PurchaseOption> = [ .appAccountToken(serverTransactionId) ] let result = try await product.purchase(options: options) Expected Behavior: Each new purchase should return the updated appAccountToken that I pass into the purchase options. Actual Behavior: The payload response after success always contains the same appAccountToken from the very first transaction. It ignores subsequent UUIDs I pass and keeps reusing the original one. This causes issues because the same identifier is being reused across multiple transactions, making it difficult to map purchases to the correct user session. Steps to Reproduce Generate a fresh UUID using UUID(). Pass it as .appAccountToken when calling purchase(). Complete the transaction in the sandbox environment. Inspect the payload response → The appAccountToken value is always the same as the first one used, not the newly provided one. Additional Info I do have a focused test project that reproduces this issue. The issue appears specific to appAccountToken persistence across multiple transactions. Has anyone else experienced this behavior with StoreKit 2? Is this expected (Apple caching the first token) or could this be a bug?
3
1
316
Nov ’25
Incorrect storefront country code
Both the legacy StoreKit API and the new StoreKit 2 API return the incorrect storefront countryCode. My actual Apple ID region is Germany, and my Sandbox test user is set to France, yet the SDK consistently returns USA. Expected Results: The returned storefront countryCode should reflect the correct region - sandbox user region if signed in and real user region if not signed in with sandbox). Actual Results: Returned country code is USA with both SKPaymentQueue.default().storefront?.countryCode and await Storefront.current?.countryCode. Signing out/in, device reboot and even reset do not help, I'm stuck with USA storefront.
3
1
303
Oct ’25
SubscriptionStoreView Localization Error
Hello! The localization isn't working when using SubscriptionStoreView. The app hasn't been published yet. The subscription has been created and localization strings have been added. Status - ready to submit. Testing environment: Sandbox When calling SubscriptionStoreView, the debug console shows this error: GenerativeModelsAvailability.Parameters: Initialized with invalid language code: ru-RU. Expected to receive two-letter ISO 639 code. e.g. 'zh' or 'en'. Falling back to: ru Despite this, the subscription interface appears in English when Russian is expected. I don't use any locale setting for ru-RU anywhere in my code. The test device's region is set to Russia, and the language is Russian. Any help would be appreciated.
0
1
206
May ’25
Storekit configuration broken in Xcode 16.4 the file has been changed
Hi everyone, After updating to Xcode 16.4, my StoreKit configuration stopped working. Whenever I run the app with a .storekit file set as the active scheme, I immediately get this alert: “The file has been changed. Do you want to save your changes or revert to the file on disk?” No matter if I choose Save Anyway or Revert, StoreKit testing does not work - the purchases are not simulated, and the scheme is basically broken. This issue didn’t exist in Xcode 15.4 - the same StoreKit configuration file works fine there. What I tried so far: Clearing Derived Data - no effect Making sure no scripts/tools modify the .storekit file - still happens Restarting Xcode and macOS - no change Environment: Xcode 16.4 Happens in both Simulator and on device Reproducible 100% Has anyone else seen this in 16.4? Any known workarounds until Apple fixes it? Thanks!
5
1
423
Oct ’25
Unresolved pending purchases for consumables
In our app we are running into a few issues with pending purchases staying on receipt indefinitely. These are consumable purchases where we received the purchase succeeded from apple but then something went wrong on our servers to validate and confirm the purchase. At this point the purchase stays on the apple receipt indefinitely or until we confirm it. The problem is there are lots of scenarios where we can't confirm purchases anymore (like a game world expired/banned player/etc). So there's a few things I'd like to know to see how this could be handle correctly. 1- Was the user already charged, and if yes would they ever be refunded if the purchase is not confirmed (some sort of expiry)? 2- Is there a way to cancel this sort of pending transaction directly from the app or backend? 3- If one of these users asked for a refund from apple would this clear the purchase from the receipt? Any information would be greatI couldn't find a lot of info on this topic.
0
1
49
Jun ’25
storefront.countryCode is fixed to USA in iOS 26 beta
Whether using Storefront.current?.countryCode or SKPaymentQueue.default().storefront?.countryCode, both are returning "USA" only. (It used to return the correct country code before the update.) In the sandbox environment, the country code is returned correctly, but in the TestFlight environment, it always returns "USA". There's no mention of this behavior in the beta release notes, so I'm posting it here for visibility.
1
1
149
Jul ’25
Does originalTransactionId change if a user resubscribes?
Hello, For In App Purchases with a renewable subscription, does the originalTransactionId change in the following scenarios? Case 1: A user subscribes to a subscription A within a Subscription Group SG1. The user then cancels it at the end of the month. Comes back later to subscribe to the same subscription A within the same Subscription Group SG1. Case 2: A user subscribes to a subscription A within a Subscription Group SG1. The user then cancels it at the end of the month. Comes back later to subscribe to subscription B within the same Subscription Group SG1.
3
1
1.1k
Mar ’25
The currency information obtained from [priceLocale] differs between the TestFlight version and the official release version.
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?
2
0
145
Apr ’25
Mac OS 15.4 breaks receipt Validation
I'm using Swift to verify receipts in myObjective C Mac Application using the following code: @objc class MyAppTransaction: NSObject{ @objc class func checkReceipt() async -> String { do { let verificationResult = try await AppTransaction.shared switch verificationResult { case .verified(_): return "VERIFIED" case .unverified(_, _): return "NO RECEIPT" } } catch { return "ERROR" //(StoreKit.StoreKitError) unknown } } } Starting today with my upgrade to Sequoia 15.4 and XCode 16.3 receipt validation is broken. The function is going to the catch and returning "ERROR" I can't set a break point in the do {} but if I set one at the return "ERROR", in the debugger error = (StoreKit.StoreKitError) unknown. the Compiler logs an error:Failed to parse AppTransaction: missingValue(for: [StoreKit.AppTransaction.Key.appTransactionID], expected: StoreKit.BackingValue). Reading the developer documentation I can't find anything about these struct members. I tried to use refresh() to get a receipt like I used to with exit(173) but the compiler says refresh () not found. This is extremely troubling because I can't debug my receipt validation code and I don't know if this will happen to my users. Do I just have to trust Apple that my users will have an application with a receipt attached? What can I do?
8
0
271
Apr ’25
Resending notifications from Apple
Regarding App Store Server Notifications V2,we are currently using Notifications V2 in a production environment. It is set up so that if the server receives the notification successfully, it returns 200 after about 30 seconds, and if an error occurs, it returns 400 or 500. However, the notification is being resent multiple times from Apple's server, at 1 hour, 12 hours, and 24 hours. Is it necessary to return the notification using Apple's API?
2
0
127
Apr ’25
Converting Payed App to Freemium
I just converted my App to Freemium, but the method is used to give user, that bought the App before it was free, access to the paid futures seems not to be working. I am getting the original Purchase Date from the AppTransaction (https://developer.apple.com/documentation/storekit/apptransaction/originalpurchasedate) and comparing that to a set date where the App Model changed. In Test Flight this is working without any Problems but on the Live System, users that have purchased the App do not get access! let shared = try await AppTransaction.refresh() if case .verified(let appTransaction) = shared { result(appTransaction.originalPurchaseDate.ISO8601Format()). } I am using flutter to develop the App and the result()... send the string back to the flutter side. Here is the code of the Flutter side: Future<void> restorePurchases() async { SubscriptionProvider().updatePayment(PurchaseStatus.pending); await InAppPurchase.instance.restorePurchases(); if (Platform.isIOS) { DateTime changedToFreemium = DateTime.utc(2025, 4, 7, 11, 0, 0); String? purchaseDateRaw = await IosFlutterChannel().getOriginalPurchaseDate(); if (kDebugMode) { print("Purchase Date Raw: $purchaseDateRaw"); } if (purchaseDateRaw != null) { DateTime purchaseDate = DateTime.parse(purchaseDateRaw); if (purchaseDate.isBefore(changedToFreemium)) { if (kDebugMode) { print("Restoring legacy purchases"); } SubscriptionProvider().update(true, SubscriptionStatus.active, SubscriptionType.fs_lifetime); } else { if (kDebugMode) { print("Not restoring legacy purchases"); } } } } SubscriptionProvider().updatePayment(PurchaseStatus.purchased); } Console Log when running in Test Environment: flutter: Purchase Date Raw: 2013-08-01T07:00:00Z flutter: Restoring legacy purchases Thanks!
1
0
135
Apr ’25
Renewal Info never contains offerType
Signed renewal info from 'Get Subscription Statuses' or in server notifications never has the offerType or offerDiscountType even when the corresponding transaction does have those values set. Our offer is a free trial. Do these properties refer to something different in JWSRenewalInfoDecodedPayload than they do in transactions? I'm trying to determine whether a subscription (identified by originalTransactionId) is currently in a free trial based on server notifications. The status doesn't tell us if the subscription is currently in free trial and the signedTransactionInfo may be for an older transaction.
1
0
666
Feb ’25
Postback copies dev testing with AdAttributionKit
Hello, Having bad times with Development Postback copies receival on our custom server. Current setup: App is configured to be advertised (https://developer.apple.com/documentation/adattributionkit/configuring-an-advertised-app) AdAttributionKit - Opt in for Reengagement Postback Copies ✅ AdAttributionKit - Postback Copy URL ✅ AdAttributionKit - Ad Network Identifiers ✅ Configured backend https://{name}.com/.well-known/appattribution/report-attribution/ (POST) ✅ Devices with iOS 18.4 (with Postaback Development tool and AdAttribution developer mode Enabled) Tried different Postback setup combinations, with different app builds (debug, release installed from xcode/testflight) and with AdAttribution developer mode Enabled/Disabled - doesn't make any difference. Console log: Found 0 postbacks eligible for transmission for environments: Any advise is very much appreciated
1
0
149
Apr ’25
Why Non-Consumable product has originalTransactionId?
I try to call Get Transaction Info from App Store Server API, and the transactionId is for a Non-consumable type product, but it is odd that there are so many different transactionId and they have a same originalTransactionId { "bundleId": "${bundleId}", "environment": "Production", "inAppOwnershipType": "PURCHASED", "originalPurchaseDate": 1691220528000, "originalTransactionId": "${originalTransactionId}", "productId": "${productId}", "purchaseDate": 1691220528000, "quantity": 1, "signedDate": 1692590989925, "storefront": "USA", "storefrontId": "143441", "transactionId": "${originalTransactionId}", "transactionReason": "PURCHASE", "type": "Non-Consumable" } the defination of Non-Consumable is can only purchase once for same apple account. But why there would have originalTransactionId?
3
0
1.1k
May ’25
Server Not Receiving Apple App Store Server Notification
Hello, Our server isn't receiving Apple App Store Server Notification for in-app purchases. It works for Sandbox Server, even I sent a test notification which I received on the Production Server URL, but the real in-app payment notification isn't coming to the server. I checked this already: https://developer.apple.com/documentation/appstoreservernotifications/enabling-app-store-server-notifications and everything here has been reviewed. Transport Layer Security (TLS) version and others things mentioned have been checked, test notification was received. But the main in-app purchase notification for live transaction isn't coming. What's the issue precisely?
4
0
421
May ’25
Apple Pay v2 (signedTransactionInfo) : how to verify new token format and migrate from legacy EC_v1?
I’m updating a legacy application that used Apple Pay v1 token format, and in my new revamped version I’m now receiving the newer Apple Pay v2 format. The old (v1) payload looked like this: php { "version": "EC_v1", "data": "...", "signature": "...", "header": { "ephemeralPublicKey": "...", "publicKeyHash": "...", "transactionId": "..." } } In the new revamp (v2), Apple Pay returns this instead: php { "signedTransactionInfo": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF..." } From what I understand: v1 tokens were elliptic-curve encrypted JSON objects containing a header and signature. v2 tokens seem to be JWS (JSON Web Signature) strings using the ES256 algorithm, possibly containing transaction and subscription details inside. Questions Is there any official Apple documentation or migration note explaining the move from EC_v1 → signedTransactionInfo? How should I verify or decode the new signedTransactionInfo payload? Should the verification now use Apple’s public keys instead of the legacy Merchant ID certificate? Are there any example implementations or SDKs that can handle both v1 and v2 formats during migration? Is there a recommended way to maintain backward compatibility while transitioning existing users? Goal Ensure that my revamped app can handle Apple Pay v2 tokens securely while keeping the legacy v1 integration functional until all users are migrated.
1
0
448
1d
In-App Purchases rejected + Reviewer cannot complete purchase although sandbox works fine (StoreKit2)
Hi everyone, I’m experiencing an issue with In-App Purchases during App Review. What works My consumable IAP products load correctly using StoreKit2. TestFlight (sandbox) purchases work perfectly. Localizations are filled in and valid. Paid Apps Agreement, banking, and tax forms are active. IAP products are properly created in App Store Connect and marked as “Developer Action Needed” only because they wait for approval with the new binary. What fails During review I received: “We found that your in-app purchase products exhibited one or more bugs which create a poor user experience. Specifically, we were not able to complete a purchase.” They didn’t provide any more technical details. Additional context The StoreKit configuration file is not included in the app archive. Product identifiers perfectly match those in App Store Connect. StoreKit2 purchase() works as expected on TestFlight. The app does not use server-side receipt validation - purchases are handled purely through StoreKit2 APIs, as recommended. My questions What could cause a situation where TestFlight purchases work but App Review cannot complete a purchase? Does Apple expect server-side receipt validation even for simple one-time consumables? Could there be a delay or sync issue causing IAP products to not be available to the reviewer yet? Is there anything I should check on the App Store Connect side beyond what I already verified? Any help or hints would be greatly appreciated - I’m stuck because everything works in sandbox but fails only for reviewers. Thanks!
1
0
230
Dec ’25
iOS misleading users with payment notification timing
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!
2
0
979
Jun ’25