Поддержка BillingClient SDK прекращается 1 августа 2026 года. После 1 августа 2026 года платежи перестанут обрабатываться для всех покупок, включая подписки.
До этого времени BillingClient SDK продолжает свою работу, но устранение неисправностей, влияющих на работу платежей, может занимать больше времени. Новая функциональность добавляться не будет.
Рекомендуем использовать Pay SDK в проектах.
Для перехода на Pay SDK воспользуйтесь инструкцией по миграции.
8.0.0
RuStore позволяет интегрировать платежи в мобильное приложение.
Если не знаете с чего начать, прочтите инструкцию в сценариях использования.
Пример реализации
Ознакомьтесь с приложением-примером чтобы узнать, как правильно интегрировать SDK платежей.
Условия работы платежей
- На устройстве пользователя установлена актуальная версия RuStore.
- Пользователь авторизован в RuStore.
- Пользователь и приложение не должны быть заблокированы в RuStore.
- Для приложения включена возможность покупок в RuStore Консоли.
Подготовка к работе
Для подключения пакета платежей к пр оекту выполните следующую команду.
flutter pub add flutter_rustore_billing
dependencies: flutter_rustore_billing: ^8.0.0
Обработка deeplink
Использование deeplink в RuStore SDK позволяет эффективно взаимодействовать со сторонними приложениями, например, при проведении платежей через б анковские приложения (СБП, SberPay, T-Pay и др.). Это позволяет перевести пользователя на экран оплаты, а после завершения транзакции — вернуть в ваше приложение.
Для настройки работы с deeplink в вашем приложении и RuStore SDK, укажите deeplinkScheme
внутри вашего AndroidManifest файла и переопределите метод onNewIntent вашего Activity.
<activity
android:name=".sample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="yourappscheme"/>
</intent-filter>
</activity>
Вместо yourappscheme из примера выше укажите название своей схемы. Например, ru.package.name.rustore.scheme.
Схема, указанная в AndroidManifest файле должна совпадать со схемой,
которую вы указываете в методе create RuStore SDK платежей.
Инициализация
Перед вызовом методов библиотеки необходимо выполнить ее инициализацию. Сама инициализация происходит автоматически, но для работы SDK в вашем файле необходимо прописать
Для инициализации вызовите метод RustoreBillingClient.initialize().
RustoreBillingClient.initialize(
"123456", //consolApplicationId
"yourappscheme", //deeplinkScheme
).then((value) {
print("initialize success: $value");
}, onError: (err) {
print("initialize err: $err");
}
);
-
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 генерирует свой хост к данной схеме.
deeplinkScheme, должна совпадать со схемой, указанной в AndroidManifest.xml (подробнее см. Обработка deeplink).Как работают платежи
Проверка доступности работы с платежами
Во время проверки доступности платежей проверяются следующие условия.
- На устройстве пользователя должен быть установлен RuStore.
- RuStore должен поддерживать функциональность платежей.
- Пользователь должен быть авторизован в RuStore.
- Пользователь и приложение не должны быть заблокированы в RuStore.
- Для приложения должна быть включена возможность покупок в консоли разработчика RuStore.
- В данной версии SDK метод будет возвращать сообщение о доступности платежа.
RustoreBillingClient.available().then((value) {
value.when(
available: () => // Process purchases available,
unknown: () => // Process purchases unknown,
unavailable: (e) => // Process purchases unavailable,
);
}, onError: (err) {
print("available err: $err");
});
Проверка наличия RuStore на устройстве
Метод isRuStoreInstalled применяется для проверки, установлен ли RuStore на устройстве пользователя. Эта проверка нужна для реализации корректной логики работы с товарами и покупками.
RustoreBillingClient.isRustoreInstalled().then((value) {
print("isRustoreInstalled $value");
}, onError: (err) {
print("isRustoreInstalled err: $err");
});
Приведенные ниже методы SDK платежей требуют авторизации пользователя:
- RustoreBillingClient.products(ids)
- RustoreBillingClient.purchases()
- RustoreBillingClient.purchase(id)
Если на устройстве пользователя не установлен RuStore, всякий раз будет отображаться шторка веб-авторизации, что может негативно сказаться на пользовательском опыте.
Проверка наличия авторизации у пользователя
RustoreBillingClient.getAuthorizationStatus().then((value) {
print("getAuthorizationStatus $value");
}, onError: (err) {
print("getAuthorizationStatus err: $err");
});
Методы SDK
Получение списка продуктов
Вы проверили, что платежи доступны и пользователи могут совершать покупки. Теперь можно получить список продуктов. Используйте метод RustoreBillingClient.products(ids), чтобы получить информацию о продуктах, добавленных в ваше приложение через RuStore Консоль.
RustoreBillingClient.products(ids).then((response) {
for (final product in response.products) {
print(product?.productId);
}
}, onError: (err) {
print("products err: $err");
}
);
ids: List<String?> — список идентификаторов продуктов. В нем не должно быть более 100 позиций.
Чтобы указать id продуктов, которые нужны для работы метода, выполните следующие действия.
- Откройте RuStore Консоль.
- Перейдите на вкладку Приложения.
- Выберите нужное приложение.
- В левом боковом меню выберите раздел Монетизация.
- Выберите тип товара: Подписки или Разовые покупки.
- Скопируйте идентификаторы нужных товаров. Это и есть
idпродукт ов.

