The documentation mentions the following:
Verify your receipt first with the production URL; then verify with the sandbox URL if you receive a 21007 status code. This approach ensures you don’t have to switch between URLs while your app is in testing, in review by App Review, or live in the App Store.
This way, you can use one server environment to handle both Sandbox and Production environments. It is necessary to pass App Review.
However, I'm not manually hitting these URLs - I'm using Apple's libraries.
Specifically, the environment is used in SignedDataVerifier and AppStoreServerAPIClient.
(I can't link to these because, for some reason, the domain apple.github.io is not allowed. The documentation for these is only found there. You can find it quickly by searching these terms and the domain.)
Here is how SignedDataVerifier is being used:
const verifier = new SignedDataVerifier(
appleRootCertificates,
APPLE_ENABLE_ONLINE_CHECKS,
APPLE_ENVIRONMENT,
APPLE_BUNDLE_ID,
APPLE_APP_ID
)
const verifiedNotification: ResponseBodyV2DecodedPayload = await verifier.verifyAndDecodeNotification(signedPayload)
if (!verifiedNotification)
{
// Failure
return
}
Here is how AppStoreServerAPIClient is being used:
const appStoreServerAPIClient = new AppStoreServerAPIClient(
SIGNING_KEY,
APPLE_IAP_KEY_ID,
APPLE_IAP_ISSUER_ID,
APPLE_BUNDLE_ID,
APPLE_ENVIRONMENT
)
const statusResponse: StatusResponse = await appStoreServerAPIClient.getAllSubscriptionStatuses(originalTransactionId, [Status.ACTIVE])
In the source code for SignedDataVerifier.verifyAndDecodeNotification, I can see that it throws a VerificationException(VerificationStatus.INVALID_ENVIRONMENT) error .
So for SignedDataVerifier is it as simple as wrapping my code in a try/catch and checking that the error's status code is 21007? I'm unsure about this because if you scroll to the bottom of the linked source code file, you can see the enumeration VerificationStatus, but it's unclear if this member has a value of 21007.
The source code for AppStoreServerAPIClient only says that it throws an APIException if a response could not be processed, so I'm not too sure about how to handle this one.
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
I'm running into a refund issue when testing in-app purchases in sandbox mode. I'm able to successfully purchase items but roughly 1 out of 3 times, when the refund window pops up, it says it cannot connect even though our webhook servers can verify the transaction id sent from apple. My internet connection is good and I've varied the wait period from purchase to refund from 15mins to 2 hours. Any help would be greatly appreciated.
Topic:
App & System Services
SubTopic:
StoreKit
Hi All
i have developed an app but when I go to download the paywall appears as it’s subscription only but it shows no prices for the subscription I get an endless swirl.
I checked the product id etc and it’s correct but the subcription on my App Store Connect shows as approved. is there another status it needs to reach before it becomes like like ready for sale?
https://apps.apple.com/gb/app/gameaware-pro/id6751592563
Hello!
We are implementing consumable IAP for iOS using StoreKit 2 together with our own server backend.
Our happy path looks like this:
1. Call /prepare on our server
• We only allow one purchase at a time, so this fails if a pending transaction already exists.
2. Call /purchase via StoreKit
3. If successful, call /complete on our server
4. Call .finish() on the Transaction
⸻
The Problem
Some users report being charged by Apple but not receiving coins.
I suspect this happens in rare cases where the purchase flow throws an exception:
• Every time we throw, we immediately cancel the transaction on our server.
• However, some errors may actually be temporary. StoreKit seems to recover by later sending an update through Transactions.updates.
• When that happens, since the transaction was already canceled on our server, we cannot match it. As a result, we just call .finish() without granting consumables.
⸻
Additional Observations
From user logs, the issue tends to appear when the following errors are reported:
• リクエストを完了できません。
• Triggered by: StoreKit.notEntitled
• Triggered by: StoreKit.unknown
• ヘルパーアプリケーションと通信できませんでした。
I was not able to reproduce the last one, even when testing all possible StoreKit configuration errors. Some sources suggest this may be a rare case where the app cannot communicate with the App Store itself.
Additionally, affected users often seem to be using non-standard payment methods (PayPay, gift cards, carrier billing, etc.) rather than credit cards.
⸻
My Question
What is the best practice for handling StoreKitError and PurchaseError?
Specifically:
• Should some of these errors be treated as temporary instead of final?
• How should we ensure users always receive their consumables in such cases?
⸻
Code
do {
let result = try await wrapper.product.purchase()
switch result {
case .success(let result):
let transaction = try StoreKitVerifier.checkVerified(result)
let iOSPurchase = IOSPurchase(transaction: transaction, jws: result.jwsRepresentation)
return .Success(purchase: iOSPurchase)
case .userCancelled:
return .Canceled()
case .pending:
return .Pending()
@unknown default:
return .Error(
message: "Purchase result doesn't match with anything. This must not be executed")
}
} catch {
return .Error(message: error.localizedDescription)
}
I use [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]. Works on my App which is in the store (compiled pre-iOS 26).
If I compile the same App now, same codebase with Xcode Version 26.0, restore does not work. Nothing happens. Tested on real device (iOS 26).
Documentation says its deprecated, but my deployment target is iOS 12.
Anyone has similar issues? Any recommendations?
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
login sandbox account at setting > app store > sandbox account.
download my app from testflight
purchase subscription is fine.
stop renew subscription.
after subscription expired, delete app, then download from testflight again.
tried to restore purchase, the result count always zero
We’ve been approved for the Advanced Commerce API and are setting up the generic product identifiers per the guide:
https://developer.apple.com/documentation/advancedcommerceapi/setting-up-your-project-for-advanced-commerce#Set-up-generic-product-identifiers
We have multiple auto-renewable subscriptions (for simplicity: Product 1, Product 2, etc.). We created a new subscription group for Advanced Commerce and are about to add the subscription(s) inside that group.
Should we create one auto-renewable subscription (generic, e.g. subscription.ac) to represent all of our subscriptions, or one generic per product family (e.g., product1.ac, product2.ac, …)? If the answer depends on whether subscribers can hold multiple products simultaneously, please advise which structure supports that (e.g., separate groups).
Reporting identifiers / segmentation: In Sales and Trends and Payments & Financial Reports, which identifier(s) will appear after migration: the legacy StoreKit product_id, the new generic product id, and/or the SKU? If we use a single generic subscription for all products, what’s Apple’s recommended way to segment revenue by product (Product 1 vs. Product 2)? If SKUs don’t surface in these reports, should we prefer multiple generics/groups to preserve report-level segmentation?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
In-App Purchase
Advanced Commerce API
Hello Developer support, In one of our live application we have seen that users are purchasing weekly subscription and automatically they shifted to yearly product. Due to this we have received high revenue and also refunds afterwards. To prevent this we removed our yearly product from the sale. In App Store Connect we have seen activations for weekly product and convert to standard prices are yearly products. Also we have seen weird behavior of user getting trial for same product for three times. For developer support people I am sharing my app id - 1320373866 , and here is the video of our issue - https://drive.google.com/file/d/1DBHw8ivgql4eNoo8NC3xo5v4wgr8Oh7x/view?usp=sharing , Also attaching trial behavior screenshot.
After game restart first purchase is contained in receipt but the next ones is the same as first one so new purchases is not added. I afraid players can be charged for purchase but on my server I will not receive new purchases instead receipt with old one so they can do not receive in game currency. Will in production I receive a receipts with new consumable every time player purchase it? I use Unity3d In-app purchasing 5.0.1.
Topic:
App & System Services
SubTopic:
StoreKit
Problem Summary
Apple's provisioning servers are not generating the com.apple.developer.storekit entitlement for App ID com.driftnotes.app (Team ID: 43Y6AG5NPY), making it impossible to build iOS apps for physical devices despite all configurations being correct.
Environment
macOS: 15.3.1 (24D70)
Xcode: 16.1 (xcode-select version 2409)
Flutter: 3.35.2 • channel stable
Account: Individual Developer (Kazakhstan)
Bundle ID: com.driftnotes.app
Team ID: 43Y6AG5NPY
Error Message
Error (Xcode): Provisioning profile "iOS Team Provisioning Profile: com.driftnotes.app" doesn't include the com.apple.developer.storekit entitlement.
/Users/vyacheslavkuzin/Desktop/FlutterProjects/DriftNotesDart/ios/Runner.xcodeproj
Steps to Reproduce
Configure App ID with In-App Purchase capability (✅ verified in Developer Portal)
Add In-App Purchase capability in Xcode project (✅ done)
Configure entitlements file with StoreKit keys (✅ done)
Enable automatic signing in Xcode (✅ done)
Run: flutter build ios --release
Build completes successfully ("Xcode build done. 13,8s") but fails at signing stage
Expected vs Actual Result
Expected: Provisioning profile should include com.apple.developer.storekit entitlement
Actual: Profile is created WITHOUT the entitlement, despite all configurations being correct
Configuration Details
Developer Portal
App ID com.driftnotes.app has In-App Purchase capability enabled ✅
All agreements are active in App Store Connect ✅
Xcode Project
In-App Purchase capability added via Signing & Capabilities ✅
Automatically manage signing: Enabled ✅
Team: 43Y6AG5NPY (Vyacheslav Kuzin) ✅
Entitlements File (ios/Runner/Runner.entitlements)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.in-app-payments</key>
<array>
<string>merchant.com.driftnotes.app</string>
</array>
<key>com.apple.developer.storekit</key>
<true/>
</dict>
</plist>
Build Settings
CODE_SIGN_ENTITLEMENTS: Runner/Runner.entitlements ✅
PRODUCT_BUNDLE_IDENTIFIER: com.driftnotes.app ✅
DEVELOPMENT_TEAM: 43Y6AG5NPY ✅
Troubleshooting Attempted
Multiple Attempts
Profile Recreation: Manual and automatic profiles recreated dozens of times
Cache Cleanup: Complete removal of:
~/Library/Developer/Xcode/DerivedData/*
~/Library/MobileDevice/Provisioning\ Profiles/*
Flutter clean & pod cache clean
Signing Methods: Tested both manual and automatic signing management
Wait Periods: 48+ hours for server propagation
Complete Profile Deletion: Removed ALL profiles from Developer account per Apple Support
Apple Support Workaround
Following Senior Advisor recommendation:
✅ Deleted all provisioning profiles from account
✅ Confirmed IAP capability in project
✅ Created StoreKit Configuration File for testing
✅ Verified automatic signing management
✅ Multiple "Try Again" attempts in Xcode
Result: Problem persists
Apple Support Reference
Case #102680105923 - Senior Advisor Simone confirmed after internal team consultation that this requires engineering team attention and directed to Developer Forums.
Technical Analysis
What Works
Flutter build completes successfully
Pod install executes without issues (25,9s)
Xcode build finishes successfully (13,8s)
All dependencies resolve correctly
What Fails
Provisioning profile generation: Server creates profile but omits StoreKit entitlement
All profile types affected: Both manual and automatic profiles
Consistent across configurations: Debug, Release, Profile all fail identically
Root Cause
This appears to be a server-side bug where Apple's provisioning systems are not properly correlating the App ID's In-App Purchase capability with the StoreKit entitlement generation for this specific App ID (com.driftnotes.app).
The issue is NOT in client-side configuration - all settings match Apple's official documentation exactly. The problem occurs during the server-side provisioning profile generation process.
Request for Engineering Team
This issue requires attention from Apple's provisioning infrastructure team to resolve the server-side entitlement generation bug for App ID com.driftnotes.app.
Impact
Critical: Complete inability to build iOS app for physical devices
Business: Blocking app deployment and updates
Developer Experience: Extensive time spent on troubleshooting correctly configured setup
All configurations have been verified multiple times and match Apple's official documentation. The issue has been escalated through Apple Support (Case #102680105923) and requires engineering team intervention.
Topic:
App & System Services
SubTopic:
StoreKit
Hi,
We have a app with some auto-renewing subscription in a group of subscriptions.
When a user upgrade from a subscription to another, the "user receive a refund of the prorated amount of their original subscription" (https://developer.apple.com/app-store/subscriptions/).
How is the prorated calculated ?
Example : subscription to 14,99$ / month. If subscriber upgrade after 10 days, is the refund calculated 10/30 of 14,99$ (so ~5$) ?
Hi everyone,
I’ve been receiving App Store Server Notifications (webhooks) normally for a specific transaction. Everything was working fine — I could use the original_transaction_id to query transaction history, and transaction_id to look up specific transactions.
However, starting recently, all API calls for that transaction (both Get Transaction Info and Get Transaction History) now return not found.
• The webhooks used to arrive normally for this transaction.
• I am sure I’m querying the correct environment (production vs sandbox).
• The IDs I’m using are exactly the ones from the last webhook payload.
• I haven’t changed my integration code.
My questions:
1. Under what conditions does Apple’s API return “not found” for original_transaction_id that previously worked?
2. Can Apple actually purge transaction records (in production)?
3. Could this happen due to refunds, revocations, or other account actions?
4. Is this expected behavior, or should I file a DTS (Technical Support Incident)?
Any insight would be appreciated.
Thanks in advance!
I encountered the following issues while developing in-app purchases; please help me:
When attempting to purchase a product that has already been purchased, SKPaymentQueue reports an error instead of a success message:
<SKPaymentQueue: 0x134665380>: Payment completed with error: Error Domain=ASDServerErrorDomain Code=3532 "You’re currently subscribed to this." UserInfo={NSLocalizedFailureReason=You’re currently subscribed to this., client-environment-type=Sandbox, AMSServerErrorCode=3532, storefront-country-code=USA}
After buying product A on one iPhone using a sandbox account, restoring purchases on another iPhone with the same sandbox account via paymentQueue.restoreCompletedTransactions(withApplicationUsername:) does not return the previously purchased product A data; it directly calls restoreCompletedTransactionsFinished.
Topic:
App & System Services
SubTopic:
StoreKit
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
For years I've been using Receigen for receipt verification for the Mac App Store build of my application. However, with the deprecation of exit code 173, I am moving to StoreKit-based verification and have a couple of questions.
I have followed the instructions from https://developer.apple.com/documentation/storekit/apptransaction/shared and have something like this (simplified):
Swift:
@objc class ValidateReceipt: NSObject {
@objc func validate() async -> Bool {
do {
let verificationResult = try await AppTransaction.shared
switch verificationResult {
case .verified(_ /*let appTransaction*/):
// StoreKit verified that the user purchased this app and
// the properties in the AppTransaction instance
return true;
default:
// The app transaction didn't pass StoreKit's verification
return false;
}
}
catch {
// Handle errors
return false;
}
}
}
Objective-C:
ValidateReceipt *validateReceipt = [[ValidateReceipt alloc] init];
[validateReceipt validateWithCompletionHandler:^(BOOL result) {
if (result)
{
// Successful app purchase validation
}
else
{
// App purchase validation failure
}
}];
Thing is, I always get a valid result, i.e., in ValidReceipt.validate(), the case .verified block always runs. Even when exporting a new release build of my app and running it (without any _MASReceipt).
When using exit code 173, an .app without a _MASReceipt would prompt for app store login. Nothing of the sort happens now.
Am I misunderstanding the documentation / doing something wrong / missing something obvious?
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
I would like to know if it is allowed to offer the user to either unlock the app immediately or partake in a 3-day trial period before making a purchase.
I created 2 IAP non-consumable products; 1 for the immediate [which is at a discount] and for the after trial period ends [this is at a higher cost].
Is this something that Apple allows or is frowned upon?
Our app cannot retrieve in-app purchase products from the App Store. We're getting a "storekit_no_response" error when attempting to fetch product information, despite having all products properly configured in App Store Connect.
Error: IAPError(code: storekit_no_response, source: app_store, message: StoreKit: Failed to get response from platform., details: null)
Verified product IDs match exactly what's in App Store Connect
Confirmed we're using a Sandbox Test Account
Checked that In-App Purchase capability is enabled
Waited over 24 hours for product availability
Tried multiple product ID formats
This issue is preventing us from implementing subscription functionality in our app. We need assistance determining why StoreKit isn't responding to our product queries.
Thank you for your help.
Topic:
App & System Services
SubTopic:
StoreKit
I want to test the "Remove from Sale" scenario in Sandbox. I set my subscription to "Remove from Sale" for all territories in App Store Connect, but I can still make new purchases and auto-renewals continue in the Sandbox environment.
Is this a known limitation? Or is there a specific way to make this work for testing?
If it can't be tested, I'd like to know the expected production behavior. What changes occur in the App Receipt and what App Store Server Notification is sent?