IAP Sandbox Purchase Fails: The 7-Point Diagnostic Order

Sandbox IAP has seven moving parts that must line up: the device Sandbox Apple Account, region, App Store Connect agreements, product status, bundle ID, capability, and StoreKit config file. The diagnostic order, current for iOS 18+ and Xcode 16 as of June 2026.

You wire up your first in-app purchase, run the app on a real device (the simulator can’t exercise a real sandbox purchase, only a local StoreKit config file), tap Buy, and one of three things happens: the purchase sheet appears then immediately errors with “Your purchase could not be completed”; the sheet never appears and you get “Cannot connect to iTunes Store”; or Product.products(for:) returns an empty array so the paywall has nothing to show. Nothing changed in your code; the integration that worked yesterday is broken today.

Fastest fix, in order: (1) On iOS 18+, sign a Sandbox Apple Account in at Settings → Developer → Sandbox Apple Account (Developer Mode must be on). (2) Confirm your App Store Connect Paid Apps agreement, tax, and banking are all Active. (3) Confirm each IAP product is at least Ready to Submit. Roughly 80% of sandbox failures are one of those three. The rest of this page walks the full seven-point order so you can stop guessing.

Sandbox IAP has more wiring than the API surface suggests: the device’s signed-in Sandbox Apple Account, its region and password state, the App Store Connect agreements, the IAP product status, the bundle ID, the App ID capability, and any StoreKit configuration file all need to line up. When one drifts, the error message is too vague to point at the cause.

TestFlight vs sandbox vs simulator: know which environment you’re in

These three behave differently, and assuming the wrong one wastes hours:

Build sourceEnvironmentApple Account usedCan clear history?
Xcode → real deviceSandboxSandbox Apple Account you sign inYes, in App Store Connect
Xcode → simulatorLocal .storekit file onlyNone (file-driven)N/A (right-click → reset in Xcode)
TestFlightSandbox backend, real Apple IDThe tester’s normal Apple ID, no sandbox sign-inNo

The big trap: TestFlight purchases are free and run against the sandbox backend, but they use the tester’s real Apple ID, not a Sandbox Apple Account. So the “sign in a sandbox account” steps below apply to Xcode-on-device runs, not to TestFlight. (Source: Apple, Testing subscriptions and IAP in TestFlight.)

Common causes

Ordered by hit rate.

1. No Sandbox Apple Account is signed in on the device

This is the single most common cause, and Apple changed where it lives. You do not need to sign out your real Apple Account for IAP testing (that’s only required for Apple Pay). You just sign a Sandbox Apple Account into the dedicated sandbox slot:

  • iOS 18 and later: Settings → Developer → Sandbox Apple Account. Developer Mode must be enabled first (Settings → Privacy & Security → Developer Mode, then restart).
  • iOS 12 through 17: Settings → App Store, scroll to the Sandbox Account section. On these versions the section only appears after you’ve attempted a purchase once in a development-signed build.

If neither slot has a Sandbox Apple Account, iOS falls back to your real ID and the purchase fails because real IDs can’t buy sandbox products.

How to spot it: Check the path above for your iOS version. If the sandbox slot is empty or shows your real ID, this is the cause. (Source: Apple, Create a Sandbox Apple Account.)

2. App Store Connect agreements, banking, or tax info incomplete

Until the Paid Apps agreement is signed, banking and tax forms are valid, and your status is Active, no IAP product can transact, sandbox included. Apple silently drops the product from Product.products(for:) results.

How to spot it: App Store Connect → Agreements, Tax, and Banking. Look for any row in Action Items or status other than Active. Missing W-9 / W-8BEN, expired bank info, or unsigned agreement amendments all block sandbox.

3. IAP product in “Missing Metadata” or unsubmitted state

You created the product and named it, but didn’t add a localization, a review screenshot, or pricing. The product never reaches a state where StoreKit can return it. Product.products(for:) returns an empty array for that ID.

How to spot it: App Store Connect → your app → In-App Purchases. Status must be Ready to Submit or Approved. Missing Metadata means the product isn’t queryable.

4. StoreKit configuration file doesn’t match production

You added a .storekit file for local testing. Xcode is using it instead of querying App Store Connect, and the IDs in the file diverged from production. Your code thinks a product exists; the real sandbox doesn’t have it.

How to spot it: Product → Scheme → Edit Scheme → Run → Options → StoreKit Configuration. If a file is selected, StoreKit reads from there. Either set it to None or sync the file’s product IDs with App Store Connect.