Метод возвращает ProductsResponse
class ProductsResponse {
int code;
String? errorMessage;
String? errorDescription;
String? traceId;
List<Product?> products;
List<DigitalShopGeneralError?> errors;
}
code— код ответа.errorMessage— сообщение об ошибке для пользователя.errorDescription— расшифровка сообщения об ошибке.traceId— идентификатор ошибки.errors— список ошибок для запрошенных продуктов.products— список продуктов.
Структура ошибки DigitalShopGeneralError
class DigitalShopGeneralError {
String? name;
int ? code;
String? description
}
name– имя ошибки.code— код ошибки.description– описание ошибки.
Структура продукта Product
class Product {
String productId;
String? productType;
String productStatus;
String? priceLabel;
int ? price;
String? currency;
String? language;
String? title;
String? description;
String? imageUrl;
String? promoImageUrl;
Subscription? subscription;
}
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.
Структура подписки Subscription
class Subscription {
SubscriptionPeriod? subscriptionPeriod;
SubscriptionPeriod? freeTrialPeriod;
SubscriptionPeriod? gracePeriod;
String? introductoryPrice;
String? introductoryPriceAmount;
SubscriptionPeriod? introductoryPricePeriod;
}
subscriptionPeriod— период подписки.freeTrialPeriod— пробный период подписки.gracePeriod— льготный период подписки.introductoryPrice— отформатированная вступительная цена подписки, включая знак валюты, на языкеproduct:language.introductoryPriceAmount— вступительная цена в минимальных единицах валюты (в копейках).introductoryPricePeriod— расчетный период вступительной цены.
Структура периода подписки SubscriptionPeriod
class SubscriptionPeriod {
int years;
int months;
int days;
}
years— количество лет.months— количество месяцев.days— количество дней.
Покупка продукта
Для вызова покупки продукта используйте метод RustoreBillingClient.purchase(id).
RustoreBillingClient.purchase(id, developerPayload: developerPayload, orderId: orderId).then((response) {
print("purchase success: $response");
}, onError: (err) {
print("purchase err: $err");
}
);
id — идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр)
Структура результата покупки PaymentResult
class PaymentResult {
SuccessInvoice? successInvoice;
InvalidInvoice? invalidInvoice;
SuccessPurchase? successPurchase;
InvalidPurchase? invalidPurchase;
}
Структура SuccessInvoice
class SuccessInvoice {
String invoiceId;
String finishCode;
}
Структура InvalidInvoice
class InvalidInvoice {
String? invoiceId;
}
Структура SuccessPurchase
class SuccessPurchase {
String finishCode;
String? orderId;
String purchaseId;
String productId;
String? invoiceId;
String? subscriptionToken;
bool? sandbox;
}
Структура InvalidPurchase
class InvalidPurchase {
String? purchaseId;
String? invoiceId;
String? orderId;
int? quantity;
String? productId;
int? errorCode;
bool? sandbox;
}
SuccessInvoice— платежи завершились с результатом.InvalidInvoice— платежи завершились без указания номера счета. Вероятно, они были запущены с некорректным номером счета (пустая строка, например).SuccessPurchase— результат успешного завершения покупки цифрового товара.InvalidPurchase— при оплате цифрового товара платежи завершились с ошибкой.
Возможные статусы, которые может содержать finishCode
SUCCESSFUL_PAYMENT— успешная оплата.CLOSED_BY_USER— отменено пользователем.UNHANDLED_FORM_ERROR— неизвестная ошибка.PAYMENT_TIMEOUT— ошибка оплаты по таймауту.DECLINED_BY_SERVER— отклонено сервером.RESULT_UNKNOWN— неизвестный статус оплаты.
Получение списка покупок
Метод возвращает только покупки со статусами из таблицы ниже. Подробнее о других возможных состояниях покупки смотрите в разделе Получение сведений о покупке.
| Тип/Статус | INVOICE_CREATED | CONFIRMED | PAID | PAUSED |
|---|---|---|---|---|
CONSUMABLE | + | + | ||
NON-CONSUMABLE | + | + | ||
SUBSCRIPTION | + | + | + |
Метод возвращает незавершенные состояния покупки и покупки потребляемых товаров, требующих обработки. Помимо этого, он показывает подтвержденные покупки для подписок и непотребляемых товаров — тех, которые нельзя купить повторно.
Для получения списка покупок пользователя используйте метод RustoreBillingClient.purchases.
RustoreBillingClient.purchases().then((response) {
for (final product in response.purchases) {
print(product?.purchaseId);
}
}, onError: (err) {
print("purchases err: $err" );
}
);
Метод возвращает PurchasesResponse (см. ниже).
class PurchasesResponse {
int code;
String? errorMessage;
String? errorDescription;
String? traceId;
List<Purchase?> purchases;
List<DigitalShopGeneralError?> errors;
}
code— код ответа.errorMessage— сообщение об ошибке для пользователя.errorDescription— расшифровка сообщения об ошибке.errors— список ошибок для запрошенных продуктов.purchases— список запрошенных покупок.
Структура ошибки DigitalShopGeneralError (см. ниже).
class DigitalShopGeneralError {
String? name;
int ? code;
String? description;
}
name– имя ошибки.code— код ошибки.description– описание ошиб ки.
class Purchase {
String? purchaseId;
String? productId;
String? productType;
String? language;
String? purchaseTime;
String? orderId;
String? amountLabel;
int? amount;
String? currency;
int? quantity;
String? purchaseState;
String? developerPayload;
String? invoiceId;
String? subscriptionToken;
}
Структура покупки Purchase (см. ниже).
purchaseId— идентификатор покупки.productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).description— описание на языкеlanguage.language— язык, указанный с помощью BCP 47 кодирования.purchaseTime— время покупки.orderId— уникальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.amountLable— отформатированная цена покупки, включая валютный знак.amount— цена в минимальных единицах валюты.currency— код валюты ISO 4217.quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.purchaseState— состояние покупки.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование).
Получение сведений о покупке
Для получения информации о покупке, используйте методpurchaseInfo.
RustoreBillingClient.purchaseInfo(purchaseId).then((purchase) {
print(purchase);
}, onError: (err) {
print("Error getPurchaseInfo: $err");
}
);
Структура покупки Purchase (см. ниже).
class Purchase {
String? purchaseId;
String? productId;
String? productType;
String? language;
String? purchaseTime;
String? orderId;
String? amountLabel;
int? amount;
String? currency;
int? quantity;
String? purchaseState;
String? developerPayload;
String? invoiceId;
String? subscriptionToken;
}
purchaseId— идентификатор покупки.productId— идентификатор продукта, который был присвоен продукту в RuStore Консоли (обязательный параметр).description— описание на языкеlanguage.language— язык, указанный с помощью BCP 47 кодирования.purchaseTime— время покупки.orderId— уни кальный идентификатор оплаты, сформированный приложением (опциональный параметр). Если вы укажете этот параметр в вашей системе, вы получите его в ответе при работе с API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.amountLable— отформатированная цена покупки, включая валютный знак.amount— цена в минимальных единицах валюты.currency— код валюты ISO 4217.quantity— количество продукта. Необязательный параметр со стандартным значением1. Применим только к покупке потребляемых товаров.purchaseState— состояние покупки.developerPayload— строка с дополнительной информацией о заказе, которую вы можете установить при подтверждении покупки. Эта строка переопределяет значение, заданное при инициализации. Максимальная длина 250 символов. Символы не экранируются (при использовании кавычек требуется экранирование).
Статусная модель (purchaseState)
Статусная модель покупки потребляемых продуктов (CONSUMABLES)
Статусная модель покупки непотребляемых продуктов (NON-CONSUMABLES)
Статусная модель покупки подписок (SUBSCRIPTIONS)
Подтверждение (потребление) покупки
Продукты, требующие подтверждения (потребления)
Учитывайте тип покупки. Метод подтверждения (потребления) необходим, только если у вас потребляемый товар (CONSUMABLE), который можно купить много раз.
Чтобы такие товары начислились пользователям без ошибок, подтвердите подтверждение (потребление) продукта с помощью метода confirmPurchase.
При начислении товара в вашем приложении используйте серверную валидацию платежей. Начисляйте товар только когда платеж (счет) перейдет в финальный статус CONFIRMED.
Начисление продуктов пользователям надо делать в callback addOnSuccessListener метода confirmPurchase.
Статус PAID является промежуточным и означает, что средства пользователя захолдированы на карте и вам нужно подтвердить покупку.
Исключение — платежи через СБП или со счета телефона: при этих способах оплаты используется одностадийный платеж, но модель счета остается двухстадийной. Подробнее см. пояснения ниже.
При оплате потребляемых (CONSUMABLE) товаров через СБП или со счета телефона используется одностадийный платеж, при этом модель счета остается двухстадийной. Это значит, что при переходе счета в статус PAID при оплате через СБП или со счета мобильного телефона деньги уже списаны со счета покупателя, а с разработчика удержана комиссия. В этом случае при отмене покупки в состоянии PAID происходит возврат средств (refund), а не отмена холдирования — reverse. Удержанная комиссия разработчику не возвращается. При этом для завершения покупки все равно нужно выполнить метод подтверждения (потребления) — см. также таблицу ниже.
| Платежный метод | Тип платежа | Платеж в статусе PAID |
|---|---|---|
| Двухстадийный |
|
| Одностадийный |
|
Вызов метода подтверждения (потребления)
Для подтверждения (потребления) покупки используйте методRustoreBillingClient.confirm(id). Запрос на подтверждение (потребление) покупки должен сопровождаться выдачей товара. После вызова подтверждения покупка перейдет в статус CONSUMED.
RustoreBillingClient.confirm(id).then((response) {
print( "confirm success: $response" );
}, onError: (err) {
print( "confirm err: $err" );
}
);
id— идентификатор покупки.
Метод возвращает ConfirmPurchaseResponse (см. ниже).
class ConfirmPurchaseResponse {
int code;
String? errorMessage;
String? errorDescription;
String? traceId;
List<DigitalShopGeneralError?> errors;
}
code— код ответа.errorMessage— сообщение об ошибке для пользователя.errorDescription— расшифровка сообщения об ошибке.traceId— идентификатор ошибки.errors— список ошибок для запрошенных продуктов.
Структура ошибки DigitalShopGeneralError (см. ниже).
class DigitalShopGeneralError {
String? name;
int ? code;
String? description;
}
name– имя ошибки.code— код ошибки.description– описание ошибки.
Отмена покупки
Для отмены покупки используйте метод deletePurchase.
RustoreBillingClient.deletePurchase(purchaseId = "purchaseId").then(() {
print("Delete success");
}, onError: (err) {
print("Error getPurchaseInfo: $err");
}
);
purchaseId— идентификатор покупки.
Используйте метод отмены покупки с осторожностью и только в исключительных случаях, только если покупка осталась в статусе PAID, а вы не можете выдать товар пользователю. В остальных случаях не рекомендуется вручную отменять покупки, так как RuStore автоматически обрабатывает незавершенные покупки (например, таймаут в 20 минут или повторная покупка от того же клиента).
При оплате покупки через СБП или со счета мобильного телефона отмена покупки в статусе PAID не отменяет холдирование, а приводит к возврату средств (refund). При этом с разработчика удерживается комиссия, которая не возвращается.
Валидация покупки на сервере
Если вам необходимо произвести валидацию успешной покупки на сервере методами API RuStore, вы можете использовать subscriptionToken в PurchaseResult, возвращаемой purchaseProduct при успешной покупке продукта.
SubscriptionToken состоит из invoiceId покупки и userId, записанных через точку: $invoiceId.$userId.
Также можно получить subscriptionToken в сущности Purchase. Сущность Purchase можно получить, используя метод purchases().
Ведение журнала событий
Логирование включено по умолчанию внутри flutter sdk. Логи вы можете смотреть по тегу RuStoreFlutterBillingPlugin.
Обработка ошибок
Возможные ошибки
RuStorePaymentNetworkException— ошибка сетевого взаимодействия SDK;RuStorePaymentCommonException— общая ошибка SDK;RuStorePayClient.instanceAlreadyExist— ошибка повторной инициализации SDK;-
RuStorePayClient.instanceNotCreated— попытка обратиться к публичным интерфейсам SDK до момента ее инициализации RuStorePayInvalidActivePurchase— запущен процесс оплаты неизвестного типа продукта;RuStorePayInvalidConsoleAppId— не задан обязательный параметрсonsole_application_idдля инициализации SDK;RuStorePaySignatureException— неверная сигнатура ответа (возникает при попытке совершить мошеннические действия);EmptyPaymentTokenException— ошибка получения платежного токена;RuStoreNotInstalledException— на устройстве пользователя не установлен RuStore;RuStoreOutdatedException— версия RuStore, установленная на устройстве пользователя, не поддерживает данный SDK;RuStoreUserUnauthorizedException— пользователь не авторизован в RuStore;RuStoreApplicationBannedException— приложение заблокировано в RuStore;RuStoreUserBannedException— пользователь заблокирован в RuStore;RuStoreException— базовая ошибка RuStore, от которой наследуются остальные ошибки.
По умолчанию в плагине включена нативная обработка ошибок, в случае возникновения ошибки выполняются эти действия:
-
Вызовется соответствующий обработчик ошибки.
-
Ошибка передается в метод
resolveForBillingнативного SDK. Это нужно, чтобы показать пользователю диалог с ошибкой.
fun RuStoreException.resolveForBilling(context: Context)
Чтобы отключить передачу ошибки в нативный SDK, вызовите функцию offNativeErrorHandling.
RustoreBillingClient.offNativeErrorHandling();