On this page
The happy path, where a user taps "Subscribe", pays and gets access, is a small part of subscription billing. The rest is renewals, failed payments and grace periods, upgrades, refunds, restores on new devices and fraud. A server-backed design handles all of them consistently.
Google deprecates older Play Billing Library versions on a published schedule. As of late 2026, new apps and updates can no longer use version 7 or older. Check the deprecation FAQ and use the latest version. API shapes change between major versions, so verify the code below against the reference docs for your version.
Architecture
Products, base plans and offers
- A subscription product (for example
premium) has one or more base plans (monthly, yearly; auto-renewing or prepaid). - Offers add trials or introductory prices to a base plan, with eligibility rules.
- Create them in Play Console โ Monetize. The app queries them at runtime, so never hard-code prices.
Client flow
class BillingRepository(
context: Context,
private val backend: EntitlementApi,
private val scope: CoroutineScope,
) : PurchasesUpdatedListener {
private val client = BillingClient.newBuilder(context)
.setListener(this)
.enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
.build()
suspend fun connect(): Boolean = suspendCancellableCoroutine { cont ->
client.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(result: BillingResult) {
if (cont.isActive) cont.resume(result.responseCode == BillingClient.BillingResponseCode.OK)
}
override fun onBillingServiceDisconnected() { /* reconnect on next call */ }
})
}
suspend fun premiumDetails(): ProductDetails? {
val params = QueryProductDetailsParams.newBuilder().setProductList(listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("premium").setProductType(BillingClient.ProductType.SUBS).build()
)).build()
return client.queryProductDetails(params).productDetailsList?.firstOrNull() // billing-ktx suspend API
}
fun launch(activity: Activity, details: ProductDetails, offerToken: String) {
val flowParams = BillingFlowParams.newBuilder().setProductDetailsParamsList(listOf(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(details).setOfferToken(offerToken).build()
)).build()
client.launchBillingFlow(activity, flowParams)
}
override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
if (result.responseCode != BillingClient.BillingResponseCode.OK) return // cancelled / error โ show message
purchases.orEmpty()
.filter { it.purchaseState == Purchase.PurchaseState.PURCHASED }
.forEach { purchase ->
// Server verifies with Google, acknowledges, and grants the entitlement.
scope.launch { backend.verifyAndGrant(purchase.purchaseToken, purchase.products) }
}
}
}Purchases not acknowledged within three days are refunded automatically. Acknowledge on the server after verification (or on the client with acknowledgePurchase if you have no backend).
Server responsibilities
- Verify each purchase token with the Google Play Developer API (subscriptions v2 endpoint).
- Link the purchase to your user account (and guard against token reuse across accounts).
- Acknowledge the purchase.
- Store the entitlement with its expiry and state.
- Process RTDN (real-time developer notifications via Pub/Sub) for renewals, grace periods, account holds, cancellations and refunds, re-querying the API for the latest state.
Subscription states to handle in UI
| State | User access | UI |
|---|---|---|
| Active | Full | Normal premium experience |
| Cancelled (still in period) | Until expiry | "Your plan ends on โฆ", resubscribe option |
| Grace period | Usually keep access | Ask to fix payment method |
| Account hold | Remove access | Explain and link to Play subscription centre |
| Expired / refunded | None | Offer to resubscribe |
Testing
- Add license testers in Play Console, whose purchases use test payment methods.
- Upload to a testing track: billing requires the app to be published on a track with matching signing.
- Test renewals (accelerated for testers), cancellation, grace period and restore on a second device.
Examples
Content subscription
Monthly and yearly base plans, a 7-day trial offer, and server-checked entitlements for premium content.
Remove ads (one-time)
A one-time product, acknowledged and verified, with the entitlement cached locally and checked periodically.
Multi-platform account
Entitlements stored per user on the server, so access works across the user's devices.
Frequently asked questions
Can I skip the backend?
For simple one-time unlocks you can verify and acknowledge on the device, but it's easier to defraud and harder to sync across devices. Subscriptions benefit greatly from a backend.
How do users manage or cancel?
Through the Play Store subscription centre. Provide a deep link from your app's settings.
Should I use a subscription management service?
Third-party services can handle verification, RTDN and analytics for you. Evaluate their cost and data handling against building it yourself.
Conclusion
Reliable subscriptions need Play Billing on the client, verification, acknowledgement and entitlements on your server, RTDN for lifecycle events, clear UI for every state, and thorough testing with license testers. Keep the Billing Library up to date with Google's schedule.
Next step: keep subscribers happy and ratings high with How to Improve Android App Ratings and Reviews.
Official references
๐ฑ Apps built by Yunok Tech
Real Android apps on Google Play, free to download.
Walzi4K wallpapers for lock and home screenGet it โธ
NotiVaultNotification history: recover dismissed notificationsGet it โธ
Ready to build real Android applications?
Shipping is a skill of its own. Learn to take an app from a working build to a polished, signed release that real users can install from Google Play.
Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.
Explore the Android course and take your next step as an Android developer.