9.0.2
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.
Implementation Example
Look at the example app to learn how to integrate our SDK.
Adding to the Project
Installing Plugins
- Installation via Package Manager
- Installation via .unitypackage
To connect, download the packages from the upm_tgz page:
ru.rustore.core-x.y.z.tgz
ru.rustore.pay-x.y.z.tgz
Import the packages into the project via the Package Manager (Window → Package Manager → + → Add package from tarball...).
If you are using the macOS operating system, change the settings of the archive utility. In the Archive Utility settings, uncheck the Keep expanding if possible option. Otherwise, the project archive will be downloaded incorrectly.
To connect, download the file RuStoreUnityPaySDK-version.unitypackage
and import it into the project (Assets → Import Package → Custom Package). Dependencies are automatically connected using the External Dependency Manager (included in the .unitypackage
).
If you are using the macOS operating system, change the settings of the archive utility. In the Archive Utility settings, uncheck the Keep expanding if possible option. Otherwise, the project archive will be downloaded incorrectly.
To correctly handle SDK dependencies, perform the following configuration steps:
-
Open the project settings: Edit → Project Settings → Player → Android Settings.
-
In the Publishing Settings section, enable the following options:
- Custom Main Manifest
- Custom Main Gradle Template
- Custom Gradle Properties Template
-
In the Other Settings section, configure the following:
- Package Name
- Minimum API Level = 24
- Target API Level = 34
-
Open the External Dependency Manager settings: Assets → External Dependency Manager → Android Resolver → Settings, and enable the following options:
- Use Jetifier
- Patch mainTemplate.gradle
- Patch gradleTemplate.properties
Adding Dependencies
- Automatic Dependency Resolution
- Manual Dependency Resolution
Dependencies for the Android build are automatically connected using the External Dependency Manager tool.
To automatically resolve dependencies, use the command: Assets → External Dependency Manager → Android Resolver → Force Resolve. This operation should be performed every time new versions of plugins are added or when the files Assets/Plugins/Android/mainTemplate.gradle and Assets/Plugins/Android/settingsTemplate.gradle are regenerated.
-
When installing RuStore plugins via a *.unitypackage, the External Dependency Manager does not require any special installation steps.
-
When installing RuStore plugins via the Package Manager, perform the following steps:
- Open the RuStore Core plugin tab in the Package Manager window: Window → Package Manager → Packages RuStore → RuStore Core.
- Switch to the Samples tab.
- Import the External Dependency Manager sample.
-
The latest version of External Dependency Manager can also be obtained from the developer’s repository on GitHub:
- Open the Package Manager window: Window → Package Manager → + → Add package from git URL....
- Use the URL
https://github.com/googlesamples/unity-jar-resolver.git?path=/upm
to add the package. - To resolve the error "Google.IOSResolver.dll will not be loaded", install the iOS Build Support module for your Unity version via UnityHub → Installs → Your Unity version → Add modules → iOS Build Support.
<!-- Example error message -->
<Assembly 'Packages/com.google.external-dependency-manager/ExternalDependencyManager/Editor/1.2.182/Google.IOSResolver.dll' will not be loaded due to errors:
Unable to resolve reference 'UnityEditor.iOS.Extensions.Xcode'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.>
- Open the mainTemplate.gradle file: Assets / Plugins / Android / mainTemplate.gradle. In the dependencies section, add the following lines:
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'ru.rustore.sdk:pay:x.y.z'
Example of the dependencies section:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'ru.rustore.sdk:pay:x.y.z'
}
where x.y.z is the SDK package version number.
- Open the settingsTemplate.gradle file: Assets / Plugins / Android / settingsTemplate.gradle. In the dependencyResolutionManagement repositories section, add the following lines:
maven {
url "https://artifactory-external.vkpartner.ru/artifactory/maven"
}
Example of the dependencyResolutionManagement repositories section:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/")
maven {
url "https://artifactory-external.vkpartner.ru/artifactory/maven"
}
mavenLocal()
flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}
}
}
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
. Both values must be located inside the <application>
tag.
<!-- 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" />
Also, to ensure the correct behavior of the payment sheet when the application is minimized, the game activity must be set to the android:launchMode="singleTop"
launch mode.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application>
<!-- Launch mode -->
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/UnityThemeSelector"
android:launchMode="singleTop"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</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 Package Name of the application, specified in Edit → Project Settings... → Player > Android → Other Settings → Package Name, must match the Package Name of the APK file that you published in the RuStore Console.
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 console_app_id_value
value is set in the PayClientSettings.assets
file. To create the PayClientSettings.assets
file, in the Unity editor menu, select: Window → RuStore SDK → Settings → PayClient.
The internal_config_key
value is set in the PayClientSettings.assets
file automatically.
Do not set the console_app_id_value
and internal_config_key
values directly in the manifest. The strings must be located in the resource file, which is generated automatically based on the data from PayClientSettings.assets
.
Handling Deeplinks
Deeplink in the RuStore SDK for payments is needed for proper interaction with third-party payment applications. It helps users make purchases faster in a third-party app and return to your app.
To set up deeplink handling in your application:
- Create an
intent-filter
tag inside the game activity specifying yourDeeplink Scheme
. - Create a
meta-data
tag inside<application>
specifying yourDeeplink Scheme
. - Override the
onCreate
andonNewIntent
methods of the game activity.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="ru.rustore.unitysdk.RuStoreUnityPayActivity"
android:theme="@style/UnityThemeSelector"
android:launchMode="singleTop"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 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>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
<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" />
</application>
</manifest>
The Deeplink Scheme
value is set in the PayClientSettings.assets
file. To create the PayClientSettings.assets
file, in the Unity editor menu, select: Window → RuStore SDK → Settings → PayClient.
Next, extend the UnityPlayerActivity
class and add handling of the incoming intent
in onCreate
and onNewIntent
.
package ru.rustore.unitysdk;
import android.os.Bundle;
import android.content.Intent;
import ru.rustore.unitysdk.payclient.RuStoreUnityPayClient;
import com.unity3d.player.UnityPlayerActivity;
public class RuStoreUnityPayActivity extends UnityPlayerActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
RuStoreUnityPayClient.INSTANCE.proceedIntent(getIntent());
}
}
@Override protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
RuStoreUnityPayClient.INSTANCE.proceedIntent(intent);
}
}
Place the Java file with the UnityPlayerActivity
extension code in the project's Assets
folder. If you already have your own UnityPlayerActivity
extension, transfer the code of the onCreate
and onNewIntent
functions into it.
Working with the SDK
Available public methods:
GetPurchase
— allows you to get information about a purchase by its ID.GetPurchases
— allows you to retrieve user purchases. This method supports optional filtering by product type (consumable or non-consumable products), as well as by purchase status (statusesPAID
andCONFIRMED
are supported). By default, the filters are disabled, and all user purchases (regardless of product type) with statusesPAID
andCONFIRMED
will be returned.GetPurchaseAvailability
— returns the result of checking payment availability.Purchase
— allows you to make a product purchase with the desired payment type specified: single-stage (ONE_STEP
) or two-stage (TWO_STEP
). For this method, all payment options are available on the payment sheet. If the parameter is not specified, single-stage payment is used by default.
If the payment type TWO_STEP
is specified, an attempt will be made to initiate a two-stage payment, but the final result will directly depend on the payment method (card, SBP, etc.) selected by the user. Two-stage payment is available only for a specific set of payment methods (currently — only for cards). SBP technologies do not support two-stage payment. If a payment method that does not support holding is selected, the purchase will be processed using the single-stage scenario.
PurchaseTwoStep
— initiates a guaranteed two-stage purchase scenario. When using this method, the payment sheet presents the user only with payment methods that support two-stage payment. During the payment process, the buyer's funds are first held and are debited only after the purchase is confirmed using theConfirmTwoStepPurchase
method.ConfirmTwoStepPurchase
— confirms a purchase made using two-stage payment.CancelTwoStepPurchase
— cancels a purchase made using two-stage payment.GetProducts
— allows you to get information about active products published in the RuStore console.
This method returns no more than 1000 products and works without authorization or the RuStore app being installed on the user's device.
RuStoreCoreClient.Instance
block — a set of public methods, such as:IsRuStoreInstalled
— checks if the RuStore app is installed on the user's device.OpenRuStoreDownloadInstruction
— opens a web page for downloading the RuStore app.OpenRuStore
— launches the RuStore app.OpenRuStoreAuthorization
— launches the RuStore app for authorization. After successful user authorization, the RuStore app will automatically close.
Checking Payment Availability
To check purchase availability, call the GetPurchaseAvailability
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.
PurchaseAvailabilityResult.isAvailable == true
is returned.
Otherwise, PurchaseAvailabilityResult.isAvailable == false
and PurchaseAvailabilityResult.cause
are returned, where cause
is the error indicating the unmet condition (possible errors are described in the Error Handling section).
RuStorePayClient.Instance.GetPurchaseAvailability(
onFailure: (error) => {
// Process error
},
onSuccess: (result) => {
if (result.isAvailable) {
// Process success
}
else {
// Process result.cause
}
});
Checking User Authorization Status
To check the user's authorization status, call the GetUserAuthorizationStatus
method. The result of this method is a value from the UserAuthorizationStatus
enumeration. Only two values are possible:
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.
RuStorePayClient.Instance.GetUserAuthorizationStatus(
onFailure: (error) => {
// Process error
},
onSuccess: (result) => {
if (result == UserAuthorizationStatus.AUTHORIZED) {
// Process success
}
});
Retrieving Product List
You checked 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.
ProductId[] ids = ...
RuStorePayClient.Instance.GetProducts(
productIds: ids,
onFailure: (error) => {
// Process error
},
onSuccess: (result) => {
// Process success
});
ProductId[] productIds
— 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.
public class Product : BaseFields {
public AmountLabel amountLabel { get; }
public Currency currency { get; }
public Description? description { get; }
public Url imageUrl { get; }
public Price? price { get; }
public ProductId productId { get; }
public Title title { get; }
public ProductType type { get; }
...
}
productId
— product ID assigned to product in RuStore Console (mandatory).type
— product type.CONSUMABLE/NON-CONSUMABLE
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.
Retrieving Purchase List
Go get the user's purchases list, use theGetPurchases
method.
RuStorePayClient.Instance.GetPurchases(
onFailure: (error) => {
// Process error
},
onSuccess: (result) => {
// Process success
});
This method supports optional filtering by product type (consumable or non-consumable products), as well as by purchase status (only PAID
and CONFIRMED
statuses are supported). By default, the filter is disabled and will return all user purchases (regardless of product type) with statuses PAID
and CONFIRMED
. The PAID
status means that the funds have been successfully held and the purchase is awaiting confirmation from the developer.
RuStorePayClient.Instance.GetPurchases(
productType: ProductType.CONSUMABLE_PRODUCT,
purchaseStatus: PurchaseStatus.CONFIRMED,
onFailure: (error) => {
// Process error
},
onSuccess: (result) => {
// Process success
});
The purchase model is shown below.
public class Purchase : BaseFields {
public PurchaseId purchaseId { get; }
public ProductId productId { get; }
public InvoiceId invoiceId { get; }
public OrderId? orderId { get; }
public PurchaseType purchaseType { get; }
public ProductType productType { get; }
public Description description { get; }
public DateTime? purchaseTime { get; }
public Price price { get; }
public AmountLabel amountLabel { get; }
public Currency currency { get; }
public Quantity quantity { get; }
public PurchaseStatus status { get; }
public DeveloperPayload? developerPayload { get; }
public bool sandbox { get; }
...
}
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
Retrieving Purchase Details
Go get purchase information, use thegetPurchase
method.
RuStorePayClient.Instance.GetPurchase(
purchaseId: purchase.purchaseId,
onFailure: (error) => {
// Process error
},
onSuccess: (response) => {
// Process success
});
The method returns information about a specific purchase in any status. The purchase model is shown below.
public class Purchase : BaseFields {
public PurchaseId purchaseId { get; }
public ProductId productId { get; }
public InvoiceId invoiceId { get; }
public OrderId? orderId { get; }
public PurchaseType purchaseType { get; }
public ProductType productType { get; }
public Description description { get; }
public DateTime? purchaseTime { get; }
public Price price { get; }
public AmountLabel amountLabel { get; }
public Currency currency { get; }
public Quantity quantity { get; }
public PurchaseStatus status { get; }
public DeveloperPayload? developerPayload { get; }
public bool sandbox { get; }
...
}
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.
Product Purchase
- When using a single-stage payment, the purchase does not require confirmation; the funds are immediately debited from the buyer’s account, and a commission is charged to the developer. In this case, if a refund to the customer is required (for example, if the product cannot be delivered for some reason), a refund can only be processed via the RuStore Console, and the funds will be returned to the buyer within a few days. The full purchase amount is refunded, but the commission previously withheld from the developer is not reimbursed.
- In the case of a two-stage payment, the funds are first held (authorized) on the buyer’s account. No commission is charged at this stage. After the hold, the purchase requires either confirmation or cancellation. The commission is charged to the developer upon purchase confirmation. Cancelling the purchase releases the hold, and the funds instantly become available to the buyer again.
Two-stage payment is available only for a specific set of payment methods (currently — only for cards). SBP technologies do not support two-stage payment. If a payment method that does not support holding funds is selected, the purchase will be processed using the single-stage scenario.
Payment with Purchase Type Selection
To initiate a product purchase with the option to select the payment stage, use the Purchase
method:
var parameters = new ProductPurchaseParams(
productId: new ProductId("product_id"),
appUserEmail: null,
appUserId: null,
developerPayload: null,
orderId: null,
quantity: new Quantity(1)
);
RuStorePayClient.Instance.Purchase(
parameters: parameters,
preferredPurchaseType: PreferredPurchaseType.ONE_STEP,
onFailure: (error) => {
switch (error) {
case RuStorePaymentException.ProductPurchaseCancelled cancelled:
// Handle cancelled purchase
break;
case RuStorePaymentException.ProductPurchaseException exception:
// Handle failed purchase
break;
default:
// Handle other error
break;
}
},
onSuccess: (result) => {
// Process success
});
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 = PreferredPurchaseType.ONE_STEP
), i.e., without funds being held.
For two-stage payment, you need to specify preferredPurchaseType = PreferredPurchaseType.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-stage payment (with funds holding)
To initiate a product purchase using the two-stage scenario, use the PurchaseTwoStep
method:
When calling this method, the user will only have access to payment methods that support two-stage payment.
var parameters = new ProductPurchaseParams(
productId: new ProductId("product_id"),
appUserEmail: null,
appUserId: null,
developerPayload: null,
orderId: null,
quantity: new Quantity(1)
);
RuStorePayClient.Instance.PurchaseTwoStep(
parameters: parameters,
onFailure: (error) => {
switch (error) {
case RuStorePaymentException.ProductPurchaseCancelled cancelled:
// Handle cancelled purchase
break;
case RuStorePaymentException.ProductPurchaseException exception:
// Handle failed purchase
break;
default:
// Handle other error
break;
}
},
onSuccess: (result) => {
// Process success
});
Purchase Parameters Structure
public class ProductPurchaseParams : BaseFields {
public ProductId productId { get; }
public AppUserEmail? appUserEmail { get; }
public AppUserId? appUserId { get; }
public Quantity? quantity { get; }
public OrderId? orderId { get; }
public DeveloperPayload? developerPayload { get; }
...
}
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.
Purchase Result Structure
public sealed class ProductPurchaseResult : BaseFields {
public PurchaseId purchaseId { get; }
public ProductId productId { get; }
public InvoiceId invoiceId { get; }
public OrderId? orderId { get; }
public PurchaseType purchaseType { get; }
public Quantity quantity { get; }
public bool sandbox { get; }
...
}
ProductPurchaseResult
— the result of a successful digital product payment (for single-stage payment) or successful funds holding (for two-stage payment).purchaseId
— purchase identifier. Used to obtain purchase information in the SDK via the purchase information retrieval method.productId
— identifier of the purchased product, specified when created in the RuStore developer console.invoiceId
— invoice identifier. 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
/TWO_STEP
/UNDEFINED
— single-stage/two-stage/undefined).quantity
— quantity of the purchased product.sandbox
— flag indicating a test payment in the sandbox. IfTRUE
, the purchase was made in test mode.
Handling Payment Errors
If an error occurs during payment or the user cancels the purchase, the execution of the payment method (both with purchase type selection and the two-stage method) will complete with an error:
ProductPurchaseException
— product purchase error.ProductPurchaseCancelled
— error caused by purchase cancellation (the user closed the payment sheet) before receiving the purchase result.
In this case, it is recommended to additionally check the purchase status using the purchase information retrieval method.
Error and cancellation structure:
public sealed class ProductPurchaseException : RuStorePaymentException {
public InvoiceId? invoiceId { get; }
public OrderId? orderId { get; }
public ProductId? productId { get; }
public PurchaseId? purchaseId { get; }
public PurchaseType? purchaseType { get; }
public Quantity? quantity { get; }
public bool? sandbox { get; }
...
}
public sealed class ProductPurchaseCancelled : RuStorePaymentException {
public PurchaseId? purchaseId { get; }
public PurchaseType? purchaseType { get; }
...
}
Server-Side Purchase Validation
If you need to validate a successful purchase on the RuStore server, you can use the invoiceId
from the SuccessProductPurchaseResult
model returned after a successful product purchase.
var parameters = new ProductPurchaseParams(
productId: new ProductId("product_id"));
RuStorePayClient.Instance.Purchase(
parameters: parameters,
preferredPurchaseType: PreferredPurchaseType.TWO_STEP,
onFailure: (error) => {
// Process error
},
onSuccess: (result) => {
var invoiceId = result.invoiceId.value;
yourApi.validate(invoiceId);
});
You can also get the invoiceId
from the Purchase
model. The Purchase
model can be obtained using the GetPurchases()
method or the GetPurchase
method.
RuStorePayClient.Instance.GetPurchases(
onFailure: (error) => {
// Process error
},
onSuccess: (result) => {
result.ForEach(item => {
yourApi.validate(item.subscriptionToken);
});
});
Confirming (Consuming) a Purchase
Only purchases initiated using the two-stage payment scenario (i.e., with funds being held) require confirmation. Such purchases, after successful holding, will have the status PurchaseStatus.PAID
.
To debit funds from the buyer's card, the purchase must be confirmed. For this, you should use the ConfirmTwoStepPurchase
method.
PurchaseId id = ...
DeveloperPayload payload = ...
RuStorePayClient.Instance.ConfirmTwoStepPurchase(
purchaseId: purchaseId,
developerPayload: payload,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
});
purchaseId
— product ID.developerPayload
— a string with additional order information that you can set when confirming the purchase. This string overrides the value set during initialization (optional). Maximum 250 characters. If provided, it replaces the value set at the start of the purchase via thePurchase
/PurchaseTwoStep
method.
Canceling a Purchase
With our SDK you can cancel only the purchases that undergo a two-stage payment process, i.e. when the user's money is put on hold. After a successful hold, such purchases are in the PurchaseStatus.PAID
status. If a purchase is canceled it has the PurchaseStatus.REVERSED
status.
Cancel purchases if you cannot deliver your product after payment is made (when the user's money is put on hold).
To cancel a purchase (put the user's money off hold), use the CancelTwoStepPurchase
method.
PurchaseId id = ...
RuStoreBillingClient.Instance.CancelTwoStepPurchase(
purchaseId: id,
onFailure: (error) => {
// Process error
},
onSuccess: () => {
// Process success
}
);
purchaseId
— product ID.
RuStoreUtils
RuStoreUtils is a block in the native SDK containing a set of public methods intended for interacting with the RuStore app on the user's device.
To access the block's methods in the Unity environment, use the singleton class RuStoreCoreClient
.
The IsRuStoreInstalled
method checks if the RuStore app is installed on the user's device.
if (RuStorePayClient.Instance.IsRuStoreInstalled()) {
// RuStore is installed on the user's device
} else {
// RuStore is not installed on the user's device
}
The openRuStoreDownloadInstruction
method opens a web page for downloading the RuStore mobile application.
RuStoreCoreClient.Instance.openRuStoreDownloadInstruction();
The openRuStore
method launches the RuStore mobile application. When this method is called, if the RuStore app is not installed, a Toast notification with the message "Failed to open the application" will be displayed.
RuStoreCoreClient.Instance.openRuStore();
The openRuStoreAuthorization
method launches the RuStore mobile application for authorization. After successful user authorization, the RuStore app will automatically close. When this method is called, if the RuStore app is not installed, a Toast notification with the message "Failed to open the application" will be displayed.
RuStoreCoreClient.Instance.openRuStoreAuthorization();
Error List
RuStoreError — base class for errors.
public class RuStoreError {
public string name;
public string description;
}
name
– error name.description
– error description.
RuStorePaymentException — base class for payment client errors.
public class RuStorePaymentException : RuStoreError {
public virtual RuStoreError? cause { get; }
...
}
cause
– additional error information.
Inherited fields:
name
– error name.description
– error description.
RuStorePaymentNetworkException — SDK network interaction error. The error model returns an error code (field code
), which can be used to determine the cause of the error. The table with error codes is available in the error codes section.
public class RuStorePaymentNetworkException : RuStorePaymentException {
public int code { get; }
...
}
code
— error code.
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
— the 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 when 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.
Error Codes
Error Code | Description |
---|---|
4000001 | The request is malformed: a required parameter is missing or incorrectly filled, or the data format is invalid. |
4000002 , 4000016 , 4040005 | Application not found. |
4000003 | Application is banned. |
4000004 | Application signature does not match the registered one. |
4000005 | Company not found. |
4000006 | Company is banned. |
4000007 | Company monetization is disabled or inactive. |
4000014 | Product not found. |
4000015 | Product not published. |
4000017 | Invalid quantity parameter. |
4000018 | Purchase limit exceeded. |
4000020 | Product already purchased. |
4000021 | Unfinished product purchase. |
4000022 | Purchase not found. |
4000025 | No suitable payment method found. |
4000026 | Invalid purchase type for confirmation (should be two-stage payment). |
4000027 | Invalid purchase status for confirmation. |
4000028 | Invalid purchase type for cancellation (should be two-stage payment). |
4000029 | Invalid purchase status for cancellation. |
4000030 | The issued token does not match the purchased product. |
4010001 | Access to the requested resource is forbidden (unauthorized). |
4010002 | Token lifetime has expired. |
4010003 | Payment token is invalid. |
4030001 | Payment token not provided. |
4030002 | User is blocked due to security requirements. |
4040002 , 4040003 , 4040004 | Payment system error. |
5000*** | Internal error. |