Skip to main content

5.0.0

RuStore allows you to integrate payments into your mobile app.

Implementation example

See the example app to learn how to integrate rating and feedback SDK correctly.

Prerequisites

  • The current version of RuStore is installed on the user's device.
  • The user is authorized in RuStore.
  • The user and the app should not be blocked in RuStore.
  • In-app purchases should be enabled for the app in RuStore Console.
  • Defold 1.6.2 and later.
caution

The service has some restrictions to work outside of Russia.

Connecting to project

Embed in your project

  1. Copy the project plugin and sample app from the official RuStore repository to GitFlic.
  2. In your IDE, open the Android project from the extension_libraries folder.
  3. Build your project with the command gradle assemble. If the build is successful, the following files will be created in billing_example/extension_rustore_billing/lib/android and billing_example/extension_rustore_core/lib/android.
    • RuStoreDefoldBilling.jar;
    • RuStoreDefoldCore.jar.
  4. Copy the billing_example/extension_rustore_billing and billing_example/extension_rustore_core folders to the root of your project.

To redirect a user to your app after payment via third-party apps (the Faster Payments System (SBP), SberPay and others), you need to properly implement deep linking in your app. Specify the intent-filter in AndroidManifest.xml with schemeof your project (see below).

AndroidManifest.xml
<activity>
<!-- RUSTORE BILLING INTENT FILTER -->
<activity android:name="ru.rustore.defold.billing.RuStoreIntentFilterActivity" android:exported="true" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Set your appscheme -->
<data android:scheme="yourappscheme" />
</intent-filter>
</activity>

where yourappscheme — your deeplink scheme, it can be changed to another one.

This scheme must match the deeplinkSheme value specified during the billing client library initialization.

The example app contains a modified manifest in file billing_example / extension_rustore_billing / manifests / android / AndroidManifest.xml

Initialization

Initialize the library before calling its methods.

For initialisation, call the init() method.
Вызов метода init
local APPLICATION_ID = "123456"
local DEEPLINK_SCHEME = "yourappscheme"
local DEBUG_LOGS = true

rustorebilling.init(APPLICATION_ID, DEEPLINK_SCHEME, DEBUG_LOGS)
  • 123456 — application code from RuStore Console (example: https://console.rustore.ru/apps/123456).
  • yourappscheme — deeplink scheme required to return to your app upon payment via a third-party application (for example, SberPay or SBP). SDK generates its host for this scheme.
  • debugLogs — flag that regulates logging (logs will be automatically disabled for Release builds).

note
The deeplink scheme passed in yourappscheme must match the one specified in AndroidManifest.xml (see Deeplinks handling).

How payments work

Checking purchases availability

  • The current version of RuStore is installed on the user's device.
  • RuStore app supports payment functionality.
  • The user is authorized in RuStore.
  • The user and the app should not be blocked in RuStore.
  • In-app purchases should be enabled for the app in RuStore Console.

You need to subscribe to the events once before calling the methods

  • rustore_check_purchases_available_success;
  • rustore_check_purchases_available_failure.
Подписка на события
function init(self)
# Initialization rustorebilling

rustorecore.connect("rustore_check_purchases_available_success", _check_purchases_available_success)
rustorecore.connect("rustore_check_purchases_available_failure", _check_purchases_available_failure)
end

function _check_purchases_availability_success(self, channel, value)
local data = json.decode(value)
end

function _check_purchases_availability_failure(self, channel, value)
local data = json.decode(value)
end
Вызов метода check_purchases_availability
rustorebilling.check_purchases_availability()

To return a JSON string with the service availability information, use rustore_check_purchases_availability_success callback (see below). below).

  • isAvailable — whether payment conditions are met (true/false).
  • cause — error information.

All possible RuStoreException errors are described in Error Handling.

To return a JSON string with the error information, use rustore_check_purchases_availability_failure callback. All possible RuStoreException errors are described in Error Handling.

Working with SDK

Getting products list

Use the get_products() method to get a list of products.

You need to subscribe to the events once before calling the methods

  • rustore_on_get_products_success;
  • rustore_on_get_products_failure.
Подписка на события
function init(self)
# Initialization rustorebilling

rustorecore.connect("rustore_on_get_products_success", _on_get_products_success)
rustorecore.connect("rustore_on_get_products_failure", _on_get_products_failure)
end

