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.
The service has some restrictions to work outside of Russia.
Connecting to project
Embed in your project
- Copy the project plugin and sample app from the official RuStore repository to GitFlic.
- In your IDE, open the Android project from the
extension_libraries
folder. - Build your project with the command
gradle assemble
. If the build is successful, the following files will be created inbilling_example/extension_rustore_billing/lib/android
andbilling_example/extension_rustore_core/lib/android
.RuStoreDefoldBilling.jar
;RuStoreDefoldCore.jar
.
- Copy the
billing_example/extension_rustore_billing
andbilling_example/extension_rustore_core
folders to the root of your project.
Deeplink processing
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 scheme
of your project (see below).
<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 theinit()
method.
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).
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
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
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 inlanguage
.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 inlanguage
.productId
— product ID..productStatus
— product type..productType
— product status..promoImageUrl
— promotional picture link..title
— product name inlanguage
.subscription
— subscription description, returned only for products withsubscription
.
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, inproduct: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
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/Status | INVOICE_CREATED | CONFIRMED | PAID |
---|---|---|---|
CONSUMABLE | + | + | |
NON-CONSUMABLE | + | + | |
SUBSCRIPTION | + | + |
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
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 inlanguage
.currency
— ISO 4217 currency code.description
— product description inlanguage
.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_failure
callback. All possible RuStoreException errors are described in Error Handling.
Getting purchase info
Use theget_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
# 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 inlanguage
.currency
— ISO 4217 currency code.description
— product description inlanguage
.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
// 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
# 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.
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.
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.
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 init
call 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, useset_theme
.
setTheme Implementation example
rustorebilling.set_theme(0)
0
- dark theme;1
- light theme.
Errors processing
Error structure
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 withReviewInfo
;RuStoreException
— basic RuStore error, from which all other errors are inherited..
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 code | Error code | Description |
---|---|---|
400 | 40001 | Incorrect request parameters: mandatory parameters are not filled in/incorrect parameters format |
400 | 40003 | No application found |
400 | 40004 | inactive application status |
400 | 40005 | Product not found |
400 | 40006 | inactive product status |
400 | 40007 | Invalid product type. Supported types: consumable , non-consumable , subscription . |
400 | 40008 | A purchase with this order_id already exists |
400 | 40009 | The 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 |
400 | 40010 | For 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 |
400 | 40011 | For 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. |
400 | 40012 | Forsubscription 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. |
400 | 40013 | Forsubscription product type. When requesting the subscription service for a list of products GET/products (serviceId , user_id ) data were not received |
400 | 40014 | The required attribute(s) was not received in the request. |
400 | 40015 | Failed to change status when updating purchase (no transition allowed). |
400 | 40016 | When purchasing a subscription for a non-consumable product, the number quantity > 1 is specified |
400 | 40017 | Product removed, no new purchases available. |
400 | 40018 | You cannot consume type product . |
401 | 40101 | Invalid token. |
401 | 40102 | Token lifetime has expired. |
403 | 40301 | Access to the requested resource is denied (unauthorized). |
403 | 40302 | The current call is not authorized (method prohibited) for the token. |
403 | 40303 | The application ID in the request does not match the one specified in the token. |
403 | 40305 | Incorrect token type. |
404 | 40401 | Not found. |
408 | 40801 | The notification timeout period specified in the request has expired. |
500 | 50*** | Internal payment service error. |