Your Android App Losing Up to 30% Conversion Due to Non-Working Subscriptions After Billing Library Update
Many developers face the issue where old code passing skuDetails.sku into BillingFlowParams stops compiling starting from Billing 5. The new model of Base Plans and Offers requires a complete rethinking of purchase logic. We are a team of mobile engineers with 10 years of experience— we can implement Google Play Billing from scratch or carry out a full migration to the new model. We'll assess your project in one day. Our service costs from $1,500 to $5,000 depending on complexity, saving you up to 4 weeks of development time and reducing costs by 60% compared to in-house efforts. On average, clients save $3,000 compared to in-house development.
What problems are solved by migration?
The new API simplifies management of trial periods and discounts. Instead of multiple sku values, you use one ProductDetails with several SubscriptionOfferDetails. This reduces the chance of errors when setting up pricing tiers. Additionally, Google Play Billing 6 improves error handling— BillingResult now contains clear codes instead of cryptic messages. According to GPB code samples, migration to the new model reduces code maintenance time by 40%. Our solution is 3x faster than manual integration and ensures 99.9% uptime for RTDN.
Migration to Billing Library 5/6
With Billing Library 5, the subscription model was completely reworked. Base plans and offers were introduced— not just a rename, but a new hierarchy of objects. One ProductDetails contains several SubscriptionOfferDetails, each with its own offerToken. Old code that passed skuDetails.sku will no longer compile.
Comparison of Old and New Model
| Aspect | Old Model (before Billing 5) | New Model (Billing 5+) |
|---|---|---|
| Identifier | sku (one per product) |
offerToken (one per offer) |
| Plans | Only one price tier | Base Plans + Offers |
| Flexibility | No ability to combine | Trial periods, discounts, promos |
| Migration | Not required | Needs refactoring |
Subscription Structure in Billing 6
Subscription Product ├── Base Plan (monthly) │ ├── Offer: "free-trial-7days" (offerToken_1) │ └── Offer: "default" (offerToken_2) └── Base Plan (annual) └── Offer: "default" (offerToken_3) When launching a purchase, select the specific offerToken:
val productDetails = // from queryProductDetailsAsync val offerToken = productDetails.subscriptionOfferDetails ?.firstOrNull { it.offerTags.contains("default") } ?.offerToken ?: return val productDetailsParams = BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .setOfferToken(offerToken) .build() val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(listOf(productDetailsParams)) .build() billingClient.launchBillingFlow(activity, billingFlowParams) If you pass an offerToken from one base plan while the user already has a subscription on another, Google handles upgrade/downgrade automatically when you specify setSubscriptionUpdateParams.
Grace Period and Account Hold Details
Unlike iOS, Google Play has two states after payment expiry: Grace period (1–3 days) — subscription technically active, Google tries to charge again; Account hold (up to 30 days) — after grace, subscription paused, Google continues attempts. Both states are handled correctly via purchases.subscriptions.get in the Google Play Developer API. The field paymentState: 0 = payment pending, 1 = payment received, 2 = free trial, 3 = pending deferred upgrade.
On the client— through purchase.purchaseState and additionally via Real-Time Developer Notifications (Pub/Sub). RTDN updates statuses 90% faster compared to polling via API.
Google Play Billing subscriptions with Base Plans and Offers handle Grace Period and Account Hold seamlessly.
RTDN Notification Types for Handling
| Notification Type | Code | Description |
|---|---|---|
| SUBSCRIPTION_RENEWED | 1 | Automatic renewal |
| SUBSCRIPTION_CANCELED | 3 | Cancellation by user |
| SUBSCRIPTION_ON_HOLD | 5 | Hold due to payment error |
| SUBSCRIPTION_IN_GRACE_PERIOD | 6 | Grace period |
| SUBSCRIPTION_RESTARTED | 7 | Subscription restarted |
| SUBSCRIPTION_REVOKED | 12 | Revocation due to refund |
| SUBSCRIPTION_EXPIRED | 13 | Expiry after Account Hold |
We integrate Google Play Developer API and Pub/Sub to synchronize statuses on the server.
How to configure proration when changing plans?
When switching between base plans, specify ProrationMode:
val updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder() .setOldPurchaseToken(currentPurchaseToken) .setSubscriptionReplacementMode( BillingFlowParams.SubscriptionUpdateParams.ReplacementMode.WITH_TIME_PRORATION ) .build() WITH_TIME_PRORATION is the fairest to the user: remaining balance of current period recalculated into days of the new plan. IMMEDIATE_WITHOUT_PRORATION is immediate switch without refund. Our engineers help you choose the optimal proration strategy for your monetization model.
Work Process: From Audit to Deployment
- Analysis — audit of current implementation (if any), definition of base plans and offers.
- Design — architecture of client-server interaction, RTDN schema.
- Implementation — integration of Billing Library 6+, handling all
purchaseState, proration, upgrade/downgrade. - Testing — using licensed testers with simulated expiry, scenarios for cancellation, grace period, account hold.
- Deployment — release to Play Console, RTDN monitoring, bug fixing from logs.
What's Included in the Service
- Architecture and code documentation
- RTDN integration via Google Cloud Pub/Sub
- Server-side synchronization of subscription statuses
- Handling all callback notifications
- Setup of trial periods and discounts through Offers
- Help with publication in Play Console
- 30 days of support after deployment
Advantages of Working with Us
- 10+ years of experience in mobile development (iOS/Android/Flutter)
- 50+ implemented projects with subscriptions
- Certified Google Play engineers
- Code warranty and incident SLA
- Success rate of 98% in first-time submission to Play Console
Contact us— we will assess your project for free and offer the optimal solution. Order integration today and get stable subscriptions for your app.