function _on_get_products_success(self, channel, value)
local data = json.decode(value)
end

func _on_get_products_failure(self, channel, value)
local data = json.decode(value)
end
Вызов метода get_products
local PRODUCT_IDS = {
"non_con2",
"non_con1",
"con2",
"con1",
"sub2",
"sub1"}

rustorebilling.get_products(PRODUCT_IDS)

PRODUCT_IDS — list of products IDs.

To return a JSON string with the product information, use rustore_on_get_products_success callback (see below). below).

  • currency — ISO 4217 currency code.
  • description — product description in language.
  • imageUrl — link to an image..
  • language — language specified with the BCP 47 encoding..
  • price — price in minor units (in kopecks)..
  • priceLable — formatted purchase price, including the currency symbol in language.
  • productId — product ID..
  • productStatus — product type..
  • productType — product status..
  • promoImageUrl — promotional picture link..
  • title — product name in language.
  • subscription — subscription description, returned only for products with subscription.

Fields available in subscription (see below). below).

  • subscriptionPeriod — subscription period..
  • freeTrialPeriod — trial subscription period..
  • gracePeriod — grace period..
  • introductoryPrice — formatted introductory subscription price, including the currency symbol, in product:language.
  • introductoryPriceAmount — introductory price in minor units of currency (in kopecks).
  • introductoryPricePeriod — calculated period of the introductory price..

Fields available in period (see below). below).

  • years — number of years..
  • months — number of days..
  • days — number of days..

To return a JSON string with the error information, use rustore_on_get_products_failure callback. All possible RuStoreException errors are described in Error Handling.

Purchasing product

Use thepurchase_product()method to call a product purchase.

You need to subscribe to the events once before calling the methods

  • rustore_on_purchase_product_success;
  • rustore_on_purchase_product_failure.
Подписка на события
function init(self)
# Initialization rustorebilling

rustorecore.connect("rustore_on_purchase_product_success", _on_purchase_product_success)
rustorecore.connect("rustore_on_purchase_product_failure", _on_purchase_product_failure)
end

function _on_purchase_product_success(self, channel, value)
local data = json.decode(value)
end

function _on_purchase_product_failure(self, channel, value)
local data = json.decode(value)
end
Вызов метода purchase_product
local PRODUCT_ID = "example_id"
local PARAMS = "{" ..
"\"orderId\":\"example\"," ..
"\"quantity\":1," ..
"\"payload\":\"example\"" ..
"}"

rustorebilling.purchase_product(PRODUCT_ID, PARAMS)
  • PRODUCT_ID — product ID.;
  • PARAMS — optional parameters:
    • orderId — unique payment identifier generated by the application (uuid);;
    • quantity — product quantity.;
    • payload — уline specified by the developer that contains additional information about the order..

To return a JSON string with the purchase information, use rustore_on_get_purchase_info_success callback. Possible values:

  • type — query result type.

    :

    • Success - successful purchase result.;
    • Failure - error occurred when sending a payment request or receiving a payment status, it is not possible to set the purchase status.;
    • Cancelled — a purchase request has been sent, but the user has closed the "payment window" on their device, so the payment result is unknown.;
    • InvalidPaymentState — Billing SDK error.. May occur in case of an incorrect reverse deeplink.

      .
  • data — JSON string with optional fields.

    .

Object type Success returned in case of successful request. Possible values:

  • orderId — unique payment identifier generated by the application (uuid);.
  • purchaseId — purchase ID..
  • productId — product ID..
  • invoiceId — invoice ID..
  • subscriptionToken — token for server validation..

Object type Failure returned in case of failed request. Possible values:

  • purchaseId — purchase ID..
  • invoiceId — invoice ID..
  • orderId — unique payment identifier generated by the application (uuid);.
  • quantity — product quantity..
  • productId — product ID..
  • errorCode — error code..

All possible errors codes are described in Error codes.

Object type Cancelled returned in case of purchase cancellation by the user. Possible values:

  • purchaseId — purchase ID..

Object type InvalidPaymentState returned in case of payment SDK error. May occur in case of an incorrect reverse deeplink.

To return a JSON string with the error information, use rustore_on_purchase_product_failure callback. All possible RuStoreException errors are described in Error Handling.

