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

Unpredictable delays in async responses from StoreKit 2
Hi, I've been reported, and I've experienced myself, extremely slow responses from StoreKit 2 on boot. I can reproduce the issue quite consistently with the iPhone, sometimes Transaction.currentEntitlements hangs for minutes even after the device has attained full Internet access. My app is a VPN client, so there's certainly a chicken-and-egg situation, but I'm performing a basic test without the in-app validation in the packet tunnel provider. The tunnel starts fine on boot (on-demand), whereas the app takes ages to return from AppTransaction.shared and Transaction.currentEntitlements. I guess this is caused by some network call inside the framework (maybe spoiled by the on-demand VPN?), but with no timeout, exceptions, logging, or future-proof fallback (appStoreReceiptURL is deprecated), I'm poking in the dark. It goes without saying, keeping the users waiting minutes to be credited for their purchases is a no-go. I still can't find a reasonable workaround, but the frustrating part is that StoreKit 2 was supposed to make these things straightforward. At times, it doesn't feel "ready" and I spend on it a lot of time that I'd rather invest in the product. Does this sound familiar to anybody? Thanks in advance Davide
1
0
243
Feb ’25
Calling AppTransaction in a SpriteKit app
Hello 👋! I'm trying to switch the business model in my app from premium to freemium, gracefully so that existing users aren't bothered. I'd like to provide newly-paywalled content for original paid users. For this to work, I need to use originalAppVersion in AppTransaction, and support iOS 16 at minimum. I've asked about originalAppVersion earlier here. I've upped to iOS 16 already, but I don't exactly know how to call AppTransaction.shared to get originalAppVersion. The issue lies in the fact that my app is based on SpriteKit, so the operative areas I have available to call AppTransaction are ostensibly limited to AppDelegate and GameViewController. I'm using the code from Supporting business model changes by using the app transaction, but if I place it in either GameViewController or AppDelegate, for example in application(_:didFinishLaunchingWithOptions:) or viewDidLoad(), I get an error concerning async/await. Now, I understand the gist of it: these are not asynchronous methods. So I'm trying to understand how to do it perhaps outside of these methods. How do I call AppTransaction.shared (and fetch originalAppVersion) in a SpriteKit based app?
0
0
137
Jul ’25
Best practices: ensuring server-side that the AppReceipt sent up by a client belongs to the client
Hi, all! I have an AppStore Server-side question. User sends up an AppReceipt that I am validating. What's the best way to tell the receipt belongs to said user? I want to make sure that the source of the AppReceipt was actually the original purchaser of the item. Is fetching Transaction + AppAccountToken the only way? AppAccountToken can only be utilized if the original purchase used it, and it is associated with the user's data. Is there another way?
0
0
300
Feb ’25
not getting stable release versions of some apps from the ios app store
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?
0
0
53
Apr ’25
不正利用された場合、Apple ID不正利用時とクレジットカード不正利用時で、アプリ側が行う標準的な対応プロセスは変わるのか
アプリに課金を実装しようと思うのですが、もし不正利用された場合、アプリ側は基本的にApp Storeを通じて対応するよう案内するのが一般的と思いますが、Apple ID不正利用時とクレジットカード不正利用時で、アプリ側が行う標準的な対応プロセスは変わるのか教えていただきたいです。 また下記内容は標準的な対応プロセスとして問題ないでしょうか?
 ■Apple ID不正利用時 → ユーザー自身がAppleサポートに連絡し、パスワード変更・二段階認証の設定・不正購入の返金申請などを行うよう案内する。 ■クレジットカード不正利用時 → まずカード会社への連絡を促すが、アプリ内決済に関してはAppleのカスタマーサポート経由で返金や調査手続きを案内する 不正利用されたユーザーへの対応に備えて、アプリ側が考慮すべきことがあれば教えてください。
