Skip to main content
Unlisted page
This page is unlisted. Search engines will not index it, and only users having a direct link can access it.

7.0.0 (Beta)

With RuStore you can integrate payments in your mobile app.

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

  • If you migrate to Pay SDK from billingClient SDK, please review the migration instructions. For more details, see here.

Implementation example

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

Prerequisites

  • In-app purchases for the app are enabled in RuStore Console.
  • The app must not be banned in RuStore.
  • The current version of RuStore is installed on the user's device.
  • User is authorized in RuStore.
  • The user must is not banned in RuStore.

Getting started

  1. Copy the plugin and the sample app projects from the official RuStore repository on GitFlic.
  2. Save the contents of the unreal_example /Plugins folder to the Plugins folder inside your project. Restart Unreal Engine.
  3. Then, in the list (Edit > Plugins > Project > Mobile) check plug-ins “RuStorePay” and “RuStoreCore”.
  4. In the YourProject.Build.cs file in the PublicDependencyModuleNames list connect modules RuStoreCore and RuStorePay.
  5. In project settings (Edit > Project Settings > Android) set:
    • Minimum SDK Version24 or later;
    • Target SDK Version31 or later.

Unreal Engine configuration

For Unreal Engine versions earlier than 5.4 gradle and gradle-wrapper update is required.

  1. Navigate to the root folder of Unreal Engine (for example: C:\Program Files\Epic Games\UE_4.26).
  2. In the \Engine\Build\Android\Java\gradle\build.gradle file set the com.android.tools.build:gradle package version to 4.2.2 or later.
  3. In the \Engine\Build\Android\Java\gradle\gradle\wrapper\gradle-wrapper.properties file set the gradle package version 7.5-all or later.
build.gradle
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
apply from: 'buildscriptAdditions.gradle', to: buildscript
}

apply from: 'baseBuildAdditions.gradle'