Getting purchases list

The method only returns purchases with statuses from the table below.

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

The method returns incomplete purchase and purchase consumable states that require processing. Apart from that, it shows confirmed purchases for subscriptions and non-consumable items - those that cannot be purchased again.

Use theget_purchases()method to get the user's list of purchases.

You need to subscribe to the events once before calling the methods

  • rustore_on_get_purchases_success;
  • rustore_on_get_purchases_failure.
Подписка на события
function init(self)
# Initialization rustorebilling

rustorecore.connect("rustore_on_get_purchases_success", _on_get_purchases_success)
rustorecore.connect("rustore_on_get_purchases_failure", _on_get_purchases_failure)
end

function _on_get_purchases_success(self, channel, value)
local data = json.decode(value)

for key, value in pairs(data) do
-- value.amount
end
end

function _on_get_purchases_failure(self, channel, value)
local data = json.decode(value)
end
Вызов метода get_purchases
rustorebilling.get_purchases()

To return objects array with the error information, use rustore_on_get_purchases_success callback. Available fields:

  • amount — price in minor units of currency..
  • amountLable — formatted purchase price, including the currency symbol in language.
  • currency — ISO 4217 currency code.
  • description — product description in language.
  • developerPayload — уline specified by the developer that contains additional information about the order..
  • invoiceId — invoice ID..
  • language — language specified with the BCP 47 encoding..
  • orderId — unique payment identifier generated by the application (uuid);.
  • productId — product ID..
  • productType — product type..
  • purchaseId — purchase ID..
  • purchaseState — purchase state.:
  • purchaseTime— time of purchase.

    .
  • quantity — product quantity..
  • subscriptionToken — token for server validation..

To return a JSON string with the error information, use rustore_on_get_purchases_failurecallback. All possible RuStoreException errors are described in Error Handling.

Getting purchase info

Use the get_purchase_info() method to retrive purchase details.

You need to subscribe to the events once before calling the methods

  • rustore_on_get_purchase_info_success;
  • rustore_on_get_purchase_info_failure.
Подписка на события
function init(self)
# Initialization rustorebilling

rustorecore.connect("rustore_on_get_purchase_info_success", _on_get_purchase_info_success)
rustorecore.connect("rustore_on_get_purchase_info_failure", _on_get_purchase_info_failure)
end

function _on_get_purchase_info_success(self, channel, value)
local data = json.decode(value)
end

function _on_get_purchase_info_failure(self, channel, value)
local data = json.decode(value)
end
Вызов метода get_purchase_info
#  Your implementation
function _on_get_purchase_info_pressed(purchaseId):
rustorebilling.get_purchase_info(purchaseId)
end

purchaseId — purchase ID.

To return a JSON string with the purchase information, use rustore_on_get_purchase_info_success callback. Available fields:

  • amount — price in minor units of currency..
  • amountLable — formatted purchase price, including the currency symbol in language.
  • currency — ISO 4217 currency code.
  • description — product description in language.
  • developerPayload — уline specified by the developer that contains additional information about the order..
  • invoiceId — invoice ID..
  • language — language specified with the BCP 47 encoding..
  • orderId — unique payment identifier generated by the application (uuid);.
  • productId — product ID..
  • productType — product type..
  • purchaseId — purchase ID..
  • purchaseState — purchase state.:
  • purchaseTime— time of purchase.

    .
  • quantity — product quantity..
  • subscriptionToken — token for server validation..

To return a JSON string with the error information, use rustore_on_get_purchase_info_failure callback. All possible RuStoreException errors are described in Error Handling.

Confirming purchase

Products that require confirmation

The RuStore application consists of the following types of products:

  • SUBSCRIPTION— subscription (can be purchased for a period of time, such as a streaming service subscription)..
  • NON_CONSUMABLE — non-consumables (one-time purchases, such as disabling ads in an app).
  • CONSUMABLE — consumables (multiple-time purchases, such as crystals in the app);

    .

Only CONSUMABLE type products require confirmation if they are in purchaseState == "PAID" state.

Calling confirmation method

Use theconfirm_purchase() method to call a product purchase. The release of the goods must be accompanied by a purchase confirmation request. Once the confirmation is called, the purchase will have a CONSUMED status.