5. Bundle ID mismatch between IAP and build

Your IAP products are registered under com.acme.app but the build’s bundle ID is com.acme.app.dev or com.acme.app.staging. StoreKit only returns products registered under the running bundle ID.

How to spot it: Open Info.plist and compare CFBundleIdentifier against the App ID under which your IAP products were created in App Store Connect. Any mismatch (including case) breaks the lookup.

6. Sandbox Apple Account is in the wrong region or in a stuck state

Sandbox accounts are storefront-locked. If you created the account for the US storefront but the device’s region resolves elsewhere, prices and product availability can break. Accounts can also get stuck after interrupted purchases or a long-running subscription test. Note: as of 2026 you can edit a sandbox account’s region in App Store Connect, but you cannot edit its email, name, or password after creation.

How to spot it: App Store Connect → Users and Access → Sandbox. Check the storefront/region. Try signing in via Settings → Developer → Sandbox Apple Account (iOS 18+) first; if sign-in fails there, the account itself is the problem, not your app. If it’s wedged, clear its purchase history (see “If it still fails”) or create a fresh one.

7. Capability not enabled on App ID

In Apple Developer → Certificates, Identifiers & Profiles → Identifiers → your App ID → Capabilities, In-App Purchase must be enabled. If it’s missing, the build can’t transact even though the products exist in App Store Connect. Explicit App IDs (not wildcard *) are required for IAP.

How to spot it: Apple Developer portal → your App ID → Capabilities list. If In-App Purchase is unchecked, that’s your problem.

Information to collect

  • The exact error message from the purchase prompt and from Console.app filtered to your bundle ID (look for AMSStatusCode and SKErrorDomain entries).
  • The sandbox account email and its storefront/region.
  • App Store Connect agreement / tax / banking status.
  • IAP product status (must be at least Ready to Submit).
  • Your build’s bundle ID and the App ID in the Developer Portal.
  • Whether a .storekit configuration file is selected in the run scheme.

Shortest path to fix

Step 1: Configure the device’s Sandbox Apple Account

On iOS 18+: Settings → Developer → Sandbox Apple Account → Sign In. (If Developer isn’t in Settings, enable Developer Mode at Settings → Privacy & Security → Developer Mode and restart.) On iOS 12–17 the slot is at Settings → App Store → Sandbox Account and only appears after one purchase attempt in a dev-signed build.

Create the account in App Store Connect → Users and Access → Sandbox first. Use a unique email that isn’t already an Apple Account (a +sandbox subaddress like you+sandbox@icloud.com is fine; email subaddressing is officially supported). You do not need to sign out your real Apple Account for IAP.

If you get “This Apple ID has not yet been used in the iTunes Store”, tap the prompt on the device to accept the Sandbox terms once.

Step 2: Verify App Store Connect agreements

In App Store Connect → Business → Agreements, Tax, and Banking:

  • Paid Apps agreement status must be Active.
  • Banking info: complete and not expired.
  • Tax info: complete (US developers: W-9; non-US: W-8BEN with treaty if applicable).
  • No outstanding action items in the “Action Items” panel.

Sandbox transactions fail silently when any of these are red. Fix them before debugging code.

Step 3: Verify each IAP product is ready

App Store Connect → your app → In-App Purchases. Each product needs:

  • Display Name, Description (per locale).
  • Pricing tier set.
  • Screenshot for review (any image works; doesn’t need to be the actual UI).
  • Status: Ready to Submit or Approved.

Missing Metadata products are invisible to Product.products(for:).

Step 4: Match the product IDs in code

// Hardcoded set or fetched from your server
let productIDs: Set<String> = [
    "com.acme.pro_monthly",
    "com.acme.coins_100"
]

let products = try await Product.products(for: productIDs)
print("Returned \(products.count) products of \(productIDs.count) requested")

If Returned is less than requested, list the missing IDs and check spelling against App Store Connect — com.acme.pro_monthly vs com.acme.proMonthly is a silent miss.

Step 4b: Confirm no stray .storekit file is hijacking the query

If products comes back empty even though everything in App Store Connect looks right, Xcode may be reading a local StoreKit config file instead of the real sandbox. Check Product → Scheme → Edit Scheme → Run → Options → StoreKit Configuration. For a real sandbox test this must be set to None. A selected file makes StoreKit return only that file’s products, never App Store Connect’s.

Step 5: Test directly in the build

Run your app from Xcode on a real device. Trigger the purchase flow. When iOS prompts for the Apple ID, sign in with the Sandbox Apple Account (or accept the auto-fill from Step 1).

