Mobile Subscriptions Are a State Problem, Not a UI Problem
- Mobile
- Payments
- Subscriptions
Designing as though your database is authoritative produces users who paid and cannot access what they bought.

Subscription billing on mobile looks like a UI problem and is actually a state-reconciliation problem. The screen with the prices is the easy part. What costs teams weeks is everything that happens after someone taps buy.
The platform is the source of truth, not your database
A user's entitlement lives with the store, and your backend holds a cached opinion about it. Subscriptions renew, lapse, get refunded, get upgraded, get restored on a new device, and get cancelled through a settings screen your app never sees.
Designing as though your database is authoritative produces the classic bugs: users who paid and cannot access what they bought, and users who stopped paying and still can.
Validate receipts server-side
Client-side validation is trivially bypassed. The client should report a purchase; the server should verify it with the platform and record the entitlement. Every access check then reads your verified record, not the device's claim.
This also gives you a single place to handle the awkward cases, rather than scattering them across two mobile codebases.
Restore is not optional
Users change phones, reinstall, and sign in on a second device. A clear, discoverable restore path is both a store requirement and the thing that prevents your most common support ticket.
Test it properly: new device, existing subscription, signed in with the same account — and separately, signed in with a different account to the one that purchased.
Handle the states that are not "active"
A subscription is not binary. At minimum you will encounter:
- In trial, which may convert or may not.
- In grace period after a failed payment, where access should usually continue while the platform retries.
- Billing retry, where it may recover.
- Cancelled but not expired — paid through a date, with no renewal coming.
- Expired.
- Refunded, which can arrive long after the fact.
Each needs a decision about access and about messaging. Treating anything other than "active" as "expired" cancels people who are mid-recovery and generates angry reviews.
Listen for server notifications
Both platforms will tell your server about renewals, cancellations, refunds and billing problems. Consuming those is how your entitlement record stays accurate between app launches. Polling, or relying on the app to tell you, means your data is stale exactly when it matters.
Pricing and presentation
Fetch prices from the store rather than hard-coding them. They are localised, they change, and a mismatch between your displayed price and the purchase sheet is both a conversion problem and a compliance one.
Show the terms plainly: what renews, when, at what price, and how to cancel. Obscuring this converts slightly better and generates refunds, chargebacks and store scrutiny.
Test with sandbox accounts, then test with real money
Sandbox behaviour differs from production in ways that matter — accelerated renewal cycles, different notification timing. Run at least one real purchase and one real cancellation through the live system before launch.
Consider not building it yourself
A subscription infrastructure service costs a percentage of revenue and removes weeks of work plus an ongoing maintenance burden across two platforms. For most teams that is a good trade, at least until the percentage becomes large enough to justify bringing it in-house.