iOS IAP E2E — on-device runbook
Card: #3688
Owner: operator (on-device taps) + ios-agent (prep)
Time: ~20 minutes (5 per step; sandbox renewals are ~5 min each)
Companion: docs/ops/runbooks/apple-iap-sandbox-e2e.md (full server-side E2E)
This document covers the on-device client-side steps only. Server-side notification verification (sub-cards #3685–#3687) is a separate gate.
Before you start — 5-minute setup
1. Get sandbox tester credentials from vault:
- Path: /Raxx/iOS/Sandbox/
- Keys: IAP_TESTER_FRESH_EMAIL / IAP_TESTER_FRESH_PASSWORD (for Pro test)
- Keys: IAP_TESTER_PROPLUS_EMAIL / IAP_TESTER_PROPLUS_PASSWORD (for Founders intro test)
- These accounts must already be created + email-verified in ASC. If not, do §2 of
ios-iap-sandbox-testing.md first (5 minutes in ASC dashboard, requires 2FA).
2. Disable the local StoreKit config in the scheme:
- Xcode: Product → Scheme → Edit Scheme → Run → Options
- Set StoreKit Configuration to None
- With None, the app hits the real Apple sandbox instead of the local mock file.
3. Build and install on your iPhone: - Select your iPhone in the Xcode device dropdown - Cmd+R — builds and installs in ~30 seconds - If you are using the existing TestFlight Wave 2 build (#891), you can skip the Xcode build step, but the StoreKit config must be None (TestFlight builds always hit the live sandbox — the local config file is inactive in distribution builds).
Step 1 — Sign in with sandbox tester (not your real Apple ID)
When the payment sheet appears, Apple prompts for Apple ID. You do NOT need to sign out of your system-level Apple ID beforehand. The sandbox tester sign-in is scoped to the in-app payment sheet only.
Sign in to Raxx with the operator passkey first, then proceed to the paywall.
Success: Raxx home screen loads normally. No purchase yet.
Step 2 — Open the paywall and confirm both products appear
Navigate: Dashboard → tap your plan section → Billing (or however the nav is wired in the build you're running).
Success: You see two subscription cards: - Raxx Pro — $39.00/month - A Founders card OR Raxx Pro+ — $79.00/month
If the Founders intro offer is configured in ASC, the Pro+ card shows: "$29.00/month for your first 6 months, then $79.00/month"
If it shows $79.00/month flat (no intro card), the Founders intro offer has not yet been configured in ASC — that is a known pending step and does not block the Pro purchase test.
If both cards are missing (blank screen), the ASC product records are not resolving.
Confirm the StoreKit config is None, the device has network, and the product IDs in
StoreKitManager.swift match the ASC records exactly:
- app.raxx.ios.pro.monthly (ASC ID 6781305735)
- app.raxx.ios.proplus.monthly (ASC ID 6781305906)
Success: At least the Pro card is visible with a price.
Step 3 — Purchase Pro
- Tap Subscribe on the Raxx Pro card.
- Apple's payment sheet appears. Header shows [Environment: Sandbox] — confirms sandbox.
- Enter sandbox tester credentials from vault (
IAP_TESTER_FRESH_EMAIL/IAP_TESTER_FRESH_PASSWORD). - Confirm the purchase. No real charge occurs.
Success signals:
- The payment sheet dismisses without an error.
- Raxx returns to the billing screen (or navigates away if entitlement changes the UI).
- In Xcode console (Window → Devices and Simulators → your device → Open Console),
you see a StoreKit log entry with transactionID — confirms the transaction was verified.
- No [StoreKit] unverified transaction error in the console.
Step 4 — Confirm entitlement unlocks
After the purchase completes, confirm the app recognizes the subscription:
- Navigate back to the billing screen (or restart the app and navigate there).
- The billing screen should reflect an active subscription state.
- If the UI gates content by entitlement, that content should now be accessible.
-
StoreKitManager.currentEntitlements()returns{"app.raxx.ios.pro.monthly"}— you can verify this via the Xcode console log or by observing the UI gate behavior.
If the billing UI stub (Restore purchases is not yet wired per ios-iap-sandbox-testing.md §0),
confirm via Xcode's Debug → StoreKit → Manage Transactions (with device connected):
you should see the sandbox transaction for app.raxx.ios.pro.monthly.
Success: The sandbox transaction appears in Xcode's StoreKit manager, OR the app surfaces an entitlement-aware UI change, OR the Xcode console logs receipt of the transaction without an error.
Step 5 — Test restore purchases
- Sign out of Raxx (Settings → Sign Out, or delete and reinstall the app).
- Sign back in with the operator passkey.
- Navigate to the billing screen.
- If a "Restore Purchases" button exists: tap it. The app calls
StoreKitManager.currentEntitlements()and should find the prior sandbox transaction. - If no "Restore Purchases" button yet (it is a known stub): on a real device with the
StoreKit config
None, StoreKit will restore prior sandbox transactions automatically on the nextcurrentEntitlements()call fromBillingViewModel. Navigate to the billing screen and observe that the subscription state is restored without tapping anything.
Success: The prior Pro subscription is recognized after sign-out/sign-in. No duplicate purchase prompt appears. The entitlement is restored without paying again.
Step 6 — Test Founders intro price path
Prerequisite: The Founders introductory offer must be configured in ASC on
app.raxx.ios.proplus.monthly before this step is testable on device. If it is not yet
configured, this step is blocked (note it in your #3688 comment and skip to done).
If configured:
- Use a FRESH sandbox tester account with no prior Pro+ purchase history.
Sign into the device using
IAP_TESTER_PROPLUS_EMAIL/IAP_TESTER_PROPLUS_PASSWORDfrom vault when the payment sheet prompts. - Or clear purchase history in ASC for the Fresh tester: ASC → Sandbox → Testers → iap-test-fresh@raxx.app → Manage → Clear Purchase History. - Navigate to the billing screen.
- The Pro+ card should show: "$29.00/month for your first 6 months, then $79.00/month"
(the Founders intro card, rendered by
BillingView.foundersCard). - Tap Subscribe on the Founders card.
- Apple's payment sheet shows the $29.00/month price (not $79.00).
- Complete the purchase with sandbox tester credentials.
Success: - The payment sheet showed $29.00/month (the introductory price). - The sandbox transaction resolves correctly. - No error in the Xcode console. - After the sandbox intro period expires (~30 minutes for a 6-month intro compressed to sandbox cadence), a renewal notification would fire at $79.00/month — you do not need to wait for this in the #3688 E2E; confirming the intro price on the payment sheet is sufficient.
Done — what to report on #3688
Post a comment on issue #3688 with:
On-device E2E complete (2026-07-13)
Step 1 — Sandbox tester sign-in: [pass/blocked — note if account not yet created]
Step 2 — Paywall products visible: [pass/fail — note which products appeared]
Step 3 — Pro purchase: [pass/fail]
Step 4 — Entitlement recognized: [pass/fail]
Step 5 — Restore: [pass/fail/stub not wired]
Step 6 — Founders intro price: [pass/blocked — note if ASC intro offer not configured]
Build: [Xcode USB / TestFlight Wave 2 #891]
Device: [iPhone model, iOS version]
StoreKit env: Sandbox (None in scheme)
Server-side E2E (Steps 0–8 in apple-iap-sandbox-e2e.md) remains open pending sub-cards #3685/#3686/#3687.
Quick troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Billing screen is blank (no products) | StoreKit config is still set to .storekit file (Simulator mode) |
Edit Scheme → Run → Options → StoreKit Configuration → None |
| Payment sheet shows real Apple ID, no sandbox badge | Logged in with personal Apple ID on device | Enter sandbox tester email when the sheet prompts (do not use personal Apple ID) |
| "Unable to complete the purchase" error | Product not yet resolvable from ASC (prices not set, or product not yet saved in ASC) | Confirm price is set in ASC; check console for StoreKit error code |
| Founders intro card does not appear | Intro offer not configured in ASC | Configure Pay As You Go offer in ASC (see §0 of ios-iap-sandbox-testing.md); works in Simulator via .storekit file without ASC config |
| Xcode "unverified transaction" log | JWS verification failed in the StoreKit layer | Rare in sandbox; try clearing purchase history and repurchasing |
| Payment sheet does not appear at all | Xcode Run config still points to .storekit file | Confirm StoreKit Configuration = None in Edit Scheme → Run → Options |