Skip to main content

5.0.0

With RuStore you can integrate payments in your mobile app.

tip

If you are in doubt read the instruction in the usage scenarios.

Implementation example

Look at the example app to learn how to integrate our SDK.

Prerequisites

  • App uploaded to RuStore Console.
  • App passed moderation (you don't have to publish the app).
Important
  • Test build signature (for example: debug) of the app must match the signature of the app build that was uploaded to the console and passed moderation (for example, release).
  • The current version of RuStore is installed on the user's device.
  • User is authorized in RuStore.
  • The user and the app are not banned in RuStore.
  • In-app purchases for the app are enabled in RuStore Console.
caution

The service has some restrictions to work outside of Russia.

Getting started

  1. Copy the plugin and the sample app projects from the official RuStore repository on GitFlic.
  2. Open the Android project from the godot_plugin_libraries folder in your IDE.
  3. In the godot_plugin_plugin_libraries/libs folder, save the godot-lib.xxx.yyy.template_release.aar package, where xxx.yyyy is the version of your Godot Engine edition.
  4. Build the project via gradle assemble command.

If the build is successful, the following files will be created in godot_example/android/plugins.

  • RuStoreGodotBilling.gdap;
  • RuStoreGodotBilling.aar;
  • RuStoreGodotCore.gdap;
  • RuStoreGodotCore.aar.
caution

Note that the plugin libraries must be built for your version of the Godot engine.

  1. Copy the contents of godot_example/android/plugins to your_project/android/plugins.
  2. In the Plug-ins list of the Android build preset select Ru Store Godot Billing and Ru Store Godot Core.

RuStore SDK uses deeplink to handle third-party payment applications. This makes it easier to pay with third-party apps and return to your app.

To configure deeplinks functionality in your app and RuStore SDK, define deeplinkScheme in your AndroidManifest file and redefine the onNewIntent method of your activity.

<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
android:theme="@style/GodotAppSplashTheme"
android:excludeFromRecents="false"
android:exported="true"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
android:resizeableActivity="false"
tools:ignore="UnusedAttribute" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<!-- your app scheme -->
<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>

Replace yourappscheme in the example above with the name of your scheme. For example, ru.package.name.rustore.scheme.

info

The scheme defined in the Androidmanifest file must match the scheme you specify in the create method of the RuStore SDK billing.

Initialization

Initialize the library before calling its methods.

For initialization, call the init method.
const APPLICATION_ID = "123456"
const DEEPLINK_SCHEME = "yourappscheme"
const DEBUG_LOGS = false

var _billing_client: RuStoreGodotBillingClient = null

func _ready():
_billing_client = RuStoreGodotBillingClient.get_instance()
_billing_client.init(APPLICATION_ID, DEEPLINK_SCHEME, DEBUG_LOGS)
  • APPLICATION_ID — application code from the RuStore Console (example: https://console.rustore.ru/apps/123456).
  • DEEPLINK_SCHEME — the deeplink scheme required to return to your app after paying with a third party app (for example: SberPay or SBP). SDK generates its host for this scheme.
  • DEBUG_LOGS — flag controls logging (logging will be automatically disabled for Release builds).
note
  • ApplicationId specified in build.gradle must match applicationId of the APK file that you published in the RuStore Console.
  • The deeplink scheme passed in deeplinkScheme must match the scheme specified in AndroidManifest.xml in section Deeplink processing.
  • The keystore signature must match the signature used to sign the app that was published in the RuStore Console. Make sure that buildType used (example: debug) uses the same signature as the published app (example: release).

After plugin initialization, all available signals are connected.

Before you start

Payment appRuStore Server RuStore_Billing_ClientYour serverYour appUserPayment appRuStore Server RuStore_Billing_ClientYour serverYour appUserPayments availability check[Optional]Server validation[Mandatory]Purchasing consumable product[Mandatory]Deeplink processing for paying with SBP, SberPay, etc.Product purchaseStarts your app checkPurchasesAvailabilityResult getProductsProducts list of your appDisplaying list of available purchasesPurchasing product purchaseProductRequest payment methodMaking paymentPayment methodPayment resultPayment infoServer validation (public API)Reliable purchase informationDeliver product to the userValidation result confirmPurchaseConsumption result purchaseProductRequest payment methodSpecified SBP/SberPay/T-PayStart payment processPayment scenarioPurchase paymentReturn to app OnNewIntentPayment resultDisplaying payment screen with the result

Payments availability check

During the purchases availability check, the following conditions are verified.

  • The current version of RuStore is installed on the user's device.
  • RuStore app supports payments.
  • User is authorized in RuStore.
  • The user and the app are not banned in RuStore.
  • In-app purchases for the app are enabled in RuStore Console.
To check payments availability, use the check_purchases_availability method.

You must subscribe to events once before using this method:

  • on_check_purchases_availability_success;
  • on_check_purchases_availability_failure.
Subscription to events
func _ready():
# `_billing_client` initialization

_billing_client.on_check_purchases_availability_success(_on_check_purchases_availability_success)
_billing_client.on_check_purchases_availability_failure(_on_check_purchases_availability_failure)

func _on_check_purchases_availability_success(result: RuStoreFeatureAvailabilityResult):
pass

func _on_check_purchases_availability_failure(error: RuStoreError):
pass
Calling check_purchases_availability
_billing_client.check_purchases_availability()

The on_check_purchases_availability_success callback returns the RuStoreFeatureAvailabilityResult object with the information about service availability.

class_name RuStoreFeatureAvailabilityResult extends Object

var isAvailable: bool
var cause: RuStoreError

func _init(json: String = ""):
if json == "":
isAvailable = false
cause = RuStoreError.new()
else:
var obj = JSON.parse_string(json)
isAvailable = obj["isAvailable"]
cause = RuStoreError.new(json)
  • isAvailable — compliance with the payments availability conditions (true/false).
  • cause — error information.

The on_check_purchases_availability_failure callback returns the RuStoreError object that contains all other errors, for example: "no Internet connection".

Working with SDK

Retrieving products list

You verified that payments are available and the users are able to make purchases. Now you can request products list. Use the getProducts method to request the information about products added to your app in RuStore Console.

You must subscribe to events once before using this method:

  • on_get_products_success;
  • on_get_products_failure.
Subscription to events
func _ready():
# `_billing_client` initialization

_billing_client.on_get_products_success(_on_get_products_success)
_billing_client.on_get_products_failure(_on_get_products_failure)

func _on_get_products_success(products: Array):
pass

func _on_get_products_failure(error: RuStoreError):
pass
Calling get_products
const PRODUCT_IDS = [
"123",
"non_con",
"con",
"sub"]

_billing_client.get_products(PRODUCT_IDS)

PRODUCT_IDS — the list of product IDs. Must not exceed 100 entries.

To specify id of the products needed for the method, do the following.

  1. Open RuStore Console.
  2. Navigate to the Applications tab.
  3. Select the necessary app.
  4. In the left side menu select Monetization.
  5. Select product type: Subscriptions or In-App purchases.
  6. Copy the IDs of the required products. These are product ids.

Maximum length — 2083 characters in the list.

The on_get_products_success callback returns the RuStoreProduct object list with the information about products.

class_name RuStoreProduct extends Object

var productId: String = ""
var productStatus: ERuStoreProductStatus.Item = 0
var productType: ERuStoreProductType.Item = 0
var priceLabel: String = ""
var price: int = 0
var currency: String = ""
var language: String = ""
var title: String = ""
var description: String = ""
var imageUrl: String = ""
var promoImageUrl: String = ""
var subscription: RuStoreProductSubscription = null

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
productId = obj["productId"]
productStatus = ERuStoreProductStatus.Item.get(obj["productStatus"])

if obj.has("productType"):
productType = ERuStoreProductType.Item.get(obj["productType"])

if obj.has("priceLabel"):
priceLabel = obj.get("priceLabel")

if obj.has("price"):
price = int(obj["price"])

if obj.has("currency"):
currency = obj.get("currency")

if obj.has("language"):
language = obj.get("language")

if obj.has("title"):
title = obj.get("title")

if obj.has("description"):
description = obj.get("description")

if obj.has("imageUrl"):
imageUrl = ""#obj["imageUrl"]

if obj.has("promoImageUrl"):
promoImageUrl = ""#obj["promoImageUrl"]

if obj.has("subscription"):
subscription = RuStoreProductSubscription.new(str(obj["subscription"]))

Below are the available product fields.

  • productId — product ID assigned to product in RuStore Console (mandatory).

  • productType — product type: CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION:

    • NON_CONSUMABLE — non-consumable (can be purchased only once, for example: disabling ads);
    • CONSUMABLE — consumable (can be bought more than once, for example: crystals in app);
    • SUBSCRIPTION — subscription (can be purchases for a period of time, for example: a streaming service subscription).
  • productStatus — product status:

    • ACTIVE — product is available for purchase;
    • INACTIVE — product cannot be purchased.
  • priceLable — formatted product price, including currency symbol in language.

  • price — price in minimum currency units.

  • currency — ISO 4217 currency code.

  • language — language specified with BCP 47 code.

  • title — product name in language.

  • description — descriptions in language.

  • imageUrl — image URL.

  • promoImageUrl — promo image URL.

  • subscription — subscription description, returns only for subscription products.

Subscription structure

class_name RuStoreProductSubscription extends Object

var subscriptionPeriod: RuStoreSubscriptionPeriod = null
var freeTrialPeriod: RuStoreSubscriptionPeriod = null
var gracePeriod: RuStoreSubscriptionPeriod = null
var introductoryPrice: String = ""
var introductoryPriceAmount: String = ""
var introductoryPricePeriod: RuStoreSubscriptionPeriod = null

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)

if obj.has("subscriptionPeriod"):
subscriptionPeriod = RuStoreSubscriptionPeriod.new(str(obj["subscriptionPeriod"]))

if obj.has("freeTrialPeriod"):
freeTrialPeriod = RuStoreSubscriptionPeriod.new(obj["freeTrialPeriod"])

if obj.has("gracePeriod"):
gracePeriod = RuStoreSubscriptionPeriod.new(obj["gracePeriod"])

if obj.has("introductoryPrice"):
introductoryPrice = obj["introductoryPrice"]

if obj.has("introductoryPriceAmount"):
introductoryPriceAmount = obj["introductoryPriceAmount"]

if obj.has("introductoryPricePeriod"):
introductoryPricePeriod = RuStoreSubscriptionPeriod.new(obj["introductoryPricePeriod"])
  • subscriptionPeriod — subscription period.
  • freeTrialPeriod — subscription trial period.
  • gracePeriod — subscription grace period.
  • introductoryPrice — formated introductory price with the currency symbol in the product:language language.
  • introductoryPriceAmount — introductory price in minimum currency units.
  • introductoryPricePeriod — introductory price invoice period.

Structure of the subscription period

class_name RuStoreSubscriptionPeriod extends Object

var days: int = 0
var months: int = 0
var years: int = 0

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
days = int(obj["days"])
months = int(obj["months"])
years = int(obj["years"])
  • days — amount of days.
  • months — amount of months.
  • years — amount of years.

The on_get_products_failure returns the RuStoreError object with the error information. The error structure is described in Error Handling.

Purchasing product

To purchase product, use the purchaseProduct method.

You must subscribe to events once before using this method:

  • on_purchase_product_success;
  • on_purchase_product_failure
Subscription to events
func _ready():
# `_billing_client` initialization

_billing_client.on_purchase_product_success(_on_purchase_product_success)
_billing_client.on_purchase_product_failure(_on_purchase_product_failure)

func _on_purchase_product_success(result: RuStorePaymentResult):
pass

func _on_purchase_product_failure(error: RuStoreError):
pass
Calling purchase_product
const PRODUCT_ID = "123"
const PARAMS = {
"order_id": "example_id",
"quantity": 1,
"payload": "Some payload"
}

_billing_client.purchase_product(PRODUCT_ID, PARAMS)
  • PRODUCT_ID — product ID assigned to product in RuStore Console (mandatory);

  • PARAMS — optional parameters:

    • orderId — order ID generated on the AnyApp side. (optional — if omitted, it is generated automatically);
    • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1) (optional);
    • developerPayload — string with additional order information, that you can specify on purchase initialization.