You need to subscribe to the events once before calling the methods

  • rustore_on_confirm_purchase_success;
  • rustore_on_confirm_purchase_failure.
Подписка на события
function init(self)
# Initialization rustorebilling

rustorecore.connect("rustore_on_confirm_purchase_success", _on_confirm_purchase_success)
rustorecore.connect("rustore_on_confirm_purchase_failure", _on_confirm_purchase_failure)
end

function _on_confirm_purchase_success(self, channel, value)
local data = json.decode(value)
end

function _on_confirm_purchase_failure(self, channel, value)
local data = json.decode(value)
end
Вызов метода confirm_purchase
// Your implementation to confirm UI purchase
function _on_confirm_purchase_pressed(purchaseId):
rustorebilling.confirm_purchase(purchaseId)
end
  • purchaseId — purchase ID..

Server validation

For server purchase validation via API RuStore methods, you can use the value of the subscriptionToken field returned in the json string when a product is successfully purchased.

SubscriptionToken consists of invoiceId of purchase and userId, written with a dot: $invoiceId.$userId.

Getting subscriptionToken via purchase result

function _on_purchase_product_success(self, channel, value)
local data = json.decode(value)

if data.type == "Success" then
local subscriptionToken = data.data.subscriptionToken
yourApi.validate(subscriptionToken)
end
end

You can also get subscriptionToken from object's list of purchases.

function _on_get_purchases_success(self, channel, value)
local data = json.decode(value)

for key, value in pairs(data) do
yourApi.validate(value.subscriptionToken)
end
end

Canceling purchase

Use thedelete_purchase method to cancel a purchase.

You need to subscribe to the events once before calling the methods

  • rustore_on_delete_purchase_success;
  • rustore_on_delete_purchase_failure.

Cancel request

Подписка на события
function init(self)
# Initialization rustorebilling

rustorecore.connect("rustore_on_delete_purchase_success", _on_delete_purchase_success)
rustorecore.connect("rustore_on_delete_purchase_failure", _on_delete_purchase_failure)
end

function _on_delete_purchase_success(self, channel, value)
local data = json.decode(value)
end

function _on_delete_purchase_failure(self, channel, value)
local data = json.decode(value)
end
Вызов метода delete_purchase
#  Your implementation to cancel UI purchase
function _on_delete_purchase_pressed(purchaseId):
rustorebilling.delete_purchase(purchaseId)
end
  • purchaseId — purchase ID..

To return the purchase ID, use rustore_on_delete_purchase_success callback.

  • purchaseId — purchase ID..

To return a JSON string with the error information, use rustore_on_delete_purchase_failure callback. Available fields:

  • purchaseId — purchase ID..
  • cause — error information.

All possible RuStoreException errors are described in Error Handling.

info

Note. Use this method if your app logic is related to purchase cancellation. The purchase is canceled automatically after a 20-min timeout, or upon a second purchase from the same customer.

Processing unfinished payments

Uncompleted payments must be processed by the developer.

To confirm a CONSUMABLE purchase type in PAID status, you can call the confirm-purchase method (see Getting purchase info).

In the case of purchase cancellations, consider your internal process when using payment processing methods. As for some developers, it provides for pre-consumption checks or purchase cancellation. In this case, request the status of such purchase separately.

tip

For example, if a user has paid for an item you can't supply to them for some reason, call the cancel purchase method on the PAID status to cancel the purchase.

In cases where the receive shopping list method returns a purchase with INVOICE_CREATED status, you can use the cancel purchase method. For example, if you don't want to see a purchase with these statuses in your shopping list. You don't have to do it yourself, as RuStore handles the cancellation of such purchases on its side.

info

In some cases, after paying through a banking app (SBP, SberPay, TinkoffPay, etc.), the purchase status may still return INVOICE_CREATED, when you subsequently return to app. This is caused by the purchase processing time by the bank. Therefore, the developer needs to correctly link the shopping list obtaining function to the life cycle on the screen.

You acn also cancel a purchase in INVOICE_CREATED status only through user interaction with the app. For example, create a separate button for this purpose.

Logging

If you want to log payment library events, add optional parameter debugLogs to initcall and subscribe to the events once:

  • rustore_on_payment_logger_debug;
  • rustore_on_payment_logger_error;
  • rustore_on_payment_logger_info;
  • rustore_on_payment_logger_verbose;
  • rustore_on_payment_logger_warning.