0
0
105
May ’25
Inconsistent appTransactionId in Transaction History
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.
1
0
173
Jul ’25
StoreKit2 Subscription Verification
My question is simple, I do not have much experience in writing swift code, I am only doing it to create a small executable that I can call from my python application which completes Subcription Management. I was hoping someone with more experience could point out my flaws along with giving me tips on how to verify that the check is working for my applicaiton. Any inight is appreciated, thank you. import Foundation import StoreKit class SubscriptionValidator { static func getReceiptURL() -> URL? { guard let appStoreReceiptURL = Bundle.main.appStoreReceiptURL else { print("No receipt found.") return nil } return appStoreReceiptURL } static func validateReceipt() -> Bool { guard let receiptURL = getReceiptURL(), let receiptData = try? Data(contentsOf: receiptURL) else { print("Could not read receipt.") return false } let receiptString = receiptData.base64EncodedString() let validationResult = sendReceiptToApple(receiptString: receiptString) return validationResult } static func sendReceiptToApple(receiptString: String) -> Bool { let isSandbox = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" let urlString = isSandbox ? "https://sandbox.itunes.apple.com/verifyReceipt" : "https://buy.itunes.apple.com/verifyReceipt" let url = URL(string: urlString)! let requestData: [String: Any] = [ "receipt-data": receiptString, "password": "0b7f88907b77443997838c72be52f5fc" ] guard let requestBody = try? JSONSerialization.data(withJSONObject: requestData) else { print("Error creating request body.") return false } var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = requestBody request.setValue("application/json", forHTTPHeaderField: "Content-Type") let semaphore = DispatchSemaphore(value: 0) var isValid = false let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil, let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let status = jsonResponse["status"] as? Int else { print("Receipt validation failed.") semaphore.signal() return } if status == 0, let receipt = jsonResponse["receipt"] as? [String: Any], let inApp = receipt["in_app"] as? [[String: Any]] { for purchase in inApp { if let expiresDateMS = purchase["expires_date_ms"] as? String, let expiresDate = Double(expiresDateMS) { let expiryDate = Date(timeIntervalSince1970: expiresDate / 1000.0) if expiryDate > Date() { isValid = true } } } } semaphore.signal() } task.resume() semaphore.wait() return isValid } }
0
0
343
Feb ’25
Biometric Authentication Behavior in IAP Sandbox Environment
Where the problem occurs: In-app purchase Non-ApplePay Non-local authentication login Environment where the problem occurs: Sandbox environment (Development environment, TestFlight environment) Problem handling process: Open page A in the app and purchase product B (auto-renewable subscription) on that page. User authentication is required to purchase product B. During the authentication process, the user needs to enter the Apple account and Apple account password. After completing the authentication, complete the purchase of product B. Problem in step 3: Why is FaceID or TouchID not used for authentication? Note: Face ID and Password -> iTunes Store and App Store -> Status is Enabled
0
0
121
Jun ’25
IAP Can not Use Sand Box Test
I am currently using StoreKit2 to set up the in-app purchase subscription flow, and I have already configured the subscription products in App Connect. I created a StoreKit Configuration file in Xcode and used it in the scheme. However, after completing the purchase, the transaction.jsonRepresentation data returns a transactionId of 0. After checking the documentation, I found that I need to disable the StoreKit Configuration and enable Sandbox Testing. But after disabling the StoreKit Configuration, I can't retrieve the real product data using Product.products(for: productIds). I can confirm that the ProductId I provided is real and matches the data configured in App Connect. Could you please help me identify the issue?
0
0
175
Feb ’25
Regarding the pattern of multiple original transaction IDs being linked
In the app we're distributing, we've identified a user where the Get All Subscription Statuses API returns two original transaction IDs in the data response. This user has gone through cancellations and re-subscriptions since their initial purchase. Meanwhile, despite maintaining a continuous subscription, a notification suddenly arrives on the renewal date with original_transaction_id2. +---------------------------+---------------------------+---------------------+ | original_transaction_id | notification_type | subtype | +---------------------------+---------------------------+---------------------+ | original_transaction_id1 | SUBSCRIBED | INITIAL_BUY | ~ Repeated cancellations and re-subscriptions ~ | original_transaction_id1 | SUBSCRIBED | RESUBSCRIBE | | original_transaction_id2 | SUBSCRIBED | INITIAL_BUY | +---------------------------+---------------------------+---------------------+ Although it can be inferred from the interface definition of the API itself that multiple original transaction IDs may be returned, what causes multiple original transaction IDs to be returned? Furthermore, is it possible to reproduce the case where multiple original transaction IDs are returned in the sandbox environment provided by Apple? As for this app, it: Uses subscriptions through in-app purchases. Does not offer upgrades, downgrades, or crossgrades, having only one product. Has never undergone price increases or decreases. Is distributed exclusively in Japan.
0
0
84
Jun ’25
InApp purchase get stuck in paymentQueue purchasing status.
Some of my users reported they can not completed the purchase . According to the logs and screen captures . Their purchase progress's last status are "purchasing" func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { .... .... case .purchasing: // 处理正在购买的情况 //print("购买中"); AppDelegate.log.debug("paymentQueue purchasing"); LoadingAlert.shared.setText(text: "购买中".localized()) .... After this ,It neither entered any error branch nor prompted the user to confirm the purchase or enter a password, but simply stopped here. There are no other purchase-related logs, and the program is still running normally. At the same time, other users are able to complete their purchases without any issues. However, there have been 4-5 users recently who reported problems with purchasing. What could be the possible reasons? In my local environment, I repeated the test many times, including using sandbox users from different regions and real Apple IDs, and everything worked fine. // // Payment.swift // RadialMenu // // Created by pat on 2023/6/26. // import Foundation import StoreKit class Payment:NSObject,SKProductsRequestDelegate,SKPaymentTransactionObserver{ func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { AppDelegate.log.debug("paymentQueue transaction product = \(transaction.payment.productIdentifier) state = \(transaction.transactionState)"); //let productID = transaction.payment.productIdentifier switch transaction.transactionState { case .purchased,.restored: if(transaction.transactionState == .purchased){ AppDelegate.log.debug("paymentQueue purchased"); LoadingAlert.shared.setText(text: "已购买".localized()) } if(transaction.transactionState == .restored){ LoadingAlert.shared.setText(text: "已恢复".localized()) AppDelegate.log.debug("paymentQueue restored"); } //} break; case .failed: AppDelegate.log.debug("paymentQueue failed "); if let error = transaction.error as? NSError { // 获取错误代码和描述 let errorCode = error.code let errorDescription = error.localizedDescription AppDelegate.log.debug("paymentQueue Transaction failed with error code: \(errorCode), description: \(errorDescription)") } queue.finishTransaction(transaction) LoadingAlert.shared.hideModal(); // 处理购买失败的情况 // 提供错误信息给用户 //print("购买失败"); alertRetry(); break; case .deferred: AppDelegate.log.debug("paymentQueue deferred"); LoadingAlert.shared.setText(text: "购买延迟".localized()) // 处理交易延迟的情况(仅限家庭共享) break; case .purchasing: // 处理正在购买的情况 //print("购买中"); AppDelegate.log.debug("paymentQueue purchasing"); LoadingAlert.shared.setText(text: "购买中".localized()) break; @unknown default: AppDelegate.log.debug("paymentQueue nknown default\(transaction.transactionState)"); break } } }
1
0
372
Mar ’25
Inquiry about Successful Subscription Without Payment Charge
Hi, I'm a server developer working on an iOS app, and I've encountered an interesting case that I'd like to understand better. We received a user report indicating that they were able to successfully start a subscription without any charge being processed on their payment method. The subscription appears to be active in our system and we can verify the receipt with Apple's server, but the user claims no payment was deducted from their account. I'm curious to know: Are there any known scenarios where a subscription might activate without an immediate payment charge? What would be the recommended way to handle such cases from the developer's perspective? Could this be related to any specific subscription states or edge cases in the IAP system? Any insights or documentation references would be greatly appreciated. I want to ensure we're handling our subscription logic correctly and providing the best experience for our users. Thank you in advance for your help!
0
0
204
Jan ’25
Operation of Server Notifications V2 when Apple account is withdrawal
Please allow me to confirm the Server Notifications V2 specification. I am aware that if withdrawal an Apple account that has a subscription, the subscription will eventually be cancelled. Regarding Server Notifications V2 notifications with a notificationType of EXPIRED, am I correct in thinking that they will be sent when the subscription expires even if the Apple account is withdrawal?
0
0
298
Feb ’25
Urgent: Reports of Duplicate Charges via AlipayHK on Apple Pay
We’ve recently observed an escalating number of complaints from AlipayHK users regarding duplicate charges when completing transactions via Apple Pay. While no similar issues have been reported by users of other credit card providers integrated with Apple Pay, the problem appears isolated to AlipayHK transactions. Key Details: Multiple users confirm being charged twice for single transactions. Complaints are increasing in frequency, indicating a potential systemic issue. No overlapping reports from non-AlipayHK payment methods at this time. To safeguard customer trust and ensure seamless payment experiences, we kindly request Apple’s support in: Investigating whether the root cause stems from Apple Pay’s transaction handling. Collaborating with AlipayHK (if necessary) to resolve the issue promptly. Providing guidance on interim measures to prevent further duplicate charges. Could Apple confirm if this is a known issue and share a timeline for resolution? We’re eager to assist in any way possible to mitigate impact on users. Thank you for your urgent attention to this matter.
1
0
82
May ’25
Sandbox user can't see StoreKit subscriptions
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
2
0
409
Mar ’25
StoreKit Subscription Fails to Load During App Review, Works in Sandbox/TestFlight
Hi everyone, I’m facing a recurring issue with my macOS app being rejected during App Store review, and I’d really appreciate any guidance. The subscription flow in my app is implemented using StoreKit, and everything works perfectly in our development environment using a StoreKit configuration file. It also behaves as expected in Sandbox testing and TestFlight — I even had few beta testers confirm that the subscription information is displayed correctly and the purchase flow completes without issues. All required subscription details are configured in App Store Connect: • Subscription duration and the description of the services offered • Price and price per unit where applicable • Paid apps agreement and related forms are correctly filled However, when the app is submitted for review, the subscription screen fails to display the expected information. From what I can tell, the product information fails to load from the App Store in the review environment — even though everything is working fine on our side. We’ve already submitted a video to Apple showing the subscription UI working in the Sandbox environment, but the app continues to be rejected under guideline 3.1.2 due to missing subscription info in the binary. Is anyone else experiencing similar behavior during review? Could there be a caching issue or delay in StoreKit syncing for newly configured products? Any help or suggestions are very welcome. Thanks in advance!
0
0
99
Apr ’25
App Clip Closes Before SKOverlay Can Show “Open” Button When Live Activity Is Involved
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.
1
0
289
Mar ’25
Transaction.id will be repeated in Apple in-app purchase
In the sandbox environment, when I quickly and repeatedly purchase an item, Transaction.id will be repeated. Will there be duplication in the production environment? func pay(productId: String, orderId: String) async { guard !productId.isEmpty, !orderId.isEmpty else { return } let orderObj = ApplePayOrderModel.init(orderId: orderId, productId: productId) do { let result = try await Product.products(for: [productId]) guard let product = result.first else { return } let purchaseResult = try await product.purchase() switch purchaseResult { case .success(let verification): switch verification { case .verified(let transaction): orderObj.transactionId = String(transaction.id) await transaction.finish() case .unverified(let transaction, let error): await transaction.finish() } case .userCancelled: break case .pending: break @unknown default: break } } catch { print("error \(error.localizedDescription)") } }
1
0
238
Jan ’25
Clarification on offerIdentifier Behavior in TransactionPayload and Upgrade Scenarios
Hello everyone, I have some questions regarding the behavior of the offerIdentifier property in the TransactionPayload from App Store Server Notifications. When a user redeems an Offer Code, the offerIdentifier field is populated with the respective identifier. However, I am unsure how this field behaves in different scenarios, and I would appreciate any insights or clarification: Does the offerIdentifier persist throughout the subscription lifecycle (from the initial purchase to expiration)? Does it become null once the Offer Code benefits expire? Is it only present at the time of purchase and omitted in subsequent notifications? Additionally, I would like to understand the behavior of the offerIdentifier in the following scenario: A user purchases a lower-tier subscription using an Offer Code. Later, they upgrade to a higher-tier plan, causing the Offer Code benefits to effectively expire. What happens to the offerIdentifier in the transaction for the upgrade? Will it still appear in transactions after the upgrade, or will it be null? I couldn't find explicit details about these situations in the official documentation, so I hope someone here might have experience or knowledge to share. Thank you in advance for your help!
0
0
401
Jan ’25
repeat subscription
After the user initiates the subscription payment, the SDK returns an error type: user cancels. When the user initiates the payment again, Apple will deduct the payment twice and successfully deduct the previously cancelled SKU. This is a recent occurrence with a large amount of data, and the app has not been upgraded in any way. We need to seek help. Thank you
0
0
192
Mar ’25