ADR 0007 — iOS subscription billing: Apple In-App Purchase
Status: Accepted (user decision 2026-04-22)
Date: 2026-04-22
Deciders: software-architect + user
Scope: How paid subscriptions are sold to users of the Raxx iOS app
Context
Raxx's subscription tiers (Free / Pro / Pro+) are sold on the web via Stripe at raxx.app/pricing. The iOS companion app needs a billing posture: how do iOS users become paying subscribers?
Three options exist:
Apple In-App Purchase (IAP) via StoreKit 2 — in-app subscription flow, Apple handles checkout, receipt, renewals, refunds. Apple takes 15% (Small Business Program, <$1M annual net revenue) or 30% (above).
External link-out to raxx.app/pricing — post-Epic v Apple (US, 2024+), apps may present a URL that leaves the app for web purchase. Requires Apple's external-purchase disclosure sheet. 0% Apple cut. Some user drop-off. EU and other regions have different rules.
Web-only signup — iOS app requires an existing web-sourced subscription; no billing UI in the app at all. 0% Apple cut. Highest friction.
Decision
Adopt Apple IAP (StoreKit 2) for iOS subscriptions.
User's stated rationale: "fine using in-app. I like the security and control point for our users. No games."
Interpretation: Raxx values the native Apple subscription-management experience (single place to cancel, Apple-vetted payment, transparent pricing in Settings > Subscriptions) over the 15% margin hit. The "no games" comment rejects the link-out gymnastics and the adversarial relationship with Apple that comes with it.
Consequences
Positive
User trust. Native Apple subscription management is the gold standard on iOS — users can see, pause, cancel in Settings without needing to know where Raxx is. Cancellation friction is a retention positive, not a business negative.
App Store review path is clean. No external-purchase disclosure sheet, no guideline 3.1.1 tension, no need to defend a link-out decision to a reviewer.
Family Sharing is native. StoreKit 2 subscriptions can optionally participate in Family Sharing with a single API flag.
Refund handling is Apple's problem. Disputes and refunds go through Apple, not Raxx support.
Negative / costs
15% of iOS subscription revenue (30% if we clear $1M/year). At $29/mo Pro × 1000 iOS subs × 12 months = $348k gross, Apple cut $52k first year. Real money.
Separate backend subscription-state path. Raptor needs:
/api/subscriptions/apple/notifications — Apple's server-to-server subscription state notifications (v2)
subscription_source column on users or a separate subscriptions table — "web" (Stripe) vs "ios" (Apple) vs "android" (Google Play future)
Receipt-validation logic calling Apple's App Store Server API for initial transaction
Grace-period handling for billing retries
Handling same-user-dual-subscription edge case (user subscribes on web AND iOS — refuse second, refund, or sync)
Pricing ladder must use Apple's tier system. $29/mo → tier 29 ($29.99) or manually price at a different nearest tier. Need to accept $29.99 vs $29 parity drift or adjust web to match.
StoreKit 2 requires Swift + iOS 15+. iOS 15 floor matches the existing iOS 16 floor decision in ADR 0004.
Neutral
User cannot upgrade from Pro to Pro+ cross-platform without handling the billing provider switch. Apple allows same-group upgrades within IAP; web-sourced upgrades happen on web. Cross-billing upgrades are explicitly not supported in v1.
Alternatives considered
External link-out (rejected)
Post-Epic v Apple, US apps may link externally. But:
- User explicitly said "no games" — rejecting the adversarial posture
- Disclosure sheet creates friction at the worst moment (conversion)
- EU / Asia / rest-of-world rules still vary; global compliance is a maintenance tax
- Apple's external-purchase commission (27% — only 3% less than IAP) in some jurisdictions eliminates the margin benefit
Web-only signup (rejected)
Highest friction for iOS-first users who want to try Raxx natively
User explicitly rejected this implicitly by choosing IAP
Forces a web detour for every new iOS signup — hurts first-touch conversion
Compliance checklist
[ ] App Store Connect: declare subscription group, auto-renewable subscription products for each tier
[ ] App Store Connect: configure introductory offer if Founders promo extends to iOS