local APPLICATION_ID = "123456"
local DEEPLINK_SCHEME = "yourappscheme"
local DEBUG_LOGS = true
local LOG_TAG = "yourtag"

function init(self)
rustorecore.connect("rustore_on_payment_logger_debug", _on_payment_logger_debug)
rustorecore.connect("rustore_on_payment_logger_error", _on_payment_logger_error)
rustorecore.connect("rustore_on_payment_logger_info", _on_payment_logger_info)
rustorecore.connect("rustore_on_payment_logger_verbose", _on_payment_logger_verbose)
rustorecore.connect("rustore_on_payment_logger_warning", _on_payment_logger_warning)

rustorebilling.init(APPLICATION_ID, DEEPLINK_SCHEME, DEBUG_LOGS)
end

function _on_payment_logger_debug(self, channel, value)
rustorecore.log_debug(LOG_TAG, value)
end

function _on_payment_logger_error(self, channel, value)
rustorecore.log_error(LOG_TAG, value)
end

function _on_payment_logger_info(self, channel, value)
rustorecore.log_info(LOG_TAG, value)
end

function _on_payment_logger_verbose(self, channel, value)
rustorecore.log_verbose(LOG_TAG, value)
end

function _on_payment_logger_warning(self, channel, value)
rustorecore.log_warning(LOG_TAG, value)
end

Logging processing parameter:

  • DEBUG_LOGS — enable logs (logs will be automatically disabled for Release builds).).

All logging callbacks return a JSON string. Available fields:

  • e — error information or "null". All possible RuStoreException errors are described in Error Handling.
  • message – error description..

Changing UI theme

To dynamically change theme, use set_theme.

setTheme Implementation example

rustorebilling.set_theme(0)
  • 0 - dark theme;
  • 1 - light theme.

Errors processing

Error structure

Обработка json ошибки
function _on_failure(self, channel, value)
local data = json.decode(value)

local message = data.detailMessage
end
  • detailMessage – error description..

Possible errors

  • RuStoreNotInstalledException — RuStore not installed on user's device;
  • RuStoreOutdatedException — RuStore, installed on the user's device, does not support payment processing functions.;
  • RuStoreUserUnauthorizedException — user not authorized on 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 all other errors are inherited..
When the purchase_product method is called, errors are handled automatically.

You can use the set_error_handling method to show an error dialog to the user:

function init(self)
rustorebilling.set_error_handling(true)

# Initialization rustorebilling
end
  • true — show dialogue;
  • false — hide dialogue.

Error codes

The following is a description of possible errors in errorCode.

HTTP codeError codeDescription
40040001Incorrect request parameters: mandatory parameters are not filled in/incorrect parameters format
40040003No application found
40040004inactive application status
40040005Product not found
40040006inactive product status
40040007Invalid product type. Supported types: consumable, non-consumable, subscription.
40040008A purchase with this order_id already exists
40040009The current client has a purchase of this product with the status invoice_created. Your are required to offer the client to pay for/cancel the purchase
40040010For consumable product type. The current customer already has purchased this product with the status paid. First you need to confirm the purchase on the device, and then you can send the following purchase request for this product
40040011For non-consumable product type. The current client already has purchased this product with the status pre_confirmed/confirmed. Such product has already been purchased. This product cannot be sold more than once.
40040012Forsubscription product type. The current client already has purchased this product with the status pre_confirmed/confirmed. Such product has already been purchased. This product cannot be sold more than once.
40040013Forsubscription product type. When requesting the subscription service for a list of products GET/products (serviceId, user_id) data were not received
40040014The required attribute(s) was not received in the request.
40040015Failed to change status when updating purchase (no transition allowed).
40040016When purchasing a subscription for a non-consumable product, the number quantity > 1 is specified
40040017Product removed, no new purchases available.
40040018You cannot consume type product.
40140101Invalid token.
40140102Token lifetime has expired.
40340301Access to the requested resource is denied (unauthorized).
40340302The current call is not authorized (method prohibited) for the token.
40340303The application ID in the request does not match the one specified in the token.
40340305Incorrect token type.
40440401Not found.
40840801The notification timeout period specified in the request has expired.
50050***Internal payment service error.