In-app Payments SDK for Godot (version 9.1.0 (current version))
With RuStore you can integrate payments in your mobile app.
-
If you don't know where to start read the instruction.
-
If you migrate to Pay SDK from billingClient SDK, see the migration instructions. For more details, see here.
Getting Started
- Copy the plugin and example application projects from the official RuStore repository on GitFlic.
- Copy the contents of the
godot_example/android/plugins
folder to theyour_project/android/plugins
folder. - In the Android build preset, in the Plugins list, check the Ru Store Godot Pay and Ru Store Godot Core plugins.
- For Godot 4.2.2 and older, in the
your_project/android/build/build.gradle
file, add theresolutionStrategy
section:
android {
...
}
configurations.all {
resolutionStrategy {
force 'androidx.core:core:1.9.0'
force 'androidx.core:core-ktx:1.9.0'
force 'androidx.lifecycle:lifecycle-runtime:2.6.2'
force 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
force 'androidx.lifecycle:lifecycle-livedata:2.6.2'
force 'androidx.lifecycle:lifecycle-livedata-core:2.6.2'
force 'androidx.lifecycle:lifecycle-viewmodel:2.6.2'
force 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
force 'androidx.lifecycle:lifecycle-process:2.6.2'
force 'androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.2'
force 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2'
}
}
SDK Initialization
Initialize the library before calling its methods. The initialization itself is done automatically, however, for your SDK to work, in your Manifest.xml
file define console_app_id_value
and internal_config_key
.
<!-- Initializing sdk -->
<meta-data
android:name="console_app_id_value"
android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data
android:name="internal_config_key"
android:value="@string/rustore_PayClientSettings_internalConfigKey" />
Both values must be placed inside the <application>
tag. Also, add the attribute tools:replace="android:label"
to the <application>
tag.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.godot.game"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="auto" >
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true" />
<uses-feature
android:glEsVersion="0x00030000"
android:required="true" />
<application
android:label="@string/godot_project_name_string"
<!-- Additional attribute -->
tools:replace="android:label"
android:allowBackup="false"
android:icon="@mipmap/icon"
android:appCategory="game"
android:isGame="true"
android:hasFragileUserData="false"
android:requestLegacyExternalStorage="false"
tools:ignore="GoogleAppIndexingWarning" >
<meta-data
android:name="org.godotengine.editor.version"
android:value="${godotEditorVersion}" />
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
android:theme="@style/GodotAppSplashTheme"
android:launchMode="singleInstancePerTask"
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.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Initializing sdk -->
<meta-data
android:name="console_app_id_value"
android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data
android:name="internal_config_key"
android:value="@string/rustore_PayClientSettings_internalConfigKey" />
</application>
</manifest>
console_app_id_value
— product ID form the RuStore Console.
Where are app IDs in the RuStore Console?
- Navigate to the Applications tab and selected the needed app.
- Copy the ID from the URL address of the app page — it is a set of numbers between
apps/
and/versions
. FOr example, for URL addresshttps://console.rustore.ru/apps/123456/versions
the app ID is123456
.
- The
ApplicationId
specified inbuild.gradle
must match theapplicationId
of the APK file you published in the RuStore Console. -
The
keystore
signature must match the signature that was used to sign the app published in the RuStore Console. Make sure thatbuildType
used (example:debug
) uses the same signature as the published app (example:release
).
debug
) of the app must match the signature of the app build that was uploaded to the console and passed moderation (for example, release
)For security purposes, the SDK sets android:usesCleartextTraffic="false"
by default to prevent data transmission over unsecured HTTP and protect against "Man-in-the-Middle" attacks. If your application requires the use of HTTP, you can change this attribute to true
, but do so at your own risk, as it increases the chance of data interception and tampering. We recommend allowing unsecured traffic only in exceptional cases and for trusted domains, preferring HTTPS for all network interactions.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Initializing sdk -->
<string name="rustore_PayClientSettings_consoleApplicationId" translatable="false">198332</string>
<string name="rustore_PayClientSettings_internalConfigKey" translatable="false">godot</string>
</resources>
Handling deeplink
A deeplink in the RuStore Payments SDK is required for proper interaction with third-party payment applications. It helps users complete purchases faster in an external app and return to your application.
To set up deeplink support in your application and the RuStore SDK, specify the deeplinkScheme
inside your AndroidManifest
file and override the onNewIntent
method of your Activity
. Additionally, for the SDK to work, you need to specify sdk_pay_scheme_value
in your Manifest.xml file.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.godot.game"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="auto" >
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true" />
<uses-feature
android:glEsVersion="0x00030000"
android:required="true" />
<application
android:label="@string/godot_project_name_string"
tools:replace="android:label"
android:allowBackup="false"
android:icon="@mipmap/icon"
android:appCategory="game"
android:isGame="true"
android:hasFragileUserData="false"
android:requestLegacyExternalStorage="false"
tools:ignore="GoogleAppIndexingWarning" >
<meta-data
android:name="org.godotengine.editor.version"
android:value="${godotEditorVersion}" />
<meta-data
android:name="console_app_id_value"
android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data
android:name="internal_config_key"
android:value="@string/rustore_PayClientSettings_internalConfigKey" />
<!-- Deeplink scheme -->
<meta-data
android:name="sdk_pay_scheme_value"
android:value="@string/rustore_PayClientSettings_deeplinkScheme" />
<!-- Your activity -->
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
android:theme="@style/GodotAppSplashTheme"
android:launchMode="singleInstancePerTask"
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.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity-alias
android:enabled="true"
android:exported="true"
android:name=".RuStoreDeeplink"
android:targetActivity=".GodotApp" >
<!-- Deeplink 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="@string/rustore_PayClientSettings_deeplinkScheme" />
</intent-filter>
</activity-alias>
</application>
</manifest>
The values sdk_pay_scheme_value
and data android:scheme
should be located in a resource file, for example: your_project/android/build/res/values/rustore_values.xml
.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="rustore_PayClientSettings_consoleApplicationId" translatable="false">198332</string>
<string name="rustore_PayClientSettings_internalConfigKey" translatable="false">godot</string>
<!-- Deeplink scheme -->
<string name="rustore_PayClientSettings_deeplinkScheme" translatable="false">yourappscheme</string>
</resources>
package com.godot.game;
import android.content.Intent;
import android.os.Bundle;
import org.godotengine.godot.GodotActivity;
import ru.rustore.godot.pay.RuStoreGodotPay;
public class GodotApp extends GodotActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.GodotAppMainTheme);
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
RuStoreGodotPay.proceedIntent(getIntent());
}
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
RuStoreGodotPay.proceedIntent(intent);
}
}
The proceedIntent
method has an overload with an additional parameter maxRetryTimeMs: Long
.
long maxRetryTimeMs = 5000L;
RuStoreGodotPay.proceedIntent(intent, maxRetryTimeMs);
maxRetryTimeMs
— the maximum time (in milliseconds) for retrying the initialization of the payment client (default is 5000 ms).
Working with the SDK
Create a RuStoreGodotPayClient
instance before using the plugin methods.
var _pay_client: RuStoreGodotPayClient = RuStoreGodotPayClient.get_instance()
Checking payment availability
To check purchase availability, call the get_purchase_availability
method. On calling, the following conditions are checked.
- The company has monetization enabled via the RuStore Developer Console.
- The application must not be banned in RuStore.
- The user must not be banned in RuStore.
RuStorePayGetPurchaseAvailabilityResult.isAvailable == true
is returned.
Otherwise, RuStorePayGetPurchaseAvailabilityResult.isAvailable == false
and RuStorePayGetPurchaseAvailabilityResult.cause
are returned, where cause
is the error indicating the unmet condition (possible errors are described in the Error Handling section).
Before using the method, you need to subscribe to the events once:
on_get_purchases_availability_success
;on_get_purchases_availability_failure
.
func _ready():
# Initialization of _pay_client
_pay_client.on_get_purchase_availability_success.connect(_on_get_purchase_availability_success)
_pay_client.on_get_purchase_availability_failure.connect(_on_get_purchase_availability_failure)
func _on_get_purchase_availability_success(result: RuStorePayGetPurchaseAvailabilityResult):
pass
func _on_get_purchase_availability_failure(error: RuStoreError):
pass
_pay_client.get_purchase_availability()
Checking user authorization status
To check the user's authorization status, call the get_user_authorization_status
method. The result of this method is a value from the ERuStorePayUserAuthorizationStatus.Item
enumeration:
AUTHORIZED
— the user is authorized in RuStore.UNAUTHORIZED
— the user is not authorized in RuStore. This value will also be returned if the user does not have the RuStore app installed on the device.
Before using the method, you need to subscribe to the events once:
on_get_user_authorization_status_success
;on_get_user_authorization_status_failure
.
func _ready():
# Initialization of _pay_client
_pay_client.on_get_user_authorization_status_success.connect(_on_get_user_authorization_status_success)
_pay_client.on_get_user_authorization_status_failure.connect(_on_get_user_authorization_status_failure)
func _on_get_user_authorization_status_success(result: ERuStorePayUserAuthorizationStatus.Item):
pass
func _on_get_user_authorization_status_failure(error: RuStoreError):
pass
_pay_client.get_user_authorization_status()
Getting a list of products
You checked that payments are available and the users are able to make purchases. Now you can request products list. Use the get_products
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
.
func _ready():
# _pay_client initialization
_pay_client.on_get_products_success.connect(_on_get_products_success)
_pay_client.on_get_products_failure.connect(_on_get_products_failure)
func _on_get_products_success(products: Array[RuStorePayProduct]):
pass
func _on_get_products_failure(error: RuStoreError):
pass
var PRODUCT_IDS: Array[RuStorePayProductId] = [
RuStorePayProductId.new("con_1"),
RuStorePayProductId.new("non_con_1"),
]
_pay_client.get_products(PRODUCT_IDS)
product_ids
— the list of product IDs that are set when products are created in the RuStore Console. The list is limited by 1000 items.
Where are product IDs in the RuStore Console?
- Navigate to the Applications tab and selected the needed app.
- Select Monetization in the left menu.
- Select product type: Subscriptions or In-App purchases.
- Copy the IDs of the required products.
The method returns products list. Below is the product pattern.
class_name RuStorePayProduct extends Object
var productId: RuStorePayProductId = null
var type: ERuStorePayProductType.Item = 0
var amountLabel: RuStorePayAmountLabel = null
var price: RuStorePayPrice = null
var currency: RuStorePayCurrency = null
var imageUrl: RuStorePayUrl = null
var title: RuStorePayTitle = null
var description: RuStorePayDescription = null
productId
— product ID assigned to product in RuStore Console (mandatory).type
— product type:CONSUMABLE
/NON-CONSUMABE
.-
amountLabel
— formatted purchase price, including currency symbol price
— price in minimum currency units.currency
— ISO 4217 currency code.title
— product name inlanguage
.description
— descriptions inlanguage
.imageUrl
— image URL.
Getting a list of purchases
To get a list of the user's purchases, use the get_purchases
method.
Before using the methods, you must subscribe to the events once:
on_get_purchases_success
;on_get_purchases_failure
.
func _ready:
# Initialize _pay_client
_pay_client.on_get_purchases_success.connect(_on_get_purchases_success)
_pay_client.on_get_purchases_failure.connect(_on_get_purchases_failure)
func _on_get_purchases_success(purchases: Array[RuStorePayPurchase]):
#
# Processing
#
# Free memory
for purchase in purchases:
if is_instance_valid(purchase):
purchase.free()
purchases.clear()
func _on_get_purchases_failure(error: RuStoreError):
#
# Processing
#
# Free memory
error.free()
# Initialize _pay_client
# Call without filter
_pay_client.get_purchases()
# Call with filter
var productType = ERuStorePayProductType.Item.CONSUMABLE_PRODUCT
var purchase_status = ERuStorePayPurchaseStatus.Item.CONFIRMED
_pay_client.get_purchases(productType, purchase_status)
The purchase model is presented below.
class_name RuStorePayPurchase extends Object
var amountLabel: RuStorePayAmountLabel = null
var currency: RuStorePayCurrency = null
var description: RuStorePayDescription = null
var developerPayload: RuStorePayDeveloperPayload = null
var invoiceId: RuStorePayInvoiceId = null
var orderId: RuStorePayOrderId = null
var price: RuStorePayPrice = null
var productId: RuStorePayProductId = null
var productType: ERuStorePayProductType.Item = 0
var purchaseId: RuStorePayPurchaseId = null
var purchaseTime: RuStorePayTime = null
var purchaseType: ERuStorePayPurchaseType.Item = 0
var quantity: RuStorePayQuantity = null
var status: ERuStorePayPurchaseStatus.Item = 0
var sandbox: bool = false
purchaseId
— product ID. Used to obtain purchase information in the SDK via the purchase information retrieval method.productId
— product ID assigned to product in RuStore Console (mandatory).invoiceId
— invoice ID. Used for server-side payment validation, searching payments in the developer console, and is also displayed to the user in the payment history in the RuStore mobile app.orderId
- unique payment identifier specified by the developer or generated automatically (uuid
).PurchaseType
— purchase type:ONE_STEP
- one-stage payment;TWO_STEP
- two-stage payment;UNDEFINED
— number of payment stages is undefined.
productType
— product type. (CONSUMABLE
/NON-CONSUMABLE
- consumable/non-consumable.)description
- purchase description.purchaseTime
— purchase time.price
— price in minimum currency units.amountLabel
— formatted purchase price, including currency symbol.currency
— ISO 4217 currency code.quantity
— product quantity.status
— purchase state:INVOICE_CREATED
— purchase invoice is created and awaiting payment;CANCELLED
— purchase canceled by the user;PROCESSING
— payment initiated;REJECTED
— purchase rejected (for example: due to insufficient funds);EXPIRED
— payment time expired;PAID
— only for two-stage payments, intermediate status, funds are put on hold on the user's account, the purchase is awaiting confirmation from the developer;CONFIRMED
— purchase successfully paid for;REFUNDING
— refunding initiated, request sent to the acquirer;REFUNDED
— purchase successfully refunded;REVERSED
— only for two-stage payment: wither the purchase was canceled by the developer or there was no payment within 6 hours, the funds on the user's account are put off hold.
-
developerPayload
— a string with additional order information that you can set when confirming the purchase. This string overrides the value set during initialization -
— test payment flag.
true
— test payment,false
— actual payment
Getting purchase information
Go get purchase information, use theget_purchase
method.
func _ready:
# Initialize _pay_client
_pay_client.on_get_purchase_success(_on_get_purchase_success)
_pay_client.on_get_purchase_failure(_on_get_purchase_failure)
func _on_get_purchase_success(purchase: RuStorePayPurchase):
pass
func _on_get_purchase_failure(purchase_id: RuStorePayPurchaseId, error: RuStoreError):
#
# Processing
#
# Free memory
error.free()
var purchase_id: RuStorePayPurchaseId = ...
_pay_client.get_purchase(purchase_id)```
The method returns information about a specific purchase in any status. The purchase model is presented below.
```js title="Purchase information structure"
class_name RuStorePayPurchase extends Object
var amountLabel: RuStorePayAmountLabel = null
var currency: RuStorePayCurrency = null
var description: RuStorePayDescription = null
var developerPayload: RuStorePayDeveloperPayload = null
var invoiceId: RuStorePayInvoiceId = null
var orderId: RuStorePayOrderId = null
var price: RuStorePayPrice = null
var productId: RuStorePayProductId = null
var productType: ERuStorePayProductType.Item = 0
var purchaseId: RuStorePayPurchaseId = null
var purchaseTime: RuStorePayTime = null
var purchaseType: ERuStorePayPurchaseType.Item = 0
var quantity: RuStorePayQuantity = null
var status: ERuStorePayPurchaseStatus.Item = 0
var sandbox: bool = false
purchaseId
— product ID. Used to obtain purchase information in the SDK via the purchase information retrieval method.productId
— product ID assigned to product in RuStore Console (mandatory).invoiceId
— invoice ID. Used for server-side payment validation, searching payments in the developer console, and is also displayed to the user in the payment history in the RuStore mobile app.orderId
- unique payment identifier specified by the developer or generated automatically (uuid
).PurchaseType
— purchase type:ONE_STEP
- one-stage payment;TWO_STEP
- two-stage payment;UNDEFINED
— number of payment stages is undefined.
productType
— product type. (CONSUMABLE
/NON-CONSUMABLE
- consumable/non-consumable.)description
- purchase description.purchaseTime
— purchase time.price
— price in minimum currency units.amountLabel
— formatted purchase price, including currency symbol.currency
— ISO 4217 currency code.quantity
— product quantity.status
— purchase state:INVOICE_CREATED
— purchase invoice is created and awaiting payment;CANCELLED
— purchase canceled by the user;PROCESSING
— payment initiated;REJECTED
— purchase rejected (for example: due to insufficient funds);EXPIRED
— payment time expired;PAID
— only for two-stage payments, intermediate status, funds are put on hold on the user's account, the purchase is awaiting confirmation from the developer;CONFIRMED
— purchase successfully paid for;REFUNDING
— refunding initiated, request sent to the acquirer;REFUNDED
— purchase successfully refunded;REVERSED
— only for two-stage payment: wither the purchase was canceled by the developer or there was no payment within 6 hours, the funds on the user's account are put off hold.
-
developerPayload
— a string with additional order information that you can set when confirming the purchase. This string overrides the value set during initialization -
— test payment flag.
true
— test payment,false
— actual payment
Purchase status model
One-stage payment status model.
Two-stage payment status model.
Purchasing a product
- When using a one-step payment, the purchase does not require confirmation, funds are immediately debited from the buyer's account, and a commission is withheld from the developer. In this case, if a refund is needed (for example, if the product cannot be delivered for some reason), it can only be done through the RuStore Console. The funds are returned to the buyer after a few days. The full purchase price is refunded, but the withheld commission is not returned to the developer.
- When using a two-step payment, the funds are first held on the buyer's account. No commission is withheld at this stage. After being held, the purchase requires confirmation or cancellation. The commission is withheld from the developer upon confirmation of the purchase. Canceling the purchase releases the hold, and the funds are instantly available to the buyer again.
Two-step payment is only available for a specific set of payment methods (currently, only for cards). Faster Payments System (SBP) technologies do not support two-step payments. If a payment method is chosen that does not support holding, the purchase will be initiated as a one-step process.
Payment with purchase type selection
To initiate a product purchase with a choice of payment stages, use the purchase
method.
Before using the method, you must subscribe to the events once:
on_purchase_success
;on_purchase_failure
.
func _ready():
# Initialize _pay_client
_pay_client.on_purchase_success(_on_purchase_success)
_pay_client.on_purchase_failure(_on_purchase_failure)
func _on_purchase_success(result: RuStorePayProductPurchaseResult):
#
# Processing
#
# Free memory
result.free()
func _on_purchase_failure(product_id: RuStorePayProductId, error: RuStoreError):
#
# Processing
#
# Free memory
error.free()
var parameters = RuStorePayProductPurchaseParams.new(
RuStoreProductId.new("product_id"), # productId
null, # appUserEmail
null, # appUserId
null, # developerPayload
null, # orderId
RuStoreQuantity.new(1)); # quantity
var preferredPurchaseType = ERuStorePayPreferredPurchaseType.Item.ONE_STEP
_pay_client.purchase(parameters, preferredPurchaseType)
productId
— product ID assigned to product in RuStore Console (mandatory).quantity
— product amount (optional, value1
will be used if not specified).orderId
— payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. If not specified, will be generated automatically (uuid). 150 characters max.developerPayload
— a string with additional order information that you can set when confirming the purchase. This string overrides the value set during initialization. Maximum length is 250 characters.-
appUserId
— the internal user ID in your application (optional parameter). A string with a maximum length of 128 characters.tipFor example, this parameter can be used to detect cases of fraud in your application, which will help improve its security.
appUserEmail
— this is an optional parameter that allows you to specify the user's email address in your application. If the buyer's email address was provided during registration in the app, it can be passed for automatic filling of theemail
field when sending a receipt — both for payments outside RuStore and in cases where the user is not authorized in RuStore. This saves the user from having to manually enter their email, shortens the purchase flow, and helps increase conversion.preferredPurchaseType
— the desired purchase type: single-stage (ONE_STEP
) or two-stage (TWO_STEP
).
This method is launched by default using the single-stage payment scenario (preferredPurchaseType = ERuStorePayPreferredPurchaseType.Item.ONE_STEP
), i.e., without funds being held.
For two-stage payment, you need to specify preferredPurchaseType = ERuStorePayPreferredPurchaseType.Item.TWO_STEP
. Two-stage payment (i.e., payment with funds being held) is not guaranteed for this method and directly depends on the payment method (card, SPB, etc.) selected by the user.
When launching this method (with the preferred preferredPurchaseType = twoStep
), until the user selects a payment method, the purchase stage will be UNDEFINED
. Please take this behavior into account when handling purchase cancellation results (ProductPurchaseCancelled
) or purchase errors (ProductPurchaseException
).
Two-step payment (with fund holding)
When calling this method, the user will be offered a limited set of payment methods — only those that support two-step payments.
purchase_two_step
method.
Before using the method, you must subscribe to the events once:
on_purchase_two_step_success
;on_purchase_two_step_failure
.
func _ready():
# Initialize _pay_client
_pay_client.on_purchase_two_step_success(_on_purchase_two_step_success)
_pay_client.on_purchase_two_step_failure(_on_purchase_two_step_failure)
func _on_purchase_two_step_success(result: RuStorePayProductPurchaseResult):
#
# Processing
#
# Free memory
result.free()
func _on_purchase_two_step_failure(product_id: RuStorePayProductId, error: RuStoreError):
#
# Processing
#
# Free memory
error.free()
var parameters = RuStorePayProductPurchaseParams.new (
RuStoreProductId.new("product_id"), # productId
null, # appUserEmail
null, # appUserId
null, # developerPayload
null, # orderId
RuStoreQuantity.new(1)); # quantity
);
_pay_client.purchase_two_step(parameters)
Purchase parameters structure
class_name RuStorePayProductPurchaseParams extends RefCounted
var productId: RuStorePayProductId = null
var appUserEmail: RuStorePayAppUserEmail = null
var appUserId: RuStorePayAppUserId = null
var developerPayload: RuStorePayDeveloperPayload = null
var orderId: RuStorePayOrderId = null
var quantity: RuStorePayQuantity = null
func _init(
productId: RuStorePayProductId,
appUserEmail: RuStorePayAppUserEmail = null,
appUserId: RuStorePayAppUserId = null,
developerPayload: RuStorePayDeveloperPayload = null,
orderId: RuStorePayOrderId = null,
quantity: RuStorePayQuantity = null
):
self.productId = productId
self.appUserEmail = appUserEmail
self.appUserId = appUserId
self.developerPayload = developerPayload
self.orderId = orderId
self.quantity = quantity
productId
— product ID assigned to product in RuStore Console (mandatory).quantity
— product amount (optional, value1
will be used if not specified).orderId
— payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. If not specified, will be generated automatically (uuid). 150 characters max.developerPayload
— a string with additional order information that you can set when confirming the purchase. This string overrides the value set during initialization. Maximum length is 250 characters.-
appUserId
— the internal user ID in your application (optional parameter). A string with a maximum length of 128 characters.tipFor example, this parameter can be used to detect cases of fraud in your application, which will help improve its security.
appUserEmail
— this is an optional parameter that allows you to specify the user's email address in your application. If the buyer's email address was provided during registration in the app, it can be passed for automatic filling of theemail
field when sending a receipt — both for payments outside RuStore and in cases where the user is not authorized in RuStore. This saves the user from having to manually enter their email, shortens the purchase flow, and helps increase conversion.
class_name RuStorePayProductPurchaseResult extends Object
var invoiceId: RuStorePayInvoiceId = null
var orderId: RuStorePayOrderId = null
var productId: RuStorePayProductId = null
var purchaseId: RuStorePayPurchaseId = null
var purchaseType: ERuStorePayPurchaseType.Item = 0
var quantity: RuStorePayQuantity = null
var sandbox: bool = false
invoiceId
— invoice identifier. Used for server-side payment validation, searching for payments in the developer console, and is also displayed to the buyer in the payment history in the RuStore mobile app.orderId
— unique payment identifier, specified by the developer or generated automatically (uuid
).productId
— identifier of the purchased product, specified when creating it in the RuStore developer console.purchaseId
— purchase identifier. Used to get purchase information in the SDK using the get purchase information method.purchaseType
— purchase type (ONE_STEP
/TWO_STEP
/UNKNOWN
— one-step/two-step/stage undefined).quantity
— product quantity.sandbox
— a flag indicating a test payment in the sandbox. IfTRUE
- the purchase was made in test mode.
Handling payment errors
If an error occurs during the payment process or the user cancels the purchase, the execution of the payment method (both with the selection of the purchase type and the two-stage method) will terminate with an error:
ProductPurchaseException
— product purchase error.ProductPurchaseCancelled
— an error caused by the cancellation of a product purchase (the user closed the payment bottom sheet) before receiving the purchase result. In this case, it is recommended to additionally check the purchase status using the method for obtaining purchase information.
Error and purchase cancellation structure:
class ProductPurchaseException extends RuStorePaymentException:
var invoiceId: RuStorePayInvoiceId = null
var orderId: RuStorePayOrderId = null
var productId: RuStorePayProductId = null
var purchaseId: RuStorePayPurchaseId = null
var purchaseType: ERuStorePayPurchaseType.Item = 0
var quantity: RuStorePayQuantity = null
var sandbox: bool = false
class ProductPurchaseCancelled extends RuStorePaymentException:
var purchaseId: RuStorePayPurchaseId = null
var purchaseType: ERuStorePayPurchaseType.Item = 0
func _on_any_purchase_failure(product_id: RuStorePayProductId, error: RuStoreError):
if is_instance_of(error, RuStorePaymentException.ProductPurchaseCancelled):
var cancelled_error = error as RuStorePaymentException.ProductPurchaseCancelled
OS.alert(cancelled_error.purchaseId.value, error.name)
elif is_instance_of(error, RuStorePaymentException.ProductPurchaseException):
var exception_error = error as RuStorePaymentException.ProductPurchaseException
OS.alert(exception_error.purchaseId.value, error.name)
else:
OS.alert(error.description, error.name)
# Free memory
error.free()
Server-side purchase validation
If you need to validate a purchase on the RuStore server, you can use subscriptionToken
in SuccessProductPurchaseResult
, that is returned on successful purchase.
func _on_purchase_two_step_success(result: RuStorePayProductPurchaseResult):
if result is RuStorePayProductPurchaseResult.SuccessProductPurchaseResult:
yourApi.validate(result.subscriptionToken);
You can also get a subscriptionToken
from the Purchase
entity. The Purchase
entity can be retrieved using the get_purchases
method.
func _on_get_purchases_success(purchases: Array[RuStorePayPurchase]):
for item in purchases:
yourApi.validate(item.subscriptionToken);
Confirming (consuming) a purchase
Us theconsume_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
.
Before using the method, you must subscribe to the events once:
on_confirm_two_step_purchase_success
;on_confirm_two_step_purchase_failure
.
func _ready:
# Initialize _pay_client
_pay_client.on_confirm_two_step_purchase_success(_on_confirm_two_step_purchase_success)
_pay_client.on_confirm_two_step_purchase_failure(_on_confirm_two_step_purchase_failure)
func _on_confirm_two_step_purchase_success(purchase_id: RuStorePayPurchaseId):
pass
func _on_confirm_two_step_purchase_failure(purchase_id: RuStorePayPurchaseId, error: RuStoreError):
#
# Processing
#
# Free memory
error.free()
var id: RuStorePayPurchaseId = ...
var payload: RuStorePayDeveloperPayload = ...
_pay_client.confirm_two_step_purchase(id, payload)
id
— product ID.-
payload
— a string with additional order information that you can set when confirming the purchase. This string overrides the value set during initialization
Canceling a purchase
To cancel a purchase, use thecancel_two_step_purchase
method.
Before using the method, you must subscribe to the events once:
on_cancel_two_step_purchase_success
;on_cancel_two_step_purchase_failure
.
func _ready:
# Initialize _pay_client
_pay_client.on_cancel_two_step_purchase_success(_on_cancel_two_step_purchase_success)
_pay_client.on_cancel_two_step_purchase_failure(_on_cancel_two_step_purchase_failure)
func _on_cancel_two_step_purchase_success(purchase_id: RuStorePayPurchaseId):
pass
func _on_cancel_two_step_purchase_failure(purchase_id: RuStorePayPurchaseId, error: RuStoreError):
#
# Processing
#
# Free memory
error.free()
# Your implementation of the purchase cancellation UI
func _on_cancel_two_step_purchase_pressed(purchaseId: RuStorePayPurchaseId):
_pay_client.cancel_two_step_purchase(purchaseId)
purchaseId
— product ID
- The
on_cancel_two_step_purchase_success
callback returns the purchase identifier. - The
on_cancel_two_step_purchase_failure
callback returns the purchase identifier of typeString
and aRuStoreError
object with error information. The error structure is described in the Error Handling section.
RuStoreUtils
RuStoreUtils is a block in the native SDK that contains a set of public methods for interacting with the RuStore application on the user's device.
To access the block's methods in the Godot environment, the RuStoreGodotCoreUtils
class singleton is used.
The is_rustore_installed
method checks if the RuStore application is installed on the user's device.
var _core_client: RuStoreGodotCoreUtils = RuStoreGodotCoreUtils.get_instance()
var is_rustore_installed: Variant = _core_client.is_rustore_installed()
if is_rustore_installed == true:
print("RuStore is installed on the user's device")
elif is_rustore_installed == false:
print("RuStore is not installed on the user's device")
else:
print("State is unknown (null)")
The open_rustore_download_instruction
method opens a web page to download the RuStore mobile application.
var _core_client: RuStoreGodotCoreUtils = RuStoreGodotCoreUtils.get_instance()
_core_client.open_rustore_download_instruction();
The open_rustore
method launches the RuStore mobile application. When calling this method, if the RuStore application is not installed, a Toast notification with the message "Failed to open the application" will be displayed.
var _core_client: RuStoreGodotCoreUtils = RuStoreGodotCoreUtils.get_instance()
_core_client.Instance.open_rustore();
The open_rustore_authorization
method launches the RuStore mobile application for authorization. After successful user authorization, the RuStore application closes automatically. When calling this method, if the RuStore application is not installed, a Toast notification with the message "Failed to open the application" will be displayed.
var _core_client: RuStoreGodotCoreUtils = RuStoreGodotCoreUtils.get_instance()
_core_client.Instance.open_rustore_authorization();
List of errors
RuStoreError — the base error class.
class_name RuStoreError extends Object
var name: String = ""
var description: String = ""
name
– error name.description
– error description.
RuStorePaymentException — the base error class for the payment client.
class_name RuStorePaymentException extends RuStoreError
var cause: RuStoreError = null
...
func _notification(what):
if what == NOTIFICATION_PREDELETE:
if is_instance_valid(cause):
cause.free()
cause = null```
* <Cause name="cause"/>.
Inherited fields:
* <NameError name="name"/>.
* <DescriptionError name="description"/>.
**RuStorePaymentNetworkException** — SDK network interaction error. The error model returns an error code (the `code` field), which can be used to determine the cause of the error. A table with error codes is available in the error codes section.
```js title="RuStorePaymentNetworkException Class"
class_name RuStorePaymentException extends RuStoreError
...
class RuStorePaymentNetworkException extends RuStorePaymentException:
var code = ""
var id: String = ""
code
— error code.id
— error identifier.
Inherited fields:
name
– error name.description
– error description.cause
– additional error information.
Possible errors
RuStorePaymentNetworkException
— SDK network communication error;RuStorePaymentCommonException
— general SDK error;RuStorePayClientAlreadyExist
— SDK re-initialization error;RuStorePayClientNotCreated
— attempt to access public SDK interfaces before initialization;RuStorePayInvalidActivePurchase
— payment initiated for unknown product type;RuStorePayInvalidConsoleAppId
— required parameterconsole_application_id
for SDK initialization is not specified;RuStorePaySignatureException
— invalid response signature. Occurs when attempting fraudulent actions;EmptyPaymentTokenException
— error obtaining payment token;InvalidCardBindingIdException
— error paying with a saved card;ApplicationSchemeWasNotProvided
— scheme for the return deeplink is not specified;ProductPurchaseException
— product purchase error. The model structure is described in the section purchase result structure;ProductPurchaseCancelled
— product purchase was cancelled (the user closed the payment sheet). The model structure is described in the section purchase result structure;ProductPurchaseException
— product purchase error;RuStoreNotInstalledException
— RuStore is not installed on the user's device;RuStoreOutdatedException
— the installed version of RuStore on the device does not support payments;RuStoreUserUnauthorizedException
— the user is not authorized in RuStore;RuStoreApplicationBannedException
— the application is banned in RuStore;RuStoreUserBannedException
— the user is banned in RuStore.