Transition from BillingClient SDK to Pay SDK: A Complete Guide for Developers
RuStore
App store for Android

Content
The RuStore team continues to develop the Pay SDK — a new payment solution that expands monetization capabilities and provides more flexibility when working with in-app purchases and subscriptions in the store.
As part of the platform's evolution, we are gradually phasing out support for the BillingClient SDK: it will be discontinued starting August 1, 2026. We are announcing this change well in advance to give developers ample time to plan the transition: prepare their architecture, test the new integration, and migrate current monetization scenarios.
We recommend using the Pay SDK for both new projects and when updating existing ones. However, it's important to assess the changes and prepare the architecture beforehand, as switching to the new payment system is not simply replacing a dependency in the project. The SDK introduces updated approaches to initialization, working with deeplinks, purchase status models, payment confirmation, and subscription logic.
A detailed migration guide is already available in the RuStore documentation. In this article, we will break down the key steps of the transition, the main differences between the SDKs, and the specifics of handling active subscriptions — to ensure a smooth update for users without revenue loss.
What Changes When Integrating Pay SDK
The Pay SDK is structured differently, and some logic is now moved from code to configuration.
1. Adding the Dependency
The SDK name changes (pay instead of billingclient), and the list of dependencies becomes shorter — extra parameters are no longer needed. Essentially, this results in a more compact and cleaner integration.
2. Initialization
In the BillingClient SDK, consoleApplicationId was passed in the code when creating the client.
In the Pay SDK, it is specified in the AndroidManifest.xml. The deeplink scheme is also moved there.
This simplifies SDK startup: less manual initialization in code, more declarative configuration.
3. Working with Deeplinks
Previously, the deeplink was configured through the client factory. Now, the scheme is declared in the AndroidManifest, and a dedicated IntentInteractor is used for handling.
The logic becomes more explicit and manageable.
4. Checking Payment Availability
The check method changes, along with the response types.
Now, PurchaseAvailabilityResult is returned, and in case of an error, a Throwable is received instead of a RuStoreException.
This makes error handling more universal.
5. Fetching Products
In the Pay SDK, the list of products can be requested without user authorization.
Plus, the limit has increased: up to 1000 items per request instead of 100. This simplifies catalog loading and reduces the number of requests.
What Changed in the Product Model
The Product structure has been updated: some fields have been renamed or removed, and a separate subscriptionInfo field has been added for subscriptions, containing detailed information about periods — free trial, promotional, main, grace period, and hold. If you have custom logic for displaying subscriptions, it will need to be adapted to the new model.
All this provides a more accurate subscription model and allows for more flexible display of information in the interface.
6. Fetching Purchases
The method for fetching purchases changes, and convenient filtering is introduced: by product type (one-time / subscriptions) and by purchase status.
The main architectural change is the introduction of a common Purchase interface and two implementations:
ProductPurchasefor one-time purchases,SubscriptionPurchasefor subscriptions. This separation makes the model cleaner but will require updating the handling of different purchase types in the code.
Purchase Statuses The Pay SDK status model has been reworked:
- Statuses have become more detailed.
- Logic differs for one-time purchases and subscriptions.
- Separate states have appeared for subscriptions (e.g., ACTIVE, PAUSED, EXPIRED). If your project has custom status mapping logic, it may need updating for subscriptions, where additional states have appeared. The logic for one-time purchases remains unchanged.
Initiating a Purchase
A universal purchase() method is now used, allowing you to choose the payment type:
- One-step (ONE_STEP),
- Two-step (TWO_STEP, with funds held on the user's card).
Previously, the step type was rigidly tied to the product type. Now, the developer can manage this parameter independently.
A separate method,
purchaseTwoStep(), is used for guaranteed two-step payment.
Important:
- The two-step scheme is not available for all payment methods.
- In certain scenarios, the set of available payment methods may differ.
- Only one-step payment is used for subscriptions.
Error Handling In the Pay SDK:
- A successful purchase is returned as a single result.
- Cancellations and errors are handled via
OnFailureListener. - Separate exception types for user cancellation have been added.
This slightly changes the result handling pattern, especially if the previous logic was tied to
Success/Failure/Cancelled.
Server-Side Validation
In the BillingClient SDK, purchaseToken was used for server-side verification.
In the Pay SDK, invoiceId is used for one-time purchases, and purchaseId for subscriptions.
If you have server-side validation set up, this block needs to be updated separately.
Confirming and Cancelling a Two-Step Purchase The confirmation and cancellation methods have changed:
- Confirmation:
confirmTwoStepPurchase(), - Cancellation:
cancelTwoStepPurchase(). This is only relevant for two-step payments.
Purchased Items and Subscriptions
As of August 1, 2026, the getPurchases() method in the BillingClient SDK will stop returning lists of purchases and subscriptions. This means the previous workflow using the BillingClient SDK will become unavailable.
One-time purchases made by users via the BillingClient SDK are preserved and remain accessible after switching to the Pay SDK when calling the getPurchases() / getPurchase() methods. Data for such purchases can also be obtained via the Public API using this method.
Subscriptions require special attention during migration to the Pay SDK. They have a different lifecycle, so the transition usually involves not only technical changes but also working with the current subscriber base.
If a user has an active subscription as of August 1, 2026, it will continue to be active until the end of the already paid period. After it ends, automatic renewal via the BillingClient SDK will not occur, and the subscription will transition to an inactive status.
Data on active subscriptions can be obtained via the Public API (method 1, method 2) until the end of December 2026.
What We Recommend Doing Before August 1
1) Take a "Snapshot" of Active Subscriptions via the Public API
Gather up-to-date information: who is subscribed, the paid period end date, and the current subscription status. This is the baseline for planning the transition.
2) Integrate the Pay SDK for New Subscriptions as Soon as Possible
It's crucial that the Pay SDK is not just integrated but tested in real scenarios: purchase flow, error handling, analytics.
The sooner new users start subscribing through the Pay SDK, the fewer users will need to be migrated when the old solution is discontinued.
3) Prepare a "Soft Migration" Scenario for Subscriptions
There will be no automatic "as-is" migration of subscriptions. Therefore, the goal is to make the process of re-subscribing via the Pay SDK stress-free for the user:
- Plan how to determine the user's current access — for example, by processing the subscription status on your server.
- Decide when and how to prompt for re-subscription.
- Decide what to show the user at the end of the paid period.
4) Launch Subscription Reactivation Campaigns
Suggest that users stop renewing their current subscription: to do this, direct them to the subscription management section in RuStore before August 1, 2026.
When the current period ends and the subscription becomes inactive, immediately offer the user a clear action: "Renew Access" or "Resume Subscription" with a single, clear CTA.
You can also set up a new subscription with a free trial in advance and offer users to subscribe to it before their current one expires. This allows them to continue using the service without interruption and without needing to re-subscribe after the current one ends.
To prevent the transition from surprising users, warn them about the changes in advance. A short message in the product, an email, or a push notification explaining the following is sufficient:
- When this will affect renewals.
- That access will continue until the end of the paid period.
- What they need to do next (re-subscribe).
5) Update the App Version for All Users to the Latest Version with the Pay SDK
We recommend ensuring in advance that users transition to the latest app version with Pay SDK support. This will help avoid a situation where, after August 1, part of the audience remains on the old version and faces the inability to make purchases.
To speed up the transition, you can use force update mechanisms, for example, via the RuStore Update SDK.
If you have any questions or need help with the transition, write to us at: support@rustore.ru.