If you see “Cannot connect to iTunes Store,” check:

  • Device network reachability.
  • Date and time set correctly (TLS cert validation depends on it).
  • VPN off (some VPNs route through regions that block sandbox).

Step 6: Validate with App Store Connect after a successful purchase

App Store Connect → Sales and Trends → Sandbox (or the Transactions view). A successful sandbox purchase appears within a few minutes. If it doesn’t, the transaction never completed on Apple’s side and your client logged a false success. With StoreKit 2, also confirm the result by reading Transaction.currentEntitlements rather than trusting the purchase callback alone.

How to confirm the fix

  • The purchase sheet appears with the correct product name and price (sandbox shows the price in the sandbox account’s storefront currency).
  • After tapping Buy and authenticating, the sheet dismisses with a green success.
  • Transaction.updates fires with a verified transaction containing the expected product ID, and that ID shows up in Transaction.currentEntitlements.
  • App Store Connect → Users and Access → Sandbox lists the purchase within a few minutes.
  • Re-running the test with the same sandbox account triggers the re-purchase flow (subscriptions auto-renew; non-consumables restore immediately).

If it still fails

  1. Clear the sandbox account’s purchase history: App Store Connect → Users and Access → Sandbox → click the account → Clear Purchase History. This resets a wedged subscription or interrupted-purchase state.
  2. Sign out and back into the Sandbox Apple Account in iOS Settings (Settings → Developer → Sandbox Apple Account on iOS 18+).
  3. Set the scheme’s StoreKit Configuration to None to force a real sandbox query (see Step 4b).
  4. Create a fresh sandbox account whose storefront matches the device’s region; old accounts can get stuck.
  5. Test with a second sandbox account to rule out a single-account issue.
  6. If the server validates receipts, point your receipt-validation call at the sandbox verify endpoint (https://sandbox.itunes.apple.com/verifyReceipt) for the legacy verifyReceipt flow, or use the App Store Server API sandbox base URL for StoreKit 2 / signed-transaction validation. A common false failure is a sandbox receipt sent to the production verify endpoint (status 21007).

Prevention

  • Set up agreements, tax, and banking before writing any IAP code; nothing downstream works without them.
  • Create one sandbox account per storefront you’ll support, with credentials stored in your team password manager.
  • Maintain a STOREKIT.md in your repo listing every product ID and where it’s defined (App Store Connect plus any .storekit file); diff it on every release.
  • Run a CI step that lists products via Product.products(for:) against the sandbox and fails if any expected ID is missing.
  • Test purchases on a real device before each release; sandbox state drifts and silent failures surface earlier this way.

FAQ

Do I have to sign out my real Apple ID to test IAP? No. For in-app purchases you sign a Sandbox Apple Account into the dedicated sandbox slot (Settings → Developer → Sandbox Apple Account on iOS 18+) and leave your real account alone. Signing out the device Apple Account is only required for Apple Pay sandbox testing.

Why does Product.products(for:) return an empty array? Three usual reasons, in order: the product isn’t Ready to Submit yet (it’s stuck in Missing Metadata), the Paid Apps agreement / tax / banking isn’t Active, or a product ID typo (pro_monthly vs proMonthly). A selected .storekit config file in the scheme also hides App Store Connect products.

Does TestFlight use sandbox testers? No. TestFlight runs against the sandbox backend but uses the tester’s real Apple ID, with no charge. Don’t sign a Sandbox Apple Account in for TestFlight, and note you can’t clear TestFlight purchase history the way you can for a sandbox account.

My code reports success but App Store Connect shows no transaction — what happened? The client trusted a callback that didn’t reflect a completed server-side purchase. With StoreKit 2, verify against Transaction.currentEntitlements and check Sandbox Transactions in App Store Connect. If a server validates receipts, status 21007 means a sandbox receipt was sent to the production verify endpoint.

Can I test sandbox purchases in the iOS Simulator? Not against the real sandbox. The simulator can only use a local .storekit configuration file. Anything touching Apple’s sandbox servers (the Sandbox Apple Account flow, real transactions, App Store Connect logging) needs a real device with Developer Mode on.

How fast do sandbox subscriptions renew? Much faster than production, so a long period compresses to minutes. By default a 1-month subscription renews about every 5 minutes in sandbox, and auto-renew stops after 12 renewals. You can adjust the renewal rate per account in App Store Connect → Users and Access → Sandbox.

Tags: #Troubleshooting #App Store #App review #IAP sandbox #IAP