allprojects {
repositories {
google()
mavenCentral()
jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}
gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

Initialization

Initialize the library before calling its methods. The initialization itself is done automatically, however, for your SDK to work, define console_app_id_key in your manifest.xml.

You can so it the following way:

Calling GetIsIninialized
URuStorePayClient::Instance()->Init();
img

For your SDK to work, the RuStorePay plugin will add to your AndroidManifest.xml through the RuStorePay_UPL_Android.xml file the data from console_app_id_key and internal_config_key. Both values are inside the <application> tag.

console_app_id and internal_config_key
<application>
...

<meta-data android:name="console_app_id_key" android:value="@string/rustore_PayClientSettings_consoleApplicationId" />
<meta-data android:name="internal_config_key" android:value="unreal" />

</application>
  • internal_config_key – always has value unreal.
  • console_app_id_key — product ID form the RuStore Console.

Where are app IDs in the RuStore Console?
  1. Navigate to the Applications tab and selected the needed app.
  2. 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 address https://console.rustore.ru/apps/123456/versions the app ID is 123456.

Important

Package Name of the app specified in Edit ➝ Project Settings... ➝ Player ➝ Android ➝ Other Settings ➝ Package Name must match Package Name of the APK file you published in the RuStore Console.

The keystore signature must be the same as the one used to sign the application published to the RuStore Console system. Make sure that buildType used (example: debug) uses the same signature as the published app (example: release).

The console_app_id_key value must be specified in a resource file, for example: rustore_pay_values.xml.

rustore_pay_values.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="rustore_PayClientSettings_consoleApplicationId">198332</string>
</resources>

You can include your resource file in your project using the UPL file of your project, in the following example copying of the rustore_pay_values.xmlfile will be done from the Source/YOUUR_PROJECT_NAME directory.

rustore_pay_values.xml
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:android="http://schemas.android.com/apk/res/android">

<resourceCopies>
<copyFile src="$S(PluginDir)/rustore_pay_values.xml" dst="$S(BuildDir)/res/values/rustore_pay_values.xml" />
</resourceCopies>

</root>
Attention

Do not specify console_app_id_key and internal_config_key in the manifest directly. The strings must be placed in a resource file.

Deinitialization

The object is bound to the scene root by calling the Init method for URuStoreRemoteConfigClient. If no further work with the objects is needed, run the Dispose method to free memory. The Dispose method call unties the objects from root and securely complete all sent requests.

Calling Dispose
bool isInitialized = URuStorePayClient::Instance()->Dispose();
img

Initialization check

If you need to check whether the library is initialized, use the GetIsInitialized method. The method returns true if the library is initialized and false if Init hasn't been called yet.

Calling GetIsIninialized
bool isInitialized = URuStorePayClient::Instance()->GetIsIninialized();
img

Working with SDK

Payments availability check

To check purchase availability, call the GetPurchaseAvailability method. On calling, the following conditions are checked.

  • The current version of RuStore is installed on the user's device.
  • RuStore app supports payments.
  • User is authorized in RuStore.
  • The user and the app are not banned in RuStore.
  • In-app purchases for the app are enabled in RuStore Console.
If all above conditions are met, PurchaseAvailabilityResult.Available is returned.

Otherwise, PurchaseAvailabilityResult.Unavailable(val cause: Throwable) is returned, where cause is an error of a failed condition. To check what caused such result, check error type for RuStoreException (error data is described in Errors).

Calling GetPurchaseAvailability
long requestId = URuStorePayClient::Instance()->GetPurchaseAvailability(
[](long requestId, TSharedPtr<FURuStorePayPurchaseAvailabilityResult, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

Check whether RuStore is installed

To check whether the RuStore app is installe don the user's device, call the IsRuStoreInstalled method.

bool bIsRuStoreInstalled = URuStorePayClient::Instance()->IsRuStoreInstalled();
img
  • true – RuStore is installed.

  • false – RuStore is not installed.

Retrieving products 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.

Calling GetProducts
TArray<URuStorePayProductId*> productIds;

long requestId = URuStorePayClient::Instance()->GetProducts(
productsId,
[](long requestId, TSharedPtr<TArray<FURuStorePayProduct>, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

TArray<URuStorePayProductId*> 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?
  1. Navigate to the Applications tab and selected the needed app.
  2. Select Monetization in the left menu.
  3. Select product type: Subscriptions or In-App purchases.
  4. Copy the IDs of the required products.

The method returns products list. Below is the product pattern.

Product structure
USTRUCT(BlueprintType)
struct FURuStorePayProduct
{
GENERATED_USTRUCT_BODY()

UPROPERTY(BlueprintReadOnly)
URuStorePayAmountLabel* amountLabel;

UPROPERTY(BlueprintReadOnly)
URuStorePayCurrency* currency;

UPROPERTY(BlueprintReadOnly)
URuStorePayDescription* description; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayUrl* imageUrl;

UPROPERTY(BlueprintReadOnly)
URuStorePayPrice* price; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;

UPROPERTY(BlueprintReadOnly)
URuStorePayTitle* title;

UPROPERTY(BlueprintReadOnly)
EURuStorePayProductType type;

FURuStorePayProduct()
{
amountLabel = NewObject<URuStorePayAmountLabel>();
currency = NewObject<URuStorePayCurrency>();
description = nullptr;
imageUrl = NewObject<URuStorePayUrl>();
price = nullptr;
productId = NewObject<URuStorePayProductId>();
title = NewObject<URuStorePayTitle>();
type = static_cast<EURuStorePayProductType>(0);
}
};
  • amountLabel — formatted purchase price, including currency symbol.
  • currency — ISO 4217 currency code.
  • description — descriptions in language.
  • imageUrl — image URL.
  • price — price in minimum currency units.
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • title — product name in language.
  • type — product type.

Purchasing product

One-stage payment (without hold)

To purchase product, use the PurchaseOneStep method.

FURuStorePayProductPurchaseParams productPurchaseParams;

...

long requestId = URuStorePayClient::Instance()->PurchaseOneStep(
productPurchaseParams,
[](long requestId, TSharedPtr<FURuStorePayProductPurchaseResult, ESPMode::ThreadSafe> response) {
auto type = response->GetTypeName();
if (type.Equals("FURuStorePaySuccessProductPurchaseResult"))
{
auto success = *StaticCastSharedPtr<FURuStorePaySuccessProductPurchaseResult>(response);

// Process success
}
else
if (type.Equals("FURuStorePayCancelledProductPurchaseResult"))
{
auto cancelled = *StaticCastSharedPtr<FURuStorePayCancelledProductPurchaseResult>(response);

// Process cancelled
}
else
if (type.Equals("FURuStorePayFailureProductPurchaseResult"))
{
auto failure = *StaticCastSharedPtr<FURuStorePayFailureProductPurchaseResult>(response);

// Process failure
}
else
{
// Process invalid state
}
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • quantity — product amount (optional, value 1 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 — string with additional order information, that you can specify on purchase initialization. 250 characters max.

Two-stage payment (with hold)

FURuStorePayProductPurchaseParams productPurchaseParams;

...

long requestId = URuStorePushClient::Instance()->PurchaseTwoStep(
productPurchaseParams,
[](long requestId, TSharedPtr<FURuStorePayProductPurchaseResult, ESPMode::ThreadSafe> response) {
auto type = response->GetTypeName();
if (type.Equals("FURuStorePaySuccessProductPurchaseResult"))
{
auto success = *StaticCastSharedPtr<FURuStorePaySuccessProductPurchaseResult>(response);

// Process success
}
else
if (type.Equals("FURuStorePayCancelledProductPurchaseResult"))
{
auto cancelled = *StaticCastSharedPtr<FURuStorePayCancelledProductPurchaseResult>(response);

// Process cancelled
}
else
if (type.Equals("FURuStorePayFailureProductPurchaseResult"))
{
auto failure = *StaticCastSharedPtr<FURuStorePayFailureProductPurchaseResult>(response);

// Process failure
}
else
{
// Process invalid state
}
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

Purchase parameters structure:

Purchase parameters structure
USTRUCT(BlueprintType)
struct FURuStorePayProductPurchaseParams
{
GENERATED_USTRUCT_BODY()

UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;

UPROPERTY(BlueprintReadOnly)
URuStorePayDeveloperPayload* developerPayload; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity; // nullable

FURuStorePayProductPurchaseParams()
{
productId = NewObject<URuStorePayProductId>();
developerPayload = nullptr;
orderId = nullptr;
quantity = nullptr;
}
};
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • developerPayload — string with additional order information, that you can specify on purchase initialization (optional).
  • 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 (optional).
  • quantity — product amount (optional, value 1 will be used if not specified) (optional).

Payment result structure:

Purchase result structure
USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()

virtual ~FURuStorePayProductPurchaseResult() {}
virtual FString GetTypeName() { return "FURuStorePayProductPurchaseResult"; }
};

USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePaySuccessProductPurchaseResult : public FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()

UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;

UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;

UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;

UPROPERTY(BlueprintReadOnly)
URuStorePaySubscriptionToken* subscriptionToken; // nullable

virtual FString GetTypeName() override { return "FURuStorePaySuccessProductPurchaseResult"; }

FURuStorePaySuccessProductPurchaseResult()
{
invoiceId = NewObject<URuStorePayInvoiceId>(GetTransientPackage());
orderId = nullptr;
productId = NewObject<URuStorePayProductId>(GetTransientPackage());
purchaseId = NewObject<URuStorePayPurchaseId>(GetTransientPackage());
subscriptionToken = nullptr;
}
};

USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePayCancelledProductPurchaseResult : public FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()

UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId; // nullable

virtual FString GetTypeName() override { return "FURuStorePayCancelledProductPurchaseResult"; }

FURuStorePayCancelledProductPurchaseResult()
{
purchaseId = nullptr;
}
};

USTRUCT(BlueprintType)
struct RUSTOREPAY_API FURuStorePayFailureProductPurchaseResult : public FURuStorePayProductPurchaseResult
{
GENERATED_USTRUCT_BODY()

UPROPERTY(BlueprintReadOnly)
FURuStoreError cause;

UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;

UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId;

UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;

UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;

UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity;

UPROPERTY(BlueprintReadOnly)
URuStorePaySubscriptionToken* subscriptionToken;

virtual FString GetTypeName() override { return "FURuStorePayFailureProductPurchaseResult"; }

FURuStorePayFailureProductPurchaseResult()
{
invoiceId = nullptr;
orderId = nullptr;
productId = nullptr;
purchaseId = nullptr;
quantity = nullptr;
subscriptionToken = nullptr;
}
};
  • FURuStorePaySuccessProductPurchaseResult - successful purchase result.
  • FURuStorePayCancelProductPurchaseResult — payment request sent, although, the user closed the payment screen on their app, thus, the payment result is unknown.
  • FURuStorePayFailureProductPurchaseResult - there was a problem during sending payment request or receiving payment status, purchase status unknown.

Getting products list

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

long requestId = URuStorePayClient::Instance()->GetPurchases(
[](long requestId, TSharedPtr<TArray<FURuStorePayPurchase>, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

This method returns the purchases list in the CONFIRMED status for non-consumable products and PAID for consumable products. Below is the purchase pattern:

Purchase information structure
USTRUCT(BlueprintType)
struct FURuStorePayPurchase
{
GENERATED_USTRUCT_BODY()

UPROPERTY(BlueprintReadOnly)
URuStorePayAmountLabel* amountLabel;

UPROPERTY(BlueprintReadOnly)
URuStorePayCurrency* currency;

UPROPERTY(BlueprintReadOnly)
URuStorePayDescription* description;

UPROPERTY(BlueprintReadOnly)
URuStorePayDeveloperPayload* developerPayload; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;

UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayPrice* price;

UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;

UPROPERTY(BlueprintReadOnly)
EURuStorePayProductType productType;

UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;

UPROPERTY(BlueprintReadOnly)
URuStorePayDate* purchaseTime; // nullable

UPROPERTY(BlueprintReadOnly)
EURuStorePayPurchaseType purchaseType;

UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity;

UPROPERTY(BlueprintReadOnly)
EURuStorePayPurchaseStatus status;

UPROPERTY(BlueprintReadOnly)
URuStorePaySubscriptionToken* subscriptionToken; // nullable

FURuStorePayPurchase()
{
amountLabel = NewObject<URuStorePayAmountLabel>(GetTransientPackage());
currency = NewObject<URuStorePayCurrency>(GetTransientPackage());
description = NewObject<URuStorePayDescription>(GetTransientPackage());
developerPayload = nullptr;
invoiceId = NewObject<URuStorePayInvoiceId>(GetTransientPackage());
orderId = nullptr;
price = NewObject<URuStorePayPrice>();
productId = NewObject<URuStorePayProductId>(GetTransientPackage());
productType = static_cast<EURuStorePayProductType>(0);
purchaseId = NewObject<URuStorePayPurchaseId>(GetTransientPackage());
purchaseTime = nullptr;
purchaseType = static_cast<EURuStorePayPurchaseType>(0);
quantity = NewObject<URuStorePayQuantity>(GetTransientPackage());
status = static_cast<EURuStorePayPurchaseStatus>(0);
subscriptionToken = nullptr;
}
};
  • amountLabel — formatted purchase price, including currency symbol.
  • currency — ISO 4217 currency code.
  • description — descriptions in language.
  • developerPayload — string with additional order information, that you can specify on purchase initialization
  • invoiceId — invoice ID.
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. If not specified, will be generated automatically (uuid). 150 characters max.
  • price — price in minimum currency units.
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • productType — product type.
  • purchaseId — product ID.
  • purchaseTime — purchase time.
  • PurchaseType — purchase type:
    • ONE_PHASE - one-stage payment;
    • TWO_PHASE - two-stage payment.
  • quantity — product amount (optional, value 1 will be used if not specified).
  • 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);
    • 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;
    • REFUNDED — purchase successfully refunded;
    • REVERSED — only for two-stage payment: wither the purchase was canceled by the developer or there was no payment within 72 hours, the funds on the user's account are put off hold.

Getting purchase information

Go get purchase information, use the GetPurchase method.

URuStorePayPurchaseId* purchaseId = ...

long requestId = URuStorePushClient::Instance()->GetPurchase(
purchaseId,
[](long requestId, TSharedPtr<FURuStorePayPurchase, ESPMode::ThreadSafe> response) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img

This method returns information about a specific purchase in any status. Below is the purchase pattern:

Purchase information structure
USTRUCT(BlueprintType)
struct FURuStorePayPurchase
{
GENERATED_USTRUCT_BODY()

UPROPERTY(BlueprintReadOnly)
URuStorePayAmountLabel* amountLabel;

UPROPERTY(BlueprintReadOnly)
URuStorePayCurrency* currency;

UPROPERTY(BlueprintReadOnly)
URuStorePayDescription* description;

UPROPERTY(BlueprintReadOnly)
URuStorePayDeveloperPayload* developerPayload; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayInvoiceId* invoiceId;

UPROPERTY(BlueprintReadOnly)
URuStorePayOrderId* orderId; // nullable

UPROPERTY(BlueprintReadOnly)
URuStorePayPrice* price;

UPROPERTY(BlueprintReadOnly)
URuStorePayProductId* productId;

UPROPERTY(BlueprintReadOnly)
EURuStorePayProductType productType;

UPROPERTY(BlueprintReadOnly)
URuStorePayPurchaseId* purchaseId;

UPROPERTY(BlueprintReadOnly)
URuStorePayDate* purchaseTime; // nullable

UPROPERTY(BlueprintReadOnly)
EURuStorePayPurchaseType purchaseType;

UPROPERTY(BlueprintReadOnly)
URuStorePayQuantity* quantity;

UPROPERTY(BlueprintReadOnly)
EURuStorePayPurchaseStatus status;

UPROPERTY(BlueprintReadOnly)
URuStorePaySubscriptionToken* subscriptionToken; // nullable

FURuStorePayPurchase()
{
amountLabel = NewObject<URuStorePayAmountLabel>(GetTransientPackage());
currency = NewObject<URuStorePayCurrency>(GetTransientPackage());
description = NewObject<URuStorePayDescription>(GetTransientPackage());
developerPayload = nullptr;
invoiceId = NewObject<URuStorePayInvoiceId>(GetTransientPackage());
orderId = nullptr;
price = NewObject<URuStorePayPrice>();
productId = NewObject<URuStorePayProductId>(GetTransientPackage());
productType = static_cast<EURuStorePayProductType>(0);
purchaseId = NewObject<URuStorePayPurchaseId>(GetTransientPackage());
purchaseTime = nullptr;
purchaseType = static_cast<EURuStorePayPurchaseType>(0);
quantity = NewObject<URuStorePayQuantity>(GetTransientPackage());
status = static_cast<EURuStorePayPurchaseStatus>(0);
subscriptionToken = nullptr;
}
};
  • amountLabel — formatted purchase price, including currency symbol.
  • currency — ISO 4217 currency code.
  • description — descriptions in language.
  • developerPayload — string with additional order information, that you can specify on purchase initialization
  • invoiceId — invoice ID.
  • orderId — payment ID generated by the app (optional). If you specify this parameter in your system, you will receive it via our API. If not specified, will be generated automatically (uuid). 150 characters max.
  • price — price in minimum currency units.
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • productType — product type.
  • purchaseId — product ID.
  • purchaseTime — purchase time.
  • PurchaseType — purchase type:
    • ONE_PHASE - one-stage payment;
    • TWO_PHASE - two-stage payment.
  • quantity — product amount (optional, value 1 will be used if not specified).
  • 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);
    • 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;
    • REFUNDED — purchase successfully refunded;
    • REVERSED — only for two-stage payment: wither the purchase was canceled by the developer or there was no payment within 72 hours, the funds on the user's account are put off hold.

Purchase status model

One-stage payment status model.

Two-stage payment status model.

Server validation

If you need to validate a purchase on the RuStore server, you can use subscriptionToken from the SuccessProductPurchaseResult model, that is returned on successful purchase.

Retrieving subscriptionToken from purchase result
long requestId = URuStorePushClient::Instance()->PurchaseTwoStep(
productPurchaseParams,
[](long requestId, TSharedPtr<FURuStorePayProductPurchaseResult, ESPMode::ThreadSafe> response) {
auto type = response->GetTypeName();
if (type.Equals("FURuStorePaySuccessProductPurchaseResult")) {
auto success = *StaticCastSharedPtr<FURuStorePaySuccessProductPurchaseResult>(response);

FString subscriptionToken = success.subscriptionToken->value;
yourApi.validate(subscriptionToken);
}
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);

You can also get a subscriptionToken from the Purchase model. The Purchase model can be retrieved using either the GetPurchases or GetPurchase method.

long requestId = URuStorePushClient::Instance()->GetPurchases(
[](long requestId, TSharedPtr<TArray<FURuStorePayPurchase>, ESPMode::ThreadSafe> response) {
for (const auto& item : *response) {
yourApi.validate(item.subscriptionToken);
}
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);

Consume (confirm) purchase

Consume (confirm) purchase

Us the ConfirmTwoStepPurchase 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.

Calling confirmation method
URuStorePayPurchaseId* purchaseId = ...
URuStorePayDeveloperPayload* developerPayload = ...

long requestId = URuStoreBillingClient::Instance()->ConfirmTwoStepPurchase(
purchaseId,
developerPayload,
[](long requestId) {
// Process response
},
[](long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img
  • purchaseId — product ID.
  • developerPayload — string with additional order information, that you can specify on purchase initialization

Purchase cancellation

To cancel a purchase, use the CancelTwoStepPurchase method.

Purchase cancellation request

Calling CancelTwoStepPurchase
URuStorePayPurchaseId* purchaseId = ...

long requestId = URuStoreBillingClient::Instance()->CancelTwoStepPurchase(
purchaseId,
[]( long requestId) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreRuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
img
  • purchaseId — product ID.
info

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.

The Failure callback returns the FURuStoreError structure with error information in the Error parameter. The structure of the FURuStoreError error is described in [Error Handling].(#handlingerrors).

Error handling

  • RuStorePaymentNetworkException — SDK network communication error;
  • RuStorePaymentCommonException — general SDK error;
  • RuStorePayClientAlreadyExist — duplicate initialization error SDK;
  • RuStorePayClientNotCreated — attempt to access public SDK interface before initialisation;
  • RuStorePayInvalidActivePurchase — payment initiated for unknown product type;
  • RuStorePayInvalidConsoleAppId — mandatory parameter сonsole_application_id for SDK initialisation not set;
  • RuStorePaySignatureException — invalid signature (occurs because of fraud actions);
  • EmptyPaymentTokenException — error receiving payment token;
  • RuStoreNotInstalledException — RuStore is not installed on the user's device;
  • RuStoreOutdatedException — RuStore version installed on the user's device does not support this SDK;
  • RuStoreUserUnauthorizedException — user is not authorized in RuStore;
  • RuStoreApplicationBannedException — app is banned in RuStore RuStore;
  • RuStoreUserBannedException — user is blocked in RuStore;
  • RuStoreException — basic RuStore error from which other errors are inherited.