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

Does scheduling a price change of a subscription while keeping the original price for existing subscribers trigger messaging to those users?
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?
0
0
104
May ’25
Verify Receipt is not found - After successful payment for Annual subscription.
The application is developed with Xamarin Framework and it is live now. The customer installed the app and purchased the annual subscription. And for some reason, they uninstall and reinstall the application on the same device. Now user wants to restore the subscription. In the application, there is an option to Restore the subscription. But restore API not return purchase details. But when clicking the subscription button instead of restoring the subscription, it says you subscribed to this plan". is there any possibility of not getting VerifyRecipt even after a successful purchase?
0
0
297
Feb ’25
Strange Pattern of Subscriptions + Refunds — Possible Abuse?
Hi everyone, I'm an indie developer and recently noticed some odd behavior in my app's subscription metrics. There’s been a sudden spike in annual subscriptions, which is very unusual for my app — historically, users rarely choose that option. What’s more concerning is that these subscriptions are almost immediately canceled and refunded. Upon checking analytics (RevenueCat + App Store Connect), I also noticed inconsistencies in user location data: users appear to be from one region (like Singapore), but deeper tracking shows actual usage from Vietnam, a market I’ve never targeted and where I do no advertising. This behavior seems coordinated and is affecting my app’s refund rate, which I worry could raise red flags on the App Store side. Has anyone experienced anything similar? Is there a recommended way to report suspicious subscription/refund activity to Apple or prevent potential abuse like this? Any advice would be really appreciated. Thanks!
0
0
73
Jun ’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
245
Jan ’25
Using Storekit development, unsubscribe and resubscribe callback problem
The app subscription function uses StoreKit. After canceling the subscription, I try to subscribe again and get the following error. I remember it was working fine before iOS 18 was released. { NSLocalizedDescription = "\U53d1\U751f\U672a\U77e5\U9519\U8bef"; NSUnderlyingError = "Error Domain=ASDErrorDomain Code=825 "(null)""; } Hope you can help me solve this problem as soon as possible. Thanks
0
0
306
Jan ’25
Revoked Non-Consumable Purchases & currentEntitlements
We use Transaction.currentEntitlements in StokeKit 2 to unlock functionality based on a Non-Consumable IAP but we have a case involving a refund that seems wrong and I am trying to understand the interation between transactionId, originalTransactionId & revocationReason. The Context: We have a universal App on macOS and iOS that offers a shared Non-Consumable IAP. For this example I have named it "app.lifetime" On macOS we use StoreKit 2 and I am calling the Transaction.currentEntitlements and Transaction.all functions. On iOS we are still using StoreKit 1. This example customer: Originally purchased "app.lifetime" on 2024-10-27 Was refunded by Apple for "app.lifetime" on 2024-10-29 Re-purchased "app.lifetime on 2025-02-24 (I have seen an email receipt of this transaction but it never shows up in Transaction data) (all the above happened on the mac via StoreKit 2) The Transactions (all lightly redacted for privacy): on macOS the following is returned from Transaction.currentEntitlements... { "appTransactionId" : "...8123", "bundleId" : "app", "currency" : "USD", "deviceVerification" : "...", "deviceVerificationNonce" : "...", "environment" : "Production", "inAppOwnershipType" : "PURCHASED", "originalPurchaseDate" : 1729997808000, "originalTransactionId" : "...9955", "price" : 1, "productId" : "app.lifetime", "purchaseDate" : 1729997808000, "quantity" : 1, "signedDate" : 1740416289102, "storefront" : "USA", "storefrontId" : "143441", "transactionId" : "...7511", "transactionReason" : "PURCHASE", "type" : "Non-Consumable" } Note in the above example the originalTransactionId & transactionId are different. Transaction.all however returns both transactions: [ { "appTransactionId" : "...8123", "bundleId" : "app", "currency" : "USD", "deviceVerification" : "...", "deviceVerificationNonce" : "...", "environment" : "Production", "inAppOwnershipType" : "PURCHASED", "originalPurchaseDate" : 1729997808000, "originalTransactionId" : "...9955", "price" : 1, "productId" : "app.lifetime", "purchaseDate" : 1729997808000, "quantity" : 1, "revocationDate" : 1730224102000, "revocationReason" : 0, "signedDate" : 1740415969925, "storefront" : "USA", "storefrontId" : "143441", "transactionId" : "...9955", "transactionReason" : "PURCHASE", "type" : "Non-Consumable" }, { "appTransactionId" : "...8123", "bundleId" : "app", "currency" : "USD", "deviceVerification" : "...", "deviceVerificationNonce" : "...", "environment" : "Production", "inAppOwnershipType" : "PURCHASED", "originalPurchaseDate" : 1729997808000, "originalTransactionId" : "...9955", "price" : 1, "productId" : "app.lifetime", "purchaseDate" : 1729997808000, "quantity" : 1, "signedDate" : 1740416289102, "storefront" : "USA", "storefrontId" : "143441", "transactionId" : "...7511", "transactionReason" : "PURCHASE", "type" : "Non-Consumable" } ] Note here that the original transaction ("...9955") includes a revocationDate and revocationReason that match the expected refund but the secondary transaction that seems to match on all other details is missing the revocation info. Looking at the iOS SK1 receipt data to compare, after a receipt refresh I see only a single transaction "...9955" which includes the cancellation info and transaction "...7511" is not present at all. The impact of this is that on iOS we are considering the purchase void but on macOS we are following currentEntitlements and consdering it still valid. Calling the inApps/v1/history/... server API with the "...7511" transactionId that is shown in the currentEntitlements response returns the "...9955" transaction with the correct revocation status but "...7511" is no returned at all. To Summarise: currentEntitlements on macOS shows transaction "...7511" as active and with an originalTransactionId of "...9955" all on macOS includes both "...7511" as active and "...9955" as revoked iOS reciept data shows only "...9955" as revoked Server API shows only "...9955" as revoked event when explicitly called with "...7511" Neither of them show a more recent purchase the same customer made for the same IAP product. My questions are: Is this a StoreKit bug or am I mis-understanding something? If it's a bug how can I work around it to ensure revoked purchases aren't still appearing in currentEntitlements? Under what conditions can StoreKit generate multiple transactionIds for the same underlying originalTransactionId? I had assumed (and the docs suggest) this only happens for subscriptions but here it is happening for a Non-Consumable IAP. Why would transactionId "...7511" only be present on macOS/SK2 and not visible at all on iOS/SK1 or API? I don't understand why the latest IAP from 2025-02-24 that the customer assures me they made (and has shown me the receipt for is not showing up in the Transactions history at all. Any ideas?
2
0
360
Mar ’25
Auto Renew Subscription Model
Hi, I want to offer an auto-renewable subscription (e.g., $1/month) that grants users (10 document analyses per month), with the count resetting at the start of each billing cycle. -Unused analyses will not roll over to the next month- Additionally, any analyses generated while the subscription is active will remain accessible to the user permanently, even if they cancel the subscription. The paywall, app description, and metadata will clearly state that the subscription grants (10 document analyses per month with no rollover) We want this to be implemented as an auto-renewable subscription model, not as a consumable service or a token/credit system (which we want to avoid). Is this model acceptable under Apple’s guidelines, or would it be considered a token/credit system? Any insights or alternative suggestions would be appreciated.. Thanks
0
0
317
Mar ’25
Migrating to StoreKit 2
Hi Friends, I have an iOS app, which uses around 500 in app purchases for various modules. I am using StoreKit for in app purchase, now trying to migrate this to StoreKit 2. I am using Product.products(for:) method to fetch all the products by sending identifiers of all the 500 In app purchases. In response, I am getting details of only 160 products, the method is not returning remaining in app purchases. What could be the reason for this behaviour, how to get rid of the issue? May be is this the issue will happen only on TestFlight? If someone from Apple assures about it, we have plan to submit the app. Please advise, Thank you.
0
0
97
May ’25
Old developer account still receiving payments after migration
Hi, I've migrated my app to another developer account more than half a year ago, but I'm still receiving a few transaction payments in the old developer account, which currently has no app. The payment date shown in the report is last month. I'm wondering how could this happen. Is it possible for users to initiate a transaction half a year ago and only successfully pay it now?
1
0
72
Mar ’25
Get the region currently used in the macOS App Store
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?
0
0
98
Apr ’25
My Subscription Screen
Hey everyone, This might be a simple fix that I’m just overlooking, but I’ve been stuck on it for the past 48 hours. The issue is on my subscription screen — after a user completes a successful in-app purchase, the app doesn’t navigate to the main app like it’s supposed to. I’ve added logs, tried various fixes, and even asked AI for help, but nothing has worked. From what I can tell, it seems like my listeners aren’t being registered properly after the transaction. I’ve tried reinitializing them, moving them around, and testing different flows, but still no luck. If anyone has insight into how they’ve set this up or any suggestions I might not have considered, I’d really appreciate it. Thanks in advance!
0
0
63
Aug ’25
Cannot use proper sandbox account for internal tester on TestFlight
I cannot test IAP using sandbox account that I logged on from settings, it keeps show my regular Apple ID when I try to test IAP from TestFlight This issue frustrate me and bunch of my colleagues, we cannot manage our subscription when sandbox account is default choosing Apple ID I've seen people complaining about this issue a lot Any help on resolving this issue would be really appreaciated
0
0
62
Mar ’25
sandbox account isn't logging in on purchase window
I don't know if I am posting this in the right place. I am using xcode's phone simulator and I have setup my sandbox account on appstoreconnect under users and access/sandbox/test accounts then in my app on the simulator when I tap the subscribe button to purchase my product the a window pops up for in app purchases and I get a login prompt for my sandbox credentials, but no matter how many times I enter them after tapping ok all I get is a blank login prompt. also not this a brand new sandbox account and I've only changed the password 3 times, that seems to be important because its inconsistent with some of the errors I am getting on the error log here is error log. Purchase did not return a transaction: Error Domain=ASDErrorDomain Code=530 "(null)" UserInfo={NSUnderlyingError=0x600000d09080 {Error Domain=AMSErrorDomain Code=100 "Authentication Failed The authentication failed." UserInfo={NSMultipleUnderlyingErrorsKey=( "Error Domain=AMSErrorDomain Code=2 "Password reuse not available for account The account state does not support password reuse." UserInfo={NSDebugDescription=Password reuse not available for account The account state does not support password reuse., AMSDescription=Password reuse not available for account, AMSFailureReason=The account state does not support password reuse.}", "Error Domain=AMSErrorDomain Code=0 "Authentication Failed Encountered an unrecognized authentication failure." UserInfo={NSDebugDescription=Authentication Failed Encountered an unrecognized authentication failure., AMSDescription=Authentication Failed, AMSFailureReason=Encountered an unrecognized authentication failure.}" ), AMSDescription=Authentication Failed, NSDebugDescription=Authentication Failed The authentication failed., AMSFailureReason=The authentication failed.}}, client-environment-type=Sandbox}
0
0
100
May ’25
"In-App Purchases are not allowed" Error Persists After All Troubleshooting Steps
Hello, I am consistently receiving the error message "In-app purchases are not allowed on this device" whenever I try to make an in-app purchase on my iOS device. Despite following all the recommended solutions I could find online, the issue remains unresolved. Here is a list of the steps I have already taken: Checked Screen Time Settings: I navigated to Settings > Screen Time > Content & Privacy Restrictions > iTunes & App Store Purchases. I have confirmed that "In-App Purchases" is set to "Allow." I have also tried toggling this setting off and on again. Signed Out & In of Apple ID: I signed out of my Apple ID via Settings > [Your Name] > Media & Purchases, restarted the device, and then signed back in. Restarted the Device: I have force-restarted my device multiple times. Updated iOS: I have ensured my device is running the latest version of iOS (checked via Settings > General > Software Update). Verified Payment Method: I have confirmed that my payment method on file is valid and up-to-date. Created a New Sandbox Account: I also created a new Sandbox Tester account in App Store Connect and tested with it, but the result was the same. Device Information: Device Model: iPhone 15, iPhone 13 iOS Version: iOS 17.5, iOS 18 Even after performing all of these steps, the problem persists. Has anyone else encountered such a stubborn issue, or does anyone have a different solution I could try? Thank you in advance for your help.
0
0
208
Jul ’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
Issues with Integration of Promotional Offers in React Native app
Hi All, We are trying to integrate Promotional Offer in our app, We have a React Native app and are using react-native-iap for handling our in app purchases, as per the documentation we are generating signature in our BE and passing the proper details to the function as well, but for subscription request which have offer applied we are getting the apple pop up properly as well with offer details but when trying to subscribe it gives us SKErrroDomain: 12, for subscription without applying offer the subscription goes through but when we apply the offer we get the above error. Our app is currently in Development Stages and has not been sent for review sam for our subscription plans as well. Please let me know what could be the probable cause for this and help us resolve the issue. This is the code snippet of ours for the front end : export const buySubscription = async (subscriptionData: any) => { try { if (subscriptionData.offer_id) { const response = await getSubscriptionSignature( subscriptionData.productId, subscriptionData.offer_id, ); const offerData = response?.data; const offer = { identifier: offerData?.offer_id, keyIdentifier: offerData?.key_id, nonce: offerData?.nonce, signature: offerData?.signature, timestamp: Number(offerData?.timestamp), }; await requestSubscription({ sku: subscriptionData.productId, withOffer: offer, }); } else { await requestSubscription({ sku: subscriptionData.productId }); } } catch (err) { logger.error('Subscription error: ' + JSON.stringify(err)); throw err; } }; and 
from my python Backend which generates the signature:

