Поддержка BillingClient SDK прекращается 1 августа 2026 года. После 1 августа 2026 года платежи перестанут обрабатываться для всех покупок, включая подписки.
До этого времени BillingClient SDK продолжает свою работу, но устранение неисправностей, влияющих на работу платежей, может занимать больше времени. Новая функциональность добавляться не будет.
Рекомендуем использовать Pay SDK в проектах.
Для перехода на Pay SDK воспользуйтесь инструкцией по миграции.
SDK Платежи in-app и подписки для Kotlin/Java (версия 5.0.0)
RuStore позволяет интегрировать платежи в мобильное приложение.
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
Подготовка к работе
- Kotlin
- Java
Добавление репозитория
Подключите репозиторий, как показано в примере ниже.
repositories {
maven {
url = uri("https://artifactory-external.vkpartner.ru/artifactory/maven")
}
}
Подключение зависимости
Добавьте следующий код в свой конфигурационный файл для подключения зависимости.
dependencies {
implementation("ru.rustore.sdk:billingclient:5.0.0")
}
Добавление репозитория
Подключите репозиторий, как показано в примере ниже.
repositories {
maven {
url "https://artifactory-external.vkpartner.ru/artifactory/maven"
}
}
Подключение зависимости
Добавьте следующий код в свой конфигурационный файл для подключения зависимости.
dependencies {
implementation "ru.rustore.sdk:billingclient:5.0.0"
}
Обработка deeplink
- Kotlin
- Java
class YourBillingActivity: AppCompatActivity() {
// Previously created with RuStoreBillingClientFactory.create()
private val billingClient: RuStoreBillingClient = YourDependencyInjection.getBillingClient()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
billingClient.onNewIntent(intent)
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
billingClient.onNewIntent(intent)
}
}
Для восстановления состояния вашего приложения при возврате с deeplink добавьте в
AndroidManifest.xml android:launchMode="singleTask".
<activity
android:name=".YourBillingActivity"
android:launchMode="singleTask"
android:exported="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
public class YourBillingActivity extends AppCompatActivity {
// Previously created with RuStoreBillingClientFactory.create();
RuStoreBillingClient billingClient = YourDependencyInjection.getBillingClient();
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
billingClient.onNewIntent(getIntent());
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
billingClient.onNewIntent(intent);
}
}
Для восстановления состояния вашего приложения при возврате с deeplink добавьте в
AndroidManifest.xml android:launchMode="singleTask".
<activity
android:name=".YourBillingActivity"
android:launchMode="singleTask"
android:exported="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
Инициализация SDK
Перед вызовом методов библиотеки необходимо выполнить ее инициализацию.
- Kotlin
- Java
Создайте RuStoreBillingClient, используя RuStoreBillingClientFactory.create().
val billingClient: RuStoreBillingClient = RuStoreBillingClientFactory.create(
context = app,
consoleApplicationId = "111111",
deeplinkScheme = "yourappscheme",
// Опциональные параметры
themeProvider = null,
debugLogs = false,
externalPaymentLoggerFactory = null,
)
-
context— это ключевой элемент, который предоставляет информацию о текущем состоянии приложения или объекта.к сведениюВ Android существует несколько типов контекста:
- Контекст приложения — это singleton-экземпляр, доступный через
getApplicationContext(). - Контекст
Activity— доступен внутриActivityи привязан к ее жизненному циклу. - Контекст в
ContentProvider— доступен через методgetContext()и аналогичен контексту приложения.
Для создания
RuStoreBillingClientпредпочтительнее исполь зоватьapplicationContext. - Контекст приложения — это singleton-экземпляр, доступный через
-
consoleApplicationId— идентификатор приложения из RuStore консоли.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/и/versions. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versionsID приложения —123456.