The on_purchase_product_success callback returns an inherited object of the RuStorePaymentResult class with the purchase information.

  • Success - successful purchase result.
  • Failure - there was a problem during sending payment request or receiving payment status, purchase status unknown.
  • Cancelled — payment request sent, although, the user closed the payment screen on their app, thus, the payment result is unknown.
  • InvalidPaymentState — SDK payments error. May occur due to an incorrect return deeplink.
class_name RuStorePaymentResult extends Object
class Success extends RuStorePaymentResult:

var orderId: String = ""
var purchaseId: String = ""
var productId: String = ""
var invoiceId: String = ""
var subscriptionToken: String = ""

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
if obj.has("orderId"):
purchaseId = obj["orderId"]

purchaseId = obj["purchaseId"]
productId = obj["productId"]
invoiceId = obj["invoiceId"]

if obj.has("subscriptionToken"):
purchaseId = obj["subscriptionToken"]
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов (optional — if omitted, will be generated automatically);
  • purchaseId — product ID;
  • productId — product ID assigned to product in RuStore Console (mandatory);
  • invoiceId — invoice ID;
  • subscriptionToken — subscriptions token. Consists of invoiceId of the purchase and RuStore userId specified using a dot delimiter: invoiceId.userId.
class Cancelled extends RuStorePaymentResult:
var purchaseId: String

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
purchaseId = obj["purchaseId"]