def generate_signature(self, product_id: str, offer_id: str) -> dict: """ Generate signature for Apple StoreKit promotional offers. Args: product_id: The product identifier from App Store Connect offer_id: The promotional offer identifier Returns: dict: Contains signature and required metadata Reference: https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/implementing_promotional_offers_in_your_app """ try: # Generate UUID without dashes and use as nonce nonce = str(uuid.uuid4()) timestamp = get_current_time_ms() # milliseconds # Create the payload string in exact order required by Apple payload_components = [ self.bundle_id, # App Bundle ID self.key_id, # Key ID from App Store Connect product_id, # Product identifier offer_id, # Promotional offer identifier nonce, # UUID without dashes str(timestamp) # Current timestamp in milliseconds ] payload_str = "\u2063".join(payload_components) # Use Unicode separator logger.debug(f"Signing payload: {payload_str}") # Create SHA256 hash of the payload digest = hashes.Hash(hashes.SHA256()) digest.update(payload_str.encode('utf-8')) payload_hash = digest.finalize() # Sign the hash using ES256 (ECDSA with SHA-256) signature = self.private_key.sign( data=payload_hash, signature_algorithm=ec.ECDSA(hashes.SHA256()) ) # Encode signature in base64 signature_b64 = base64.b64encode(signature).decode('utf-8') logger.info(f"Generated signature for product {product_id} and offer {offer_id}") return { "key_id": self.key_id, # Changed to match Apple's naming "nonce": nonce, # UUID without dashes "timestamp": timestamp, # As integer "signature": signature_b64, # Base64 encoded signature "product_id": product_id, # Changed to match Apple's naming "offer_id": offer_id # Changed to match Apple's naming } except Exception as e: logger.error(f"Failed to generate signature: {str(e)}") raise HTTPException( status_code=500, detail=f"Failed to generate signature: {str(e)}" )
0
0
73
Apr ’25