ApplicationId, указанный в build.gradle, должен совпадать с applicationId APK-файла, который вы публиковали в RuStore Консоль.
-
deeplinkScheme— схема deeplink, необходимая для возврата в ваше приложение после оплаты через стороннее приложение (например, SberPay или СБП). SDK генерирует свой хост к данной схеме.
yourappscheme, должна совпадать со схемой, указанной в AndroidManifest.xml (подробнее см. Обработка deeplink).-
themeProvider— интерфейс, который предоставляет темуBillingClientTheme. Возможны 2 реализации темыBillingClientTheme: све тлая (Light) и темная (Dark). Необязательный интерфейс, по умолчанию применяется светлая тема.
примечаниеПо умолчанию тема будет светлой (
Light), но вы можете настроить и темную (Dark). -
externalPaymentLoggerFactory— интерфейс, позволяющий вести журнал событий.подсказкаЖурнал событий полезен для версий, которые еще не опубликованы на пользователей. С его помощью можно отследить возникающие ошибки.
-
debugLogs— флаг, регулирующий ведение журнала событий. Укажите значениеtrue, если хотите, чтобы события попадали в журнал. В ином случае укажитеfalse.
Подпись keystore должна совпадать с подписью, которой было подписано приложение, опубликованное в RuStore Консоль. Убедитесь, что используемый buildType (пр. debug) использует такую же подпись, что и опубликованное приложение (пр. release).
Создайте RuStoreBillingClient, используя RuStoreBillingClientFactory.create().
final Context context = getContext();
final String consoleApplicationId = "111111";
final String deeplinkScheme = "yourappscheme";
// Опциональные параметры
final BillingClientThemeProvider themeProvider = null;
final boolean debugLogs = false;
final ExternalPaymentLoggerFactory externalPaymentLoggerFactory = null;
final SuperAppTokenProvider superAppTokenProvider = null;
RuStoreBillingClient billingClient = RuStoreBillingClientFactory.INSTANCE.create(
context,
consoleApplicationId,
deeplinkScheme,
// Опциональные параметры
themeProvider,
superAppTokenProvider,
externalPaymentLoggerFactory
debugLogs,
);
-
context— это ключевой элемент, который предоставляет информацию о текущем состоянии приложения или объекта.к сведениюВ Android существует несколько типов контекста:
- Контекст приложения — это singleton-экземпляр, доступный через
getApplicationContext(). - Контекст
Activity— доступен внутриActivityи привязан к ее жизненному циклу. - Контекст в
ContentProvider— доступен через методgetContext()и аналогичен контексту приложения.
Для создания
RuStoreBillingClientпредпочтительнее использоватьapplicationContext. - Контекст приложения — это singleton-экземпляр, доступный через
-
consoleApplicationId— идентификатор приложения из RuStore консоли.
Где в RuStore Консоль отображаются идентификаторы приложений?
- Перейдите на вкладку Приложения и выберите нужное приложение.
- Скопируйте идентификатор из URL-адреса страницы приложения — это набор цифр между
apps/и/versions. Например, для URL-адресаhttps://console.rustore.ru/apps/123456/versionsID приложения —123456.

ApplicationId, указанный в build.gradle, должен совпадать с applicationId APK-файла, который вы публиковали в RuStore Консоль.
-
deeplinkScheme— схема deeplink, необходимая для возврата в ваше приложение после оплаты через стороннее приложение (например, SberPay или СБП). SDK генерирует свой хост к данной схеме.
yourappscheme, должна совпадать со схемой, указанной в AndroidManifest.xml (подробнее см. Обработка deeplink).-
themeProvider— интерфейс, который предоставляет темуBillingClientTheme. Возможны 2 реализации темыBillingClientTheme: светлая (Light) и темная (Dark). Необязательный интерфейс, по умолчанию применяется светлая тема.
примечаниеПо умолчанию тема будет светлой (
Light), но вы можете настроить и темную (Dark). -
externalPaymentLoggerFactory— интерфейс, позволяющий вести журнал событий.подсказкаЖурнал событий полезен для версий, которые еще не опубликованы на пользователей. С его помощью можно отследить возникающие ошибки.
-
debugLogs— флаг, регулирующий ведение журнала событий. Укажите значениеtrue, если хотите, чтобы события попадали в журнал. В ином случае укажитеfalse.
Подпись keystore должна совпадать с подписью, которой было подписано приложение, опубликованное в RuStore Консоль. Убедитесь, что используемый buildType (пр. debug) использует такую же подпись, что и опубликованное приложение (пр. release).
Методы SDK
Получение списка продуктов
- Kotlin
- Java
getProducts, чтобы получить информацию о продуктах, добавленных в ваше приложение через RuStore Консоль.
val productsUseCase: ProductsUseCase = billingClient.products
productsUseCase.getProducts(productIds = listOf("id1", "id2"))
.addOnSuccessListener { products: List<Product> ->
// Process success
}
.addOnFailureListener { throwable: Throwable ->
// Process error
}
productIds — список идентификаторов продуктов. В нем не должно быть более 100 позиций.
Чтобы указать id продуктов, которые нужны для работы метода, выполните следующие действия.
- Откройте RuStore Консоль.
- Перейдите на вкладку Приложения.
- Выберите нужное приложение.
- В левом боковом меню выберите раздел Монетизация.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров. Это и есть
idпродуктов.

Метод возвращает
data class Product(
val productId: String,
val productType: ProductType?,
val productStatus: ProductStatus,
val priceLabel: String?,
val price: Int?,
val currency: String?,
val language: String?,
val title: String?,
val description: String?,
val imageUrl: Uri?,
val promoImageUrl: Uri?,
val subscription: ProductSubscription?,
)
Структура продукта
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).productType— тип продукта (потребляемый / непотребляемый / подписка):CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION.productStatus— статус продукта.priceLable— отформатированная цена товара, включая валютный знак на языкеlanguage.price— цена в минимальных единицах (в копейках).currency— код валюты ISO 4217.language— язык, указанный с помощью BCP 47 кодирования.title— название продукта на языкеlanguage.description— описание на языкеlanguage.imageUrl— ссылка на картинку.promoImageUrl— ссылка на промокартинку.subscription— описание подписки, возвращается только для продуктов с типомsubscription.
Структура подписки
data class ProductSubscription(
val subscriptionPeriod: SubscriptionPeriod?,
val freeTrialPeriod: SubscriptionPeriod?,
val gracePeriod: SubscriptionPeriod?,
val introductoryPrice: String?,
val introductoryPriceAmount: String?,
val introductoryPricePeriod: SubscriptionPeriod?
)
subscriptionPeriod— период подписки.freeTrialPeriod— п робный период подписки.gracePeriod— льготный период подписки.introductoryPrice— отформатированная вступительная цена подписки, включая знак валюты, на языкеproduct:language.introductoryPriceAmount— вступительная цена в минимальных единицах валюты (в копейках).introductoryPricePeriod— расчетный период вступительной цены.
Структура периода подписки
data class SubscriptionPeriod(
val years: Int,
val months: Int,
val days: Int,
)
years— количество лет.months— количество месяцев.days— количество дней.
getProducts, чтобы получить информацию о продуктах, добавленных в ваше приложение через RuStore Консоль.
ProductsUseCase productsUseCase = billingClient.getProducts();
productsUseCase.getProducts(Arrays.asList("id1", "id2"))
.addOnSuccessListener(products ->
// Process success
)
.addOnFailureListener(throwable ->
// Process error
);
productIds: List<String> — список идентификаторов продуктов. В нем не должно быть более 100 позиций.
Чтобы указать id продуктов, которые нужны для работы метода, выполните следующие действия.
- Откройте RuStore Консоль.
- Перейдите на вкладку Приложения.
- Выберите нужное приложение.
- В левом боковом меню выберите раздел Монетизация.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров. Это и есть
idпродуктов.

