In-App Subscription Infrastructure
How we manage premium subscriptions across iOS and Android with a unified backend — cross-platform management, receipt validation, and churn tracking.

The traveler subscribed on their iPhone. Now they want to use the premium features on the web. Their subscription was purchased through the iOS App Store, managed by Apple's billing system, and their account on our backend has no record of a payment because the money went through Apple, not through us. Cross-platform subscription management is a problem that looks simple until you actually build it.
Mobile app subscriptions involve at least three parties: the app store (Apple or Google), a subscription management layer, and your backend. Each has its own state, its own event system, and its own opinion about whether the user is currently subscribed. Keeping these synchronized is the core infrastructure challenge.
Cross-platform subscription management

iOS and Android have different billing systems. The App Store and Google Play each have their own APIs, their own receipt formats, their own webhook events, and their own refund processes. Building a subscription system that works across both platforms means either writing two complete integrations or using a management layer that abstracts the differences.
We use a subscription management service that sits between the app stores and our backend. The mobile app communicates with this service to initiate purchases, restore previous purchases, and check current entitlements. The service handles the platform-specific details: App Store receipt validation, Google Play purchase verification, subscription state management, and cross-platform identity mapping.
The subscription provider wraps the entire app, making subscription state available to every screen. Any component can check whether the current user has an active premium subscription by calling a hook. The hook returns the current entitlement state: free tier, premium monthly, or premium annual.
This abstraction means the app's business logic never deals with App Store or Google Play directly. It asks "does this user have premium?" and gets a boolean. The complexity of receipt formats, billing retry, and cross-platform syncing is hidden behind that boolean.
Receipt validation and entitlement checking
When a traveler purchases a subscription, the app store sends a receipt to the app. The app forwards this receipt to the subscription management service for validation. Validation confirms that the receipt is genuine (not forged), that the purchase is active (not refunded), and that it belongs to the claimed user.
This validation happens server-side. Never validate receipts on the client. A malicious client can forge receipts or replay old receipts. Server-side validation against the app store's verification API is the only trustworthy path.
After validation, the management service updates the traveler's entitlement state and notifies our backend via webhook. The backend records the subscription status in the user's profile, which gates access to premium features: higher rate limits on chat messages, access to premium AI model quality, additional document storage, and priority support.
The entitlement check happens on every API request that involves a premium feature. The middleware checks the user's subscription status before processing the request. If the subscription has expired (the management service's webhook updated the status), the middleware returns a clear error code that the client handles by showing an upgrade prompt.
Grace periods and billing retry

Subscriptions don't just have two states (active and expired). They have a nuanced lifecycle with intermediate states that the infrastructure must handle.
Active. The subscription is paid and current. Full access to premium features.
Grace period. The subscription renewal failed (expired card, insufficient funds), but the app store is retrying the charge. During the grace period (typically 16 days on iOS, up to 30 days on Google Play), the traveler keeps premium access. The idea is that most billing failures are temporary and resolve themselves when the card is updated or funds become available.
Billing retry. The app store is actively retrying the charge. The traveler might see a notification from the app store to update their payment method. The subscription management service tracks the retry state and keeps our backend informed.
Expired. All billing retries failed. The subscription is no longer active. Premium features are revoked. The traveler sees free-tier limitations and an upgrade prompt.
Paused. Some platforms allow subscribers to pause their subscription. The traveler isn't charged during the pause, and premium features are suspended.
Our backend handles all of these states. The webhook from the subscription management service fires on every state transition, and our backend updates the user's access accordingly. The transition from active to grace period doesn't revoke access (we don't want to punish the traveler for a temporary billing issue). The transition from grace period to expired does.
Subscription analytics and churn tracking
Understanding subscription health requires tracking more than just active subscriber count. We track several metrics that reveal the health and trajectory of the subscription business.
Monthly churn rate. What percentage of subscribers cancel or let their subscription expire each month. A spike in churn indicates a product or pricing problem.
Trial conversion rate. Of travelers who start a free trial, what percentage convert to a paid subscription. Low conversion suggests the premium value proposition isn't compelling enough or that the trial period doesn't showcase the right features.
Renewal rate. Of subscribers whose subscription comes up for renewal, what percentage successfully renew. The gap between renewal rate and 100% is involuntary churn (billing failures) plus voluntary churn (cancellations).
Revenue per subscriber. Average revenue per active subscriber per month. This varies by plan (monthly vs. annual) and by platform (App Store takes a different commission than Google Play).
The subscription management service provides most of these metrics natively. We supplement them with our own analytics that correlate subscription events with product usage. Do subscribers who use the AI chat frequently have lower churn? Do subscribers who book through the platform renew at higher rates? These correlations inform product decisions about which features to improve and which to gate behind premium.
Backend integration for subscription-gated features
The subscription state influences the backend's behavior in several places.
Rate limiting adjusts based on subscription tier. Free-tier travelers have a lower message-per-minute limit on the AI chat. Premium travelers get a higher limit. The rate limiter checks the subscription status on every request and applies the appropriate threshold.
AI model routing can vary by tier. Premium subscribers might get routed to more capable (and more expensive) models for complex queries. Free-tier users get the standard model. This is a cost management strategy: the premium subscription revenue subsidizes the higher inference cost.
Document storage limits differ by tier. Free-tier travelers can store a limited number of travel documents (boarding passes, hotel confirmations). Premium travelers get expanded storage.
The important architectural point: subscription gating is applied at the middleware layer, not scattered throughout the business logic. A single middleware checks the subscription status, determines the tier, and attaches the tier's limits to the request context. Downstream code reads the limits from the context without knowing how they were determined. If we change the tier structure, we update the middleware, not every endpoint.
Implement cross-platform subscriptions
If you're adding subscriptions to your mobile app, here's what I'd emphasize.
Use a management layer. Don't build App Store and Google Play integrations from scratch. The edge cases (grace periods, billing retry, cross-platform restore, family sharing, promotional offers) are numerous and platform-specific. A management layer handles them.
Validate receipts server-side. Always. Client-side validation is insecure.
Handle every lifecycle state. Active and expired aren't enough. Grace period, billing retry, paused, and refunded all need specific handling. Test each state transition explicitly.
Track churn by cause. Voluntary churn (the traveler chose to cancel) and involuntary churn (billing failure) have different solutions. Voluntary churn is a product problem. Involuntary churn is a billing recovery problem. Conflating them leads to wrong conclusions.
Gate features at the middleware layer. Don't scatter subscription checks throughout your codebase. Centralize the entitlement check and propagate the result through the request context.
Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. Plan your next trip.