purchaseId — product ID.

class Failure extends RuStorePaymentResult:

var purchaseId: String = ""
var invoiceId: String = ""
var orderId: String = ""
var quantity: int = 0
var productId: String = ""
var errorCode: int = 0

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
if obj.has("purchaseId"): purchaseId = obj["purchaseId"]
if obj.has("invoiceId"): invoiceId = obj["invoiceId"]
if obj.has("orderId"): orderId = obj["orderId"]
if obj.has("quantity"): quantity = int(obj["quantity"])
if obj.has("productId"): productId = obj["productId"]
if obj.has("errorCode"): errorCode = int(obj["errorCode"])
  • purchaseId — product ID.
  • invoiceId — invoice ID.
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.
  • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1).
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • errorCode — error code.
class InvalidPaymentState extends RuStorePaymentResult:
pass

The on_purchase_product_failure callback returns the RuStoreError object with the error information. The error structure is described in Error Handling.

Getting purchase information

Go get purchase information, use the get_purchase_info method.

You must subscribe to events once before using this method:

  • on_get_purchase_info_success;
  • on_get_purchase_info_failure.
Subscription to events
func _ready:
# `_billing_client` initialization

_billing_client.on_get_purchase_info_success(_on_get_purchase_info_success)
_billing_client.on_get_purchase_info_failure(_on_get_purchase_info_failure)

func _on_get_purchase_info_success(purchase: RuStorePurchase):
pass

func _on_get_purchase_info_failure(error: RuStoreError):
pass
Calling get_purchase_info
# Your purchase information request UI implementation
func _on_confirm_purchase_pressed(purchase: RuStorePurchase):
_billing_client.get_purchase_info(purchase.purchaseId)

purchase.purchaseId — product ID.

The on_get_purchase_info_success callback returns the RuStorePurchase object with the purchase information.

class_name RuStorePurchase extends Node

var purchaseId: String = ""
var productId: String = ""
var productType: ERuStoreProductType.Item = ERuStoreProductType.Item.NON_CONSUMABLE
var invoiceId: String = ""
var description: String = ""
var language: String = ""
var purchaseTime: String = ""
var orderId: String = ""
var amountLabel: String = ""
var amount: int = 0
var currency: String = ""
var quantity: int = 0
var purchaseState: ERuStorePurchaseState.Item = ERuStorePurchaseState.Item.CANCELLED
var developerPayload: String = ""
var subscriptionToken: String = ""

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
if obj.has("purchaseId"): purchaseId = obj["purchaseId"]
productId = obj["productId"]
if obj.has("productType"): productType = ERuStoreProductType.Item.get(obj["productType"])
if obj.has("invoiceId"): invoiceId = obj["invoiceId"]
if obj.has("description"): description = obj["description"]
if obj.has("language"): language = obj["language"]
if obj.has("purchaseTime"): purchaseTime = obj["purchaseTime"]#RuStoreDateTime
if obj.has("orderId"): orderId = obj["orderId"]
if obj.has("amountLabel"): amountLabel = obj["amountLabel"]
if obj.has("amount"): amount = int(obj["amount"])
if obj.has("currency"): currency = obj["currency"]
if obj.has("quantity"): quantity = int(obj["quantity"])
if obj.has("purchaseState"): purchaseState = ERuStorePurchaseState.Item.get(obj["purchaseState"])
if obj.has("developerPayload"): developerPayload = obj["developerPayload"]
if obj.has("subscriptionToken"): subscriptionToken = obj["subscriptionToken"]
  • purchaseId — product ID.

  • productId — product ID assigned to product in RuStore Console (mandatory).

  • productType — product type: CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION:

    • NON_CONSUMABLE — non-consumable (can be purchased only once, for example: disabling ads);
    • CONSUMABLE — consumable (can be bought more than once, for example: crystals in app);
    • SUBSCRIPTION — subscription (can be purchases for a period of time, for example: a streaming service subscription).
  • invoiceId — invoice ID.

  • description — descriptions in language.

  • language — language specified with BCP 47 code.

  • purchaseTime — purchase time:

    • MMM — abbreviated month name (January — Jan);
    • dd — day of month;
    • yyyy — year;
    • h — hour in the 12-hour format;
    • mm — minutes;
    • ss — seconds;
    • a — AM/PM time indicator.
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.

  • amountLable — formatted purchase price, including currency symbol.

  • amount — price in minimum currency units.

  • currency — ISO 4217 currency code.

  • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1).

  • purchaseState — purchase state:

    • CREATED — purchase created;
    • INVOICE_CREATED — purchase invoiced is created and awaiting payment;
    • PAID — only for consumable products — intermediate status, the funds on the user's account are put on hold. The purchase is awaiting confirmation from the developer;
    • CONFIRMED — payment for non-consumable product successful;
    • CONSUMED — payment for consumable product successful;
    • CANCELLED — purchase canceled — there was no payment or the payment was refunded (if a purchase is a subscription it doesn't change its state to CANCELLED);
    • PAUSED — for subscriptions — the purchase is in HOLD period;
    • TERMINATED — subscription terminated.
  • developerPayload — string with additional order information, that you can specify on purchase initialization.

  • subscriptionToken — purchase token for server validation .

State model (purchaseState)

CONSUMABLES - purchase state model

img

NON-CONSUMABLES - purchase state model

img

(SUBSCRIPTIONS) - purchase state model

img

The on_get_purchase_info_failure callback returns the RuStoreError object with the error information. The error structure is described in Error Handling.

Getting products list

This method returns purchases with the following statuses. For more informations on possible purchase states see Getting purchase info.

Type/StatusINVOICE_CREATEDCONFIRMEDPAIDPAUSED
CONSUMABLE++
NON-CONSUMABLE++
SUBSCRIPTION+++
note

This method returns incomplete purchases that require attention. Also, it shows confirmed subscriptions and consumable products that cannot be purchased more than once.

Go get the user's purchases list, use the get_purchases method.

You must subscribe to events once before using this method:

  • on_get_purchases_success;
  • on_get_purchases_failure.
Subscription to events
func _ready:
# `_billing_client` initialization

_billing_client.on_get_purchases_success(_on_get_purchases_success)
_billing_client.on_get_purchases_failure(_on_get_purchases_failure)

func _on_get_purchases_success(purchases: Array):
pass

func _on_get_purchases_failure(error: RuStoreError):
pass
Calling get_purchases
_billing_client.get_purchases()

The on_get_purchases_success callback returns the RuStorePurchase object array with the information about purchases.

class_name RuStorePurchase extends Node

var purchaseId: String = ""
var productId: String = ""
var productType: ERuStoreProductType.Item = ERuStoreProductType.Item.NON_CONSUMABLE
var invoiceId: String = ""
var description: String = ""
var language: String = ""
var purchaseTime: String = ""
var orderId: String = ""
var amountLabel: String = ""
var amount: int = 0
var currency: String = ""
var quantity: int = 0
var purchaseState: ERuStorePurchaseState.Item = ERuStorePurchaseState.Item.CANCELLED
var developerPayload: String = ""
var subscriptionToken: String = ""

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)
if obj.has("purchaseId"): purchaseId = obj["purchaseId"]
productId = obj["productId"]
if obj.has("productType"): productType = ERuStoreProductType.Item.get(obj["productType"])
if obj.has("invoiceId"): invoiceId = obj["invoiceId"]
if obj.has("description"): description = obj["description"]
if obj.has("language"): language = obj["language"]
if obj.has("purchaseTime"): purchaseTime = obj["purchaseTime"]#RuStoreDateTime
if obj.has("orderId"): orderId = obj["orderId"]
if obj.has("amountLabel"): amountLabel = obj["amountLabel"]
if obj.has("amount"): amount = int(obj["amount"])
if obj.has("currency"): currency = obj["currency"]
if obj.has("quantity"): quantity = int(obj["quantity"])
if obj.has("purchaseState"): purchaseState = ERuStorePurchaseState.Item.get(obj["purchaseState"])
if obj.has("developerPayload"): developerPayload = obj["developerPayload"]
if obj.has("subscriptionToken"): subscriptionToken = obj["subscriptionToken"]
  • purchaseId — product ID.

  • productId — product ID assigned to product in RuStore Console (mandatory).

  • productType — product type: CONSUMABLE/NON-CONSUMABE/SUBSCRIPTION:

    • NON_CONSUMABLE — non-consumable (can be purchased only once, for example: disabling ads);
    • CONSUMABLE — consumable (can be bought more than once, for example: crystals in app);
    • SUBSCRIPTION — subscription (can be purchases for a period of time, for example: a streaming service subscription).
  • invoiceId — invoice ID.

  • description — descriptions in language.

  • language — language specified with BCP 47 code.

  • purchase_time — purchase time.

    • MMM — abbreviated month name (January — Jan);
    • dd — day of month;
    • yyyy — year;
    • h — hour in the 12-hour format;
    • mm — minutes;
    • ss — seconds;
    • a — AM/PM time indicator.
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. Если не укажете, он будет сгенерирован автоматически (uuid). Максимальная длина 150 символов.

  • amountLable — formatted purchase price, including currency symbol.

  • amount — price in minimum currency units.

  • currency — ISO 4217 currency code.

  • quantity — количество продукта (необязательный параметр — если не указывать, будет подставлено значение 1).

  • purchaseState — purchase state:

    • CREATED — purchase created;
    • INVOICE_CREATED — purchase invoiced is created and awaiting payment;
    • PAID — only for consumable products — intermediate status, the funds on the user's account are put on hold. The purchase is awaiting confirmation from the developer;
    • CONFIRMED — payment for non-consumable product successful;
    • CONSUMED — payment for consumable product successful;
    • CANCELLED — purchase canceled — there was no payment or the payment was refunded (if a purchase is a subscription it doesn't change its state to CANCELLED);
    • PAUSED — for subscriptions — the purchase is in HOLD period;
    • TERMINATED — subscription terminated.
  • developerPayload — string with additional order information, that you can specify on purchase initialization.

  • subscriptionToken — purchase token for server validation .

The on_get_purchases_failure returns the RuStoreError object with the error information. The error structure is described in Error Handling.

Consume (confirm) purchase

Products that require confirmation

Please, keep in mind the purchase type. Confirmation is only needed if your product is CONSUMABLE and can be purchased more than once.

To correctly deliver such products, confirm purchases with the confirmPurchase method. On delivering a product, use server validation. Deliver your product only after the payment (invoice) is in the CONFIRMED status. Use the addOnSuccessListener callback of the confirmPurchase method to deliver products.

Attention!

The PAID status is intermediate and meas that the user's money is put on hold on their card, so you need to confirm the purchase.

The exceptions are SBP or mobile payment — see the explanation below.

When paying for CONSUMABLE products with SBP or mobile payment, one-stage payment is used, although the payment model is as in two-stage payments. It means that what a payment is in the PAID status, when paying with SBP or mobile payment, the money is withdrawn from the buyer's account, as well as the developer's fee is withdrawn from their's. In this case, if a purchase is canceled from the PAID status the refund is made, not reverse. The developer's fee will not be returned. At the same time, to complete the purchase you still have to confirm purhchase — see the table below.

Payment methodPayment typePayment in the PAID status
  • bank cards;
  • Sber ID;
  • SberPay;
  • T-Pay;
  • VK Pay.
Two-stage
  • Money is on hold on the buyer's account.
  • Developer's fee is not applied.
  • Payment cancellation (reverse) is available.
  • SBP;
  • mobile payment.
One-stage
  • Money is withdrawn from the buyer's account.
  • The developer's fee is applied.
  • If a purchase is canceled form the PAID status the transaction is refunded, not reverse reversed. The developer's fee will not be returned.

ConfirmPurchase request

Us the confirm_purchase method to confirm a purchase. Purchase confirmation request must be accompanied by the delivery of the product. After calling the confirmation method the purchase changes its state to CONSUMED.

You must subscribe to events once before using this method:

  • on_confirm_purchase_success;
  • on_confirm_purchase_failure.
Subscription to events
func _ready:
# `_billing_client` initialization

_billing_client.on_confirm_purchase_success(_on_confirm_purchase_success)
_billing_client.on_confirm_purchase_failure(_on_confirm_purchase_failure)

func _on_confirm_purchase_success(purchase_id: String):
pass

func _on_confirm_purchase_failure(purchase_id: String, error: RuStoreError):
pass
Calling confirm_purchase
# Your purchase confirmation UI implementation
func _on_confirm_purchase_pressed(purchase: RuStorePurchase):
_billing_client.confirm_purchase(purchase.purchaseId)

purchase.purchaseId — product ID.

The on_confirm_purchase_failure callback returns the purchase ID of the String type and the RuStoreError object with the error information. The error structure is described in Error Handling.

Purchase cancellation

To cancel a purchase, use the delete_purchase method.

You must subscribe to events once before using this method:

  • on_delete_purchase_success;
  • on_delete_purchase_failure.
Subscription to events
func _ready:
# `_billing_client` initialization

_billing_client.on_delete_purchase_success(_on_delete_purchase_success)
_billing_client.on_delete_purchase_failure(_on_delete_purchase_failure)

func _on_delete_purchase_success(purchase_id: String):
pass

func _on_delete_purchase_failure(purchase_id: String, error: RuStoreError):
_core_client.show_toast(purchase_id + " " + error.description)
Calling delete_purchase
# Your purchase cancellation UI implementation
func _on_delete_purchase_pressed(purchase: RuStorePurchase):
_billing_client.delete_purchase(purchase.purchaseId)
purchase.purchaseId — product ID

  • The on_delete_purchase_info_success callback returns purchase ID.
  • The on_delete_purchase_info_failure callback returns purchase ID of the String type and the RuStoreError object with error information. The error structure is described in Error Handling.

Logging

If you need to log payment library events, add optional debugLogs in the init call and subscribe to the events:

  • on_payment_logger_debug;
  • on_payment_logger_error;
  • on_payment_logger_info;
  • on_payment_logger_verbose;
  • on_payment_logger_warning.

Logging will work only for Debug builds of the app and *.aar packages. Logging will be automatically disabled for Release builds.

func _ready():
_billing_client = RuStoreGodotBillingClient.get_instance()

_billing_client.on_payment_logger_debug.connect(_on_payment_logger_debug)
_billing_client.on_payment_logger_error.connect(_on_payment_logger_error)
_billing_client.on_payment_logger_info.connect(_on_payment_logger_info)
_billing_client.on_payment_logger_verbose.connect(_on_payment_logger_verbose)
_billing_client.on_payment_logger_warning.connect(_on_payment_logger_warning)

# calling init

func _on_payment_logger_debug(error: RuStoreError, message: String, tag: String):
_core_client.show_toast(tag + ": " + message)

func _on_payment_logger_error(error: RuStoreError, message: String, tag: String):
_core_client.show_toast(tag + ": " + message)

func _on_payment_logger_info(error: RuStoreError, message: String, tag: String):
_core_client.show_toast(tag + ": " + message)

func _on_payment_logger_verbose(error: RuStoreError, message: String, tag: String):
_core_client.show_toast(tag + ": " + message)

func _on_payment_logger_warning(error: RuStoreError, message: String, tag: String):
_core_client.show_toast(tag + ": " + message)

Below are the return parameters.

  • error — error information. The error structure is described in Error Handling.
  • message — message for logging.
  • tag — log tag.

Dynamic interface theme change

To dynamically change the theme, use the set_theme method.

SetTheme request

func _ready():
_billing_client = RuStoreGodotBillingClient.get_instance()

var theme = ERuStoreTheme.Item.DARK

Here: theme — theme type from ERuStoreTheme:

  • DARK — dark theme;
  • LIGHT — light theme.

Error handling

Possible errors

  • RuStoreNotInstalledException — RuStore is not installed on the user's device;
  • RuStoreOutdatedException — RuStore version installed on the user's device does not support this SDK;
  • RuStoreUserUnauthorizedException — user is not authorized in RuStore;
  • RuStoreRequestLimitReached — not enough time has passed since the process was last shown;
  • RuStoreReviewExists — this user has already rated your app;
  • RuStoreInvalidReviewInfo — problems with ReviewInfo;
  • RuStoreException — basic RuStore error from which other errors are inherited.

Error structure

class_name RuStoreError extends Object

var name: String = ""
var description: String = ""

func _init(json: String = ""):
if json != "":
var obj = JSON.parse_string(json)

if obj.has("simpleName"):
name = obj["simpleName"]

if obj.has("detailMessage"):
description = obj["detailMessage"]
  • name – error name.
  • description – error description.

Automatic error handling

On calling the purchase_product method, errors are handled automatically.

Use the set_error_handling method to display the error dialog to the user (see below).

func _ready():
_billing_client = RuStoreGodotBillingClient.get_instance()
_billing_client.set_error_handling(true)
  • true — display dialog;
  • false — do not display dialog.