Структура продукта
public Product(
String productId,
@Nullable
ProductType productType,
ProductStatus productStatus,
@Nullable
String priceLabel,
@Nullable
Integer price,
@Nullable
String currency,
@Nullable
String language,
@Nullable
String title,
@Nullable
String description,
@Nullable
Uri imageUrl,
@Nullable
Uri promoImageUrl,
@Nullable
ProductSubscription subscription
) {
this.productId = productId;
this.productType = productType;
this.productStatus = productStatus;
this.priceLabel = priceLabel;
this.price = price;
this.currency = currency;
this.language = language;
this.title = title;
this.description = description;
this.imageUrl = imageUrl;
this.promoImageUrl = promoImageUrl;
this.subscription = subscription;
}
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).productType— тип продукта (потребляемый / непотребляемый / подписка):CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION.productStatus— статус продукта.priceLabel— отформатированная цена товара, включая валютный знак на языкеlanguage.price— цена в минимальных единицах (в копейках).currency— код валюты ISO 4217.language— язык, указанный с помощью BCP 47 кодирования.title— название продукта на языкеlanguage.description— описание на языкеlanguage.imageUrl— ссылка на картинку.promoimageurl— ссылка на промокартинку.subscription— описание подписки, возвращается только для продуктов с типомsubscription.
Структура подписки
public ProductSubscription(
@Nullable
SubscriptionPeriod subscriptionPeriod,
@Nullable
SubscriptionPeriod freeTrialPeriod,
@Nullable
SubscriptionPeriod gracePeriod,
@Nullable
String introductoryPrice,
@Nullable
String introductoryPriceAmount,
@Nullable
SubscriptionPeriod introductoryPricePeriod
) {
this.subscriptionPeriod = subscriptionPeriod;
this.freeTrialPeriod = freeTrialPeriod;
this.gracePeriod = gracePeriod;
this.introductoryPrice = introductoryPrice;
this.introductoryPriceAmount = introductoryPriceAmount;
this.introductoryPricePeriod = introductoryPricePeriod;
}
subscriptionPeriod— период подписки.freeTrialPeriod— пробный период подписки.gracePeriod— льготный период подписки.introductoryPrice— отформатированная вступительная цена подписки, включая знак валюты, на языкеproduct:language.introductoryPriceAmount— вступительная цена в минимальных единицах валюты (в копейках).introductoryPricePeriod— расчетный период вступительной цены.
Структура периода подписки
public SubscriptionPeriod(
int years,
int months,
int days
) {
this.years = years;
this.months = months;
this.days = days;
}
years— количество лет.months— количество месяцев.days— количество дней.
Покупка продукта
- Kotlin
- Java
Для вызова покупки продукта используйте метод purchaseProduct.
val purchasesUseCase: PurchasesUseCase = billingClient.purchases
purchasesUseCase.purchaseProduct(
productId = productId,
orderId = UUID.randomUUID().toString(),
quantity = 1,
developerPayload = null,
).addOnSuccessListener { paymentResult: PaymentResult ->
when (paymentResult) {
// Process PaymentResult
}
}.addOnFailureListener { throwable: Throwable ->
// Process error
}
productId: String— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).orderId: String— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.quantity: Int— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование).
Структура результата покупки
public sealed interface PaymentResult {
public data class Success(
val orderId: String?,
val purchaseId: String,
val productId: String,
val invoiceId: String,
val subscriptionToken: String? = null,
) : PaymentResult
public data class Cancelled(
val purchaseId: String,
) : PaymentResult
public data class Failure(
val purchaseId: String?,
val invoiceId: String?,
val orderId: String?,
val quantity: Int?,
val productId: String?,
val errorCode: Int?,
) : PaymentResult
public object InvalidPaymentState : PaymentResult()
}
Success— результат успешного завершения покупки цифрового товара.Failure— при отправке запроса на оплату или получения статуса оплаты возникла проблема, невозможно установить статус покупки.Cancelled— запрос на покупку отправлен, при этом пользователь закрыл «платежную шторку» на своем устройстве, и результат оплаты неизвестен.InvalidPaymentState— ошибка работы SDK платежей. Может возникнуть, в случае некорректного обратного deeplink.
Для вызова покупки продукта используйте метод purchaseProduct.
purchasesUseCase.purchaseProduct(productId, null, 1, developerPayload)
.addOnSuccessListener(result ->
// Process PaymentResult
)
.addOnFailureListener(throwable ->
// Process error
);
productId: String— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).orderId: String— уникаль ный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.quantity: Int— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование).
Структура результата покупки
public interface PaymentResult {
class Success implements PaymentResult {
@Nullable
String orderId;
String purchaseId;
String productId;
String invoiceId;
@Nullable
String subscriptionToken;
public Success(@Nullable String orderId, String purchaseId, String productId, String invoiceId,
@Nullable String subscriptionToken) {
this.orderId = orderId;
this.purchaseId = purchaseId;
this.productId = productId;
this.invoiceId = invoiceId;
this.subscriptionToken = subscriptionToken;
}
}
class Failure implements PaymentResult {
@Nullable
String purchaseId;
@Nullable
String invoiceId;
@Nullable
String orderId;
@Nullable
Integer quantity;
@Nullable
String productId;
@Nullable
Integer errorCode;
public Failure(@Nullable String purchaseId, @Nullable String invoiceId, @Nullable String orderId,
@Nullable Integer quantity, @Nullable String productId, @Nullable Integer errorCode) {
this.purchaseId = purchaseId;
this.invoiceId = invoiceId;
this.orderId = orderId;
this.quantity = quantity;
this.productId = productId;
this.errorCode = errorCode;
}
}
class Cancelled implements PaymentResult {
String purchaseId;
public Cancelled(String purchaseId) {
this.purchaseId = purchaseId;
}
}
class InvalidPaymentState implements PaymentResult {}
}
Success— результат успешного завершения покупки цифрового товара.Failure— при отправке запроса на оплату или получения статуса оплаты возникла проблема, невозможно установить статус покупки.Cancelled— запрос на покупку отправлен, при этом пользователь закрыл «платежную шторку» на своем устройстве, и результат оплаты неизвестен.InvalidPaymentState— ошибка работы SDK платежей. Может возникнуть, в случае некорректного обратного deeplink.
Подтверждение (потребление) покупки
Продукты, требующие подтверждения (потребления)
Учитывайте тип покупки. Метод подтверждения (потребления) необходим, только если у вас потребляемый товар (CONSUMABLE), который можно купить много раз.
Чтобы такие товары начислились пользователям без ошибок, подтвердите подтверждение (потребление) продукта с помощью метода confirmPurchase.
При начислении товара в вашем приложении используйте серверную валидацию платежей. Начисляйте товар только когда платеж (счет) перейдет в финальный статус CONFIRMED.
Начисление продуктов пользователям надо делать в callback addOnSuccessListener метода confirmPurchase.
Статус PAID является промежуточным и означает, что средства пользователя захолдированы на карте и вам нужно подтвердить покупку.
Исключение — платежи через СБП или со счета телефона: при этих способах оплаты используется одностадийный платеж, но модель счета остается двухстадийной. Подробнее см. пояснения ниже.
При оплате потребляемых (CONSUMABLE) товаров через СБП или со счета телефона используется одностадийный платеж, при этом м одель счета остается двухстадийной. Это значит, что при переходе счета в статус PAID при оплате через СБП или со счета мобильного телефона деньги уже списаны со счета покупателя, а с разработчика удержана комиссия. В этом случае при отмене покупки в состоянии PAID происходит возврат средств (refund), а не отмена холдирования — reverse. Удержанная комиссия разработчику не возвращается. При этом для завершения покупки все равно нужно выполнить метод подтверждения (потребления) — см. также таблицу ниже.
| Платежный метод | Тип платежа | Платеж в статусе PAID |
|---|---|---|
| Двухстадийный |
|
| Одностадийный |
|
Вызов метода подтверждения (потребления)
- Kotlin
- Java
Для подтверждения (потребления) покупки используйте метод confirmPurchase. Запрос на подтверждение (потребление) покупки должен сопровождаться выдачей товара. После вызова подтверждения покупка перейдет в статус CONSUMED.
val purchasesUseCase: PurchasesUseCase = billingClient.purchases
purchasesUseCase.confirmPurchase(purchaseId = "purchaseId", developerPayload = null)
.addOnSuccessListener {
// Process success
}
.addOnFailureListener { throwable: Throwable ->
// Process error
}
purchaseId— идентификатор покупки.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование).
Для подтверждения (потребления) покупки используйте метод confirmPurchase. Запрос на подтверждение (потребление) покупки должен сопровождаться выдачей товара. После вызова подтверждения покупка перейдет в статус CONSUMED.
PurchasesUseCase purchasesUseCase = billingClient.getPurchases();
purchasesUseCase.confirmPurchase("purchaseId", "developerPayload")
.addOnSuccessListener(unit ->
// Process success
)
.addOnFailureListener(throwable ->
// Process error
);
purchaseId— идентификатор покупки.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование).
Отмена покупки
- Kotlin
- Java
Для отмены покупки используйте метод deletePurchase.
val purchasesUseCase: PurchasesUseCase = billingClient.purchases
purchasesUseCase.deletePurchase(purchaseId = "purchaseId")
.addOnSuccessListener {
// Process success
}
.addOnFailureListener { throwable: Throwable ->
// Process error
}
purchaseId— идентификатор покупки.
Используйте метод отмены покупки с осторожностью и только в исключительных случаях, только если покупка осталась в статусе PAID, а вы не можете выдать товар пользователю. В остальных случаях не рекомендуется вручную отменять покупки, так как RuStore автоматически обрабатывает незавершенные покупки (например, таймаут в 20 минут или повторная покупка от того же кли ента).
При оплате покупки через СБП или со счета мобильного телефона отмена покупки в статусе PAID не отменяет холдирование, а приводит к возврату средств (refund). При этом с разработчика удерживается комиссия, которая не возвращается.
Также вы можете подтверждать или отменять покупки через API RuStore:
Обработка ошибок
При вызове метода RuStoreBillingClient.purchases.purchaseProduct(), ошибки обрабатываются автоматически.
Метод устарел и не рекомендуется к использованию.
Для показа диалога с ошибкой пользователю используйте метод
resolveForBilling
public fun RuStoreException.resolveForBilling(context: Context)
Для отмены покупки используйте метод deletePurchase.
PurchasesUseCase purchasesUseCase = billingClient.getPurchases();
purchasesUseCase.deletePurchase("purchaseId")
.addOnSuccessListener(unit ->
// Process success
)
.addOnFailureListener(throwable ->
// Process error
);
purchaseId— идентификатор покупки.
Используйте метод отмены покупки с осторожностью и только в исключительных случаях, только если покупка осталась в статусе PAID, а вы не можете выдать товар пользователю. В остальных случаях не рекомендуется вручную отменять покупки, так как RuStore автоматически обрабатывает незавершенные покупки (например, таймаут в 20 минут или повторная покупка от того же клиента).
При оплате покупки через СБП или со счета мобильного телефона отмена покупки в статусе PAID не отменяет холдирование, а приводит к возврату средств (refund). При этом с разработчика удерживается комиссия, которая не возвращается.
Также вы можете подтверждать или отменять покупки через API RuStore:
Обработка ошибок
При вызове метода RuStoreBillingClient.purchases.purchaseProduct(), ошибки обрабатываются автоматически.
Метод устарел и не рекомендуется к использованию.
Для показа диалога с ошибкой пользователю используйте метод
resolveForBilling
BillingRuStoreExceptionExtKt.resolveForBilling(exception, getContext());
Получение сведений о покупке
- Kotlin
- Java
getPurchaseInfo.
val purchasesUseCase: PurchasesUseCase = billingClient.purchases
purchasesUseCase.getPurchaseInfo("purchaseId")
.addOnSuccessListener { purchase: Purchase ->
// Process success
}
.addOnFailureListener { throwable: Throwable ->
// Process error
}
Структура покупки
data class Purchase(
val purchaseId: String?,
val productId: String,
val productType: ProductType?,
val invoiceId: String?,
val description: String?,
val language: String?,
val purchaseTime: Date?,
val orderId: String?,
val amountLabel: String?,
val amount: Int?,
val currency: String?,
val quantity: Int?,
val purchaseState: PurchaseState?,
val developerPayload: String?,
val subscriptionToken: String?
)
-
purchaseId— идентификатор покупки. -
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр). -
description— описание на языкеlanguage. -
invoiceId— идентификатор счета. -
language— язык, указанный с помощью BCP 47 кодирования. -
purchaseTime— время покупки. -
orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов. -
amountLable— отформатированная цена покупки, включая валютный знак. -
amount— цена в минимальных единицах валюты. -
currency— код валюты ISO 4217. -
quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров. -
purchaseState— состояние покупки:CREATED— покупка создана;INVOICE_CREATED— создан счет на оплату, покупка ожидает оплаты;PAID— только для покупки потребляемого товара — промежуточный статус, средства на счете покупателя зарезервированы. Покупка ожидает подтверждения от разработчика;CONFIRMED— платеж за непотребляемый товар успешно совершен;CONSUMED— платеж за потребляемый товар успешно совершен;CANCELLED— покупка отменена — оплата не была произведена или был совершен возврат средств покупателю (для подписок после возврата средств покупка не переходит вCANCELLED);PAUSED— для подписок — подписка перешла в HOLD период;TERMINATED— подписка закрылась.
-
developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование). -
subscriptionToken— токен для валидации покупки на сервере.
getPurchaseInfo.
PurchasesUseCase purchasesUseCase = billingClient.getPurchases();
purchasesUseCase.getPurchaseInfo("purchaseId")
.addOnSuccessListener(purchase ->
// Process success
)
.addOnFailureListener(throwable ->
// Process error
);
Структура покупки
public Purchase(
@Nullable
String purchaseId,
String productId,
@Nullable
ProductType productType,
@Nullable
String invoiceId,
@Nullable
String description,
@Nullable
String language,
@Nullable
Date purchaseTime,
@Nullable
String orderId,
@Nullable
String amountLabel,
@Nullable
Integer amount,
@Nullable
String currency,
@Nullable
Integer quantity,
@Nullable
PurchaseState purchaseState,
@Nullable
String developerPayload,
@Nullable
String subscriptionToken
) {
this.purchaseId = purchaseId;
this.productId = productId;
this.productType = productType;
this.invoiceId = invoiceId;
this.description = description;
this.language = language;
this.purchaseTime = purchaseTime;
this.orderId = orderId;
this.amountLabel = amountLabel;
this.amount = amount;
this.currency = currency;
this.quantity = quantity;
this.purchaseState = purchaseState;
this.developerPayload = developerPayload;
this.subscriptionToken = subscriptionToken;
}
-
purchaseId— идентификатор покупки. -
productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр). -
description— описание на языкеlanguage. -
invoiceId— идентификатор счета. -
language— язык, указанный с помощью BCP 47 кодирования. -
purchaseTime— время покупки. -
orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов. -
amountLable— отформатированная цена покупки, включая валютный знак. -
amount— цена в минимальных единицах валюты. -
currency— код валюты ISO 4217. -
quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров. -
purchaseState— состояние покупки:CREATED— покуп ка создана;INVOICE_CREATED— создан счет на оплату, покупка ожидает оплаты;PAID— только для покупки потребляемого товара — промежуточный статус, средства на счете покупателя зарезервированы. Покупка ожидает подтверждения от разработчика;CONFIRMED— платеж за непотребляемый товар успешно совершен;CONSUMED— платеж за потребляемый товар успешно совершен;CANCELLED— покупка отменена — оплата не была произведена или был совершен возврат средств покупателю (для подписок после возврата средств покупка не переходит вCANCELLED);PAUSED— для подписок — подписка перешла в HOLD период.TERMINATED— подписка закрылась.
-
developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование). -
subscriptionToken— токен для валидации покупки на с ервере.
Получение списка покупок
- Kotlin
- Java
Метод возвращает только покупки со статусами из таблицы ниже. Подробнее о других возможных состояниях покупки смотрите в разделе Получение сведений о покупке.
| Тип/Статус | INVOICE_CREATED | CONFIRMED | PAID | PAUSED |
|---|---|---|---|---|
CONSUMABLE | + | + | ||
NON-CONSUMABLE | + | + | ||
SUBSCRIPTION | + | + | + |
Метод возвращает незавершенные состояния покупки и покупки потребляемых товаров, требующих обработки. Помимо этого, он показывает подтвержденные покупки для подписок и непотребляемых товаров — тех, которые нельзя купить повторно.
Для получения списка покупок пользователя используйте метод getPurchases.
val purchasesUseCase: PurchasesUseCase = billingClient.purchases
purchasesUseCase.getPurchases()
.addOnSuccessListener { purchases: List<Purchase> ->
// Process success
}
.addOnFailureListener { throwable: Throwable ->
// Process error
}
Структура покупки
data class Purchase(
val purchaseId: String?,
val productId: String,
val productType: ProductType?,
val invoiceId: String?,
val description: String?,
val language: String?,
val purchaseTime: Date?,
val orderId: String?,
val amountLabel: String?,
val amount: Int?,
val currency: String?,
val quantity: Int?,
val purchaseState: PurchaseState?,
val developerPayload: String?,
val subscriptionToken: String?
)
purchaseId— идентификатор покупки.productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).productType— тип продукта (потребляемый / непотребляемый / подписка):CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION.invoiceId— идентификатор счета.description— описание на языкеlanguage.language— язык, указанный с помощью BCP 47 кодирования.purchaseTime— время покупки.orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.amountLable— отформатированная цена покупки, включая валютный знак.amount— цена в минимальных единицах валюты.currency— код валюты ISO 4217.quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.purchaseState— состояние покупки.
Структура ответа сервера на запрос покупок
data class PurchasesResponse(
override val meta: RequestMeta?,
override val code: Int,
override val errorMessage: String?,
override val errorDescription: String?,
override val errors: List<DigitalShopGeneralError>?,
val purchases: List<Purchase>?,
) : ResponseWithCode
meta— дополнительная информация о запросе.code— код ответа.errorMessage— сообщение об ошибке для пользователя.errorDescription— расшифровка сообщения об ошибке.errors— список ошибок для запрошенных продуктов.purchases— список запрошенных покупок.
Метод возвращает только покупки со статусами из таблицы ниже. Подробнее о других возможных состояниях покупки смотрите в разделе Получение сведений о покупке.
| Тип/Статус | INVOICE_CREATED | CONFIRMED | PAID | PAUSED |
|---|---|---|---|---|
CONSUMABLE | + | + | ||
NON-CONSUMABLE | + | + | ||
SUBSCRIPTION | + | + | + |
Метод возвращает незавершенные состояния покупки и покупки потребляемых товаров, требующих обработки. Помимо этого, он показывает подтвержденные покупки для подписок и непотребляемых товаров — тех, которые нельзя купить повторно.
Для получения списка покупок пользователя используйте метод getPurchases.
PurchasesUseCase purchasesUseCase = billingClient.getPurchases();
purchasesUseCase.getPurchases()
.addOnSuccessListener(purchases ->
// Process PaymentResult
)
.addOnFailureListener(throwable ->
// Process error
);
Структура покупки
public Purchase(
@Nullable
String purchaseId,
String productId,
@Nullable
ProductType productType,
@Nullable
String invoiceId,
@Nullable
String description,
@Nullable
String language,
@Nullable
Date purchaseTime,
@Nullable
String orderId,
@Nullable
String amountLabel,
@Nullable
Integer amount,
@Nullable
String currency,
@Nullable
Integer quantity,
@Nullable
PurchaseState purchaseState,
@Nullable
String developerPayload,
@Nullable
String subscriptionToken
) {
this.purchaseId = purchaseId;
this.productId = productId;
this.productType = productType;
this.invoiceId = invoiceId;
this.description = description;
this.language = language;
this.purchaseTime = purchaseTime;
this.orderId = orderId;
this.amountLabel = amountLabel;
this.amount = amount;
this.currency = currency;
this.quantity = quantity;
this.purchaseState = purchaseState;
this.developerPayload = developerPayload;
this.subscriptionToken = subscriptionToken;
}
purchaseId— идентификатор покупки.productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).productType— тип продукта (потребляемый / непотребляемый / подписка):CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION.invoiceId— идентификатор счета.description— описание на языкеlanguage.language— язык, указанный с помощью BCP 47 кодирования.purchaseTime— время покупки.orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.AmountLabel— отформатированная цена покупки, включая валютный знак.amount— цена в минимальных единицах валюты.currency— код валюты ISO 4217.quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.purchaseState— состояние покупки.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование).subscriptionToken— токен для валидации покупки на сервере.
Проверка доступности работы с платежами
- Kotlin
- Java
Во время проверки доступности платежей проверяются следующие условия.
- На устройстве пользователя установлена актуальная версия RuStore.
- Приложение RuStore поддерживает функциональность платежей.
- Пользователь авторизован в RuStore.
Пользователь и приложение не должны быть заблокированы в RuStore.
.Для приложения включена возможность покупок в RuStore Консоли.
.
Проверка доступности платежей зависит от наличия RuStore на устройстве пользователя. Если у пользователя не установлено приложение RuStore, метод вернет FeatureAvailabilityResult.Unavailable.
Метод устарел и не рекомендуется к использованию.
Для проверки доступности платежей используйте метод
checkPurchasesAvailability.
FeatureAvailabilityResult.Available.
В противном случае возвращается FeatureAvailabilityResult.Unavailable(val cause: RuStoreException), где cause — это ошибка о невыполненном условии.
Все возможные о шибки RuStoreException описаны в разделе Обработка ошибок. Прочие ошибки возвращаются в onFailure. (См. Task API).
RuStoreBillingClient.checkPurchasesAvailability(context)
.addOnSuccessListener { result ->
when (result) {
FeatureAvailabilityResult.Available -> {
// Process purchases available
}
is FeatureAvailabilityResult.Unavailable -> {
// Process purchases unavailable
}
}
}
.addOnFailureListener { throwable ->
// Process unknown error
}
context — контекст Android.
Во время проверки доступности платежей проверяются следующие условия.
- На устройстве пользователя установлена актуальная версия RuStore.
- Приложение RuStore поддерживает функциональность платежей.
- Пользователь авторизован в RuStore.
Пользователь и приложение не должны быть заблокированы в RuStore.
.Для приложения включена возможность покупок в RuStore Консоли.
.
Проверка доступности платежей зависит от наличия RuStore на устройстве пользователя. Если у пользователя не установлено приложение RuStore, метод вернет FeatureAvailabilityResult.Unavailable.
Метод устарел и не рекомендуется к использованию.
Для проверки доступности платежей используйте метод
checkPurchasesAvailability.
FeatureAvailabilityResult.Available.
В противном случае возвращается FeatureAvailabilityResult.Unavailable(val cause: RuStoreException), где cause — это ошибка о невыполненном условии.
Все возможные ошибки RuStoreException описаны в разделе Обработка ошибок. Прочие ошибки возвращаются в onFailure. (См. Task API).
RuStoreBillingClientExtKt.checkPurchasesAvailability(RuStoreBillingClient.Companion, getContext())
.addOnSuccessListener(result -> {
if (result instanceof FeatureAvailabilityResult.Available) {
// Hanlde purchases available
} else {
RuStoreException exception = ((FeatureAvailabilityResult.Unavailable) result).getCause();
// Hanlde purchases unavailable
}
})
.addOnFailureListener(error -> {
// Handling error
});
Смена темы интерфейса
- Kotlin
- Java
SDK поддерживает динамическую смены темы через интерфейс провайдера BillingClientThemeProvider.
val billingClient: RuStoreBillingClient = RuStoreBillingClientFactory.create(
context = app,
consoleApplicationId = "111111",
deeplinkScheme = "yourappscheme",
themeProvider? = BillingClientThemeProviderImpl(),
)
class BillingClientThemeProviderImpl: BillingClientThemeProvider {
override fun provide(): BillingClientTheme {
// Тут должна размещаться логика по проверке установленной темы
val darkTheme = ....
if(darkTheme){
BillingClientTheme.Dark
} else {
BillingClientTheme.Light
}
}
}
SDK подде рживает динамическую смены темы через интерфейс провайдера BillingClientThemeProvider.
final Context context = getContext();
final String consoleApplicationId = "111111";
final String deeplinkScheme = "yourappscheme";
final BillingClientThemeProvider themeProvider = BillingClientThemeProviderImpl();
RuStoreBillingClient billingClient = RuStoreBillingClientFactory.INSTANCE.create(
context,
consoleApplicationId,
deeplinkScheme,
themeProvider
);
public class BillingClientThemeProviderImpl implements BillingClientThemeProvider {
@NonNull
@Override
public BillingClientTheme provide() {
// Тут должна размещаться логика по проверке установленной темы
boolean darkTheme = ...;
if (darkTheme) {
return BillingClientTheme.Dark;
} else {
return BillingClientTheme.Light;
}
}
}
Обработка ошибок
- Kotlin
- Java
Возможные ошибки
RuStoreNotInstalledException— на устройстве пользователя не установлен RuStore;RuStoreOutdatedException— версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK;RuStoreUserUnauthorizedException— пользователь не авторизован в RuStore;RuStoreRequestLimitReached— с момента последнего отображения процесса прошло слишком мало времени;RuStoreReviewExists— этот пользователь уже оценил ваше приложение;RuStoreInvalidReviewInfo— проблемы сReviewInfo;RuStoreException— базовая ошибка RuStore, от которой наследуются остальные ошибки.
RuStoreBillingClient.purchases.purchaseProduct() ошибки обрабатываются автоматически.
Метод устарел и не рекомендуется к использованию.
Для показа диалога с ошибкой пользователю используйте метод
resolveForBilling
public fun RuStoreException.resolveForBilling(context: Context)
Возможные ошибки
RuStoreNotInstalledException— на устройстве пользователя не ус тановлен RuStore;RuStoreOutdatedException— версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK;RuStoreUserUnauthorizedException— пользователь не авторизован в RuStore;RuStoreRequestLimitReached— с момента последнего отображения процесса прошло слишком мало времени;RuStoreReviewExists— этот пользователь уже оценил ваше приложение;RuStoreInvalidReviewInfo— проблемы сReviewInfo;RuStoreException— базовая ошибка RuStore, от которой наследуются остальные ошибки.
RuStoreBillingClient.purchases.purchaseProduct() ошибки обрабатываются автоматически.
Метод устарел и не рекомендуется к использованию.
Для показа диалога с ошибкой пользователю используйте метод
resolveForBilling
BillingRuStoreExceptionExtKt.resolveForBilling(exception, getContext());
Коды ошибок
Ниже представлено описание возможных ошибок в поле errorCode.
| HTTP-код | Код ошибки | Описание |
|---|---|---|
400 | 40001 | Параметры запроса неверны — не заполнены обязательные параметры/неверный формат параметров. |
400 | 40003 | Приложение не найдено. |
400 | 40004 | Статус приложения inactive. |
400 | 40005 | Продукт не найден. |
400 | 40006 | Статус продукта inactive. |
400 | 40007 | Недопустимый тип продукта. Поддерживаемые типы: consumable, non-consumable, subscription. |
400 | 40008 | Покупка с таким order_id уже существует. |
400 | 40009 | У текущего клиента найдена покупка этого продукта со статусом invoice_created. Необходимо предложить клиенту оплатить/отменить покупку. |
400 | 40010 | Для типа продукта consumable. У текущего клиента найдена покупка этого продукта со статусом paid. Сначала требуется подтвердить потребление покупки на устройстве, а затем можно отправлять следующий запрос на покупку этого продукта. |
400 | 40011 | Для типа продукта non-consumable. У текущего клиента найдена покупка этого продукта со статусом pre_confirmed/confirmed. Такой продукт уже приобретен. Более одного раза продукт не продается. |
400 | 40012 | Для типа продукта subscription. У текущего клиента найдена покупка этого продукта со статусом pre_confirmed/confirmed. Такой продукт уже приобретен. Более одного раза продукт не продается. |
400 | 40013 | Для типа продукта subscription. При обращении в сервис подписок за списком продуктов GET/products (serviceId, user_id) данные не были получены. |
400 | 40014 | Обязательный атрибут(-ы) не пришел в запросе. |
400 | 40015 | Не удалось изменить статус при обновлении покупки (переход запрещен). |
400 | 40016 | При покупке подписки непотребляемого продукта указано значение quantity > 1. |
400 | 40017 | Продукт удален, новые покупки не доступны. |
400 | 40018 | Нельзя подтверждать продукт с типом тип продукта. |
401 | 40101 | Невалидный токен. |
401 | 40102 | Время жизни токена истекло. |
403 | 40301 | Доступ к запрашиваемому ресурсу запрещен (неавторизованно). |
403 | 40302 | Для текущего токена текущий вызов не авторизован (метод запрещен). |
403 | 40303 | Идентификатор приложения в запросе и токен не совпадают. |
403 | 40305 | Неверный тип токена. |
404 | 40401 | Не найдено. |
408 | 40801 | Истекло время ожидания уведомления, указанное в запросе. |
500 | 50*** | Внутренняя ошибка платежного сервиса. |