5.0.0
RuStore allows you to integrate payments into your mobile app.
Implementation example
See the example app to learn how to integrate rating and feedback SDK correctly.
All operations with the client are also accessible from Blueprints. Below is a Initialization example.
![img](/help/en/assets/images/initialization-v0-63164dadedabad36b2b433e65cd55851.jpg)
Prerequisites
- The current version of RuStore is installed on the user's device.
- The user is authorized in RuStore.
- The user and the app should not be blocked in RuStore.
- In-app purchases should be enabled for the app in RuStore Console.
- Unreal Engine 4.26 and later.
The service has some restrictions to work outside of Russia.
Getting started
- In your IDE, open the Android project from the
unreal_plugin_libraries
. - Build your project with the command
gradle assemble
.
If the build is successful, the following files will be created in unreal_example/Plugins/RuStoreBilling/Source/RuStoreBilling/ThirdParty/Android/libs
and unreal_example / Plugins / RuStoreCore / Source / RuStoreCore / ThirdParty / Android / libs
.
RuStoreUnityBillingClient.aar
RuStoreUnityCore.aar
- Copy the contents of the
Plugins
folder from the official RuStore repository on GitFlic to thePlugins
of your project. - Restart Unreal Engine.
- Then, in (Edit > Plugins > Project > Mobile) check plug-ins RuStoreBilling and RuStoreCore.
- In the
YourProject.Build.cs
file in thePublicDependencyModuleNames
list connect modulesRuStoreCore
andRuStoreBilling
. - In the project settings (Edit > Project Settings > Android) set the Minimum SDK Version parameter to 24 or later and the Target SDK Version parameter: 31 or later.
Deeplink processing
To redirect a user to your app after payment via third-party apps (the Faster Payments System (SBP), SberPay and others), you need to properly implement deep linking in your app. To proces plug-in RuStore Billing automatically adds the AndroidManifest.xml
attribute for the main activity and the next intent-filter
You can change this behavior in the RuStoreBilling_UPL_Android.xml
.
<activity android:name="com.Plugins.RuStoreBilling.RuStoreIntentFilterActivity" android:exported="true" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Set your appscheme -->
<data android:scheme="@string/rustore_app_scheme" />
</intent-filter>
</activity>
@string/rustore_app_scheme
implementation is necessary for your project.
@string/rustore_app_scheme
— your deeplink scheme. This scheme must match the deeplinkSheme value specified during the billing client library initialization.
Initialization
Initialize the library before calling its methods.
FURuStoreBillingClientConfig config;
config.consoleApplicationId = "123456";
config.deeplinkScheme = "yourscheme";
config.allowNativeErrorHandling = false;
config.enableLogs = false;
URuStoreBillingClient::Instance()->Init(config);
All operations with the client are also accessible from Blueprints. Below is a Initialization example.
![img](/help/en/assets/images/initialization-v0-63164dadedabad36b2b433e65cd55851.jpg)
-
consoleApplicationId
— application code from RuStore Console (example:https://console.rustore.ru/apps/123456
). -
deeplinkSheme
— an url used for deeplink. Make sure your use a unique name, for exampl: yourappscheme). -
allowNativeErrorHandling
— allow error handling (see in Error handling). -
enableLogs
— enable event logging.
The Init()
call ties the object to the scene root, and, If no further work with the object is needed, execute the Dispose()
method to free memory.
Deinitialization
URuStoreBillingClient::Instance()->Dispose();
![img](/help/en/assets/images/deinitialization-v0-248fe7a1b5db1bc0cc8799371439ed49.jpg)
Initialization check
If you need to check whether the library is initialized, use the GetIsInitialized()
method. The method will return true
if the library is initialized and false
if Init
hasn't been called yet.
bool isInitialized = URuStoreBillingClient::Instance()->GetIsIninialized();
![img](/help/en/assets/images/isinitialized-v0-8bfde1b1cbf1ffe08a1a1caca60674e9.jpg)
How payments work
Checking purchases availability
Please ensure compliance with the conditions below to check whether your app supports payment functions.
- The current version of RuStore is installed on the user's device.
- RuStore app supports payment functionality.
- The user is authorized in RuStore.
- The user and the app should not be blocked in RuStore.
- In-app purchases should be enabled for the app in RuStore Console.
To check whether your app supports payment functions, call the CheckPurchasesAvailability
method.
Each request returns requestId
that is unique per app launch. Each event returns requestId
of the request that triggered this event.
long requestId = URuStoreBillingClient::Instance()->CheckPurchasesAvailability(
[]( long requestId, TSharedPtr<FURuStoreFeatureAvailabilityResult, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
![img](/help/en/assets/images/checkPurchasesAvailability-v0-8fa8c56ecf394cddace8d8d0ccff9209.jpg)
The Success
callback returns the FURuStoreFeatureAvailabilityResult
structure in the Response
parameter (see below) below).
USTRUCT(BlueprintType)
struct RUSTORECORE_API FURuStoreFeatureAvailabilityResult
{
GENERATED_USTRUCT_BODY()
FURuStoreFeatureAvailabilityResult()
{
isAvailable = false;
}
UPROPERTY(BlueprintReadWrite)
bool isAvailable;
UPROPERTY(BlueprintReadWrite)
FURuStoreError cause;
};
-
isAvailable
— whether payment conditions are met (true
/false
). -
cause
— error information.
All possiblecause
errors are described in Error Handling.. Other errors are processed in on Failure
.
The Failure
callback returns the FURuStoreError
structure with the error information in the Error
parameter. All possible FURuStoreError
errors are described in Error Handling.
Working with SDK
Getting products list
Use the GetProducts()
method to get a list of products.
long requestId = URuStoreBillingClient::Instance()->GetProducts(
productIds,
[]( long requestId, TSharedPtr<FURuStoreProductsResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
![img](/help/en/assets/images/GetProducts-v0-49e5f7ca2f3825f0ba5a7c6a88f951c5.jpg)
TArray<FString> productIds
— list of products IDs.
The Success
callback returns the FURuStoreProductsResponse
structure in the Response
parameter (see below).
GetProducts
response
USTRUCT(BlueprintType)
struct FURuStoreProductsResponse
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
TArray<FURuStoreProduct> products;
};
products
— list of products.
Product structure
USTRUCT(BlueprintType)
struct FURuStoreProduct
{
GENERATED_USTRUCT_BODY()
FURuStoreProduct()
{
productId = "";
productType = EURuStoreProductType::NON_CONSUMABLE;
productStatus = EURuStoreProductStatus::INACTIVE;
priceLabel = "";
price = 0;
currency = "";
language = "";
title = "";
description = "";
imageUrl = "";
promoImageUrl = "";
}
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
EURuStoreProductType productType;
UPROPERTY(BlueprintReadOnly)
EURuStoreProductStatus productStatus;
UPROPERTY(BlueprintReadOnly)
FString priceLabel;
UPROPERTY(BlueprintReadOnly)
int price;
UPROPERTY(BlueprintReadOnly)
FString currency;
UPROPERTY(BlueprintReadOnly)
FString language;
UPROPERTY(BlueprintReadOnly)
FString title;
UPROPERTY(BlueprintReadOnly)
FString description;
UPROPERTY(BlueprintReadOnly)
FString imageUrl;
UPROPERTY(BlueprintReadOnly)
FString promoImageUrl;
UPROPERTY(BlueprintReadOnly)
FURuStoreProductSubscription subscription;
};
productId
— product ID..productType
— product type..productStatus
— product status..priceLable
— formatted purchase price, including the currency symbol inlanguage
.price
— price in minor units (in kopecks)..currency
— ISO 4217 currency code.language
— language specified with the BCP 47 encoding..title
— product name inlanguage
.description
— product description inlanguage
.imageUrl
— link to an image..promoImageUrl
— promotional picture link..subscription
— subscription description, returned only for products withsubscription
.
Product type
UENUM(BlueprintType)
enum class EURuStoreProductType : uint8
{
NON_CONSUMABLE UMETA(DisplayName = "NON_CONSUMABLE"),
CONSUMABLE UMETA(DisplayName = "CONSUMABLE"),
SUBSCRIPTION UMETA(DisplayName = "SUBSCRIPTION")
};
Product status
UENUM(BlueprintType)
enum class EURuStoreProductStatus : uint8
{
ACTIVE UMETA(DisplayName = "ACTIVE"),
INACTIVE UMETA(DisplayName = "INACTIVE")
};
Subscription structure
USTRUCT(BlueprintType)
struct FURuStoreProductSubscription
{
GENERATED_USTRUCT_BODY()
FURuStoreProductSubscription()
{
introductoryPrice = "";
introductoryPriceAmount = "";
}
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod subscriptionPeriod;
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod freeTrialPeriod;
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod gracePeriod;
UPROPERTY(BlueprintReadOnly)
FString introductoryPrice;
UPROPERTY(BlueprintReadOnly)
FString introductoryPriceAmount;
UPROPERTY(BlueprintReadOnly)
FURuStoreSubscriptionPeriod introductoryPricePeriod;
};
subscriptionPeriod
— subscription period..freeTrialPeriod
— trial subscription period..gracePeriod
— grace period..introductoryPrice
— formatted introductory subscription price, including the currency symbol, inproduct:language
.introductoryPriceAmount
— introductory price in minor units of currency (in kopecks).introductoryPricePeriod
— calculated period of the introductory price..
Subscription period structure
USTRUCT(BlueprintType)
struct FURuStoreSubscriptionPeriod
{
GENERATED_USTRUCT_BODY()
FURuStoreSubscriptionPeriod()
{
years = 1970;
months = 1;
days = 1;
}
UPROPERTY(BlueprintReadOnly)
int years;
UPROPERTY(BlueprintReadOnly)
int months;
UPROPERTY(BlueprintReadOnly)
int days;
};
years
— number of years..months
— number of days..days
— number of days..
The Failure
callback returns the FURuStoreError
structure with the error information in the Error
parameter.
All possible FURuStoreError
errors are described in Error Handling.
Purchasing product
Use thePurchaseProduct()
method to call a product purchase.
Purchase product request
long requestId = URuStoreBillingClient::Instance()->PurchaseProduct(
productId,
orderId,
quantity,
developerPayload,
[]( long requestId, TShardPtr<FURuStorePaymentResult, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
![img](/help/en/assets/images/PurchaseProduct-v0-90232bf8f5474f47fee77a83d4204fa7.jpg)
productId
— product ID..orderId: String
— unique payment identifier generated by the application (uuid);.quantity
— product quantity..developerPayload
— уline specified by the developer that contains additional information about the order..
The Success
callback returns the smart thread safe (ESPMode::ThreadSafe
) pointer to an object of the structure's heir FURuStorePaymentResult
in the Response
parameter.
The type of the heir object can be obtained using the GetTypeName()
method. The type cast can be done via StaticCastSharedPtr<>
.
// TShardPtr<FURuStorePaymentResult, ESPMode::ThreadSafe> response
FString typeName = response->GetTypeName();
if (typeName == "FURuStoreSuccess")
{
auto success = *StaticCastSharedPtr<FURuStoreSuccess>(response);
}
Possible types values:
FURuStoreSuccess
- successful purchase result..FURuStoreFailure
- error occurred when sending a payment request or receiving a payment status, it is not possible to set the purchase status..FURuStoreCancelled
— a purchase request has been sent, but the user has closed the "payment window" on their device, so the payment result is unknown..
.FURuStoreInvalidPaymentState
— Billing SDK error.. May occur in case of an incorrect reverse deeplink.
The Success
callback returns a managed UE pointer for the URuStorePaymentResultClass
class in the Response
parameter. Casting to a heir type can be done through a cascade of Cast To
calls.
![img](/help/en/assets/images/CastFURuStorePaymentResult-v0-072c00b59afff13189d37fa550835f20.jpg)
Purchase result structure
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStorePaymentResultClass : public UObject
{
GENERATED_BODY()
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
virtual ~FURuStorePaymentResult() {}
virtual FString GetTypeName() { return "FURuStorePaymentResult"; }
};
Payment Result StructureSuccess
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreSuccess : public URuStorePaymentResultClass
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreSuccess value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreSuccess : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
FURuStoreSuccess()
{
orderId = "";
purchaseId = "";
productId = "";
invoiceId = "";
subscriptionToken = "";
}
UPROPERTY(BlueprintReadOnly)
FString orderId;
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
FString invoiceId;
UPROPERTY(BlueprintReadOnly)
FString subscriptionToken;
virtual FString GetTypeName() override { return "FURuStoreSuccess"; }
};
Payment Result StructureCancelled
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreCancelled : public URuStorePaymentResultClass
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreCancelled value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreCancelled : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
FURuStoreCancelled()
{
purchaseId = "";
}
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
virtual FString GetTypeName() override { return "FURuStoreCancelled"; }
};
Payment Result StructureFailure
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreFailure : public URuStorePaymentResultClass
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreFailure value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreFailure : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
public:
FURuStoreFailure()
{
purchaseId = "";
invoiceId = "";
orderId = "";
quantity = 0;
productId = "";
errorCode = 0;
}
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
UPROPERTY(BlueprintReadOnly)
FString invoiceId;
UPROPERTY(BlueprintReadOnly)
FString orderId;
UPROPERTY(BlueprintReadOnly)
int quantity;
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
int errorCode;
virtual FString GetTypeName() override { return "FURuStoreFailure"; }
};
PaymentResult StructureInvalidPaymentState
UCLASS(BlueprintType)
class RUSTOREBILLING_API URuStoreInvalidPaymentState : public URuStorePaymentResultBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly)
FURuStoreInvalidPaymentState value;
};
USTRUCT(BlueprintType)
struct RUSTOREBILLING_API FURuStoreInvalidPaymentState : public FURuStorePaymentResult
{
GENERATED_USTRUCT_BODY()
virtual FString GetTypeName() override { return "FURuStoreInvalidPaymentState"; }
};
The Failure
callback returns the FURuStoreError
structure with the error information in the Error
parameter. All possible FURuStoreError
errors are described in Error Handling.
Getting purchases list
The method only returns purchases with statuses from the table below.
Type/Status | INVOICE_CREATED | CONFIRMED | PAID |
---|---|---|---|
CONSUMABLE | + | + | |
NON-CONSUMABLE | + | + | |
SUBSCRIPTION | + | + |
The method returns incomplete purchase and purchase consumable states that require processing. Apart from that, it shows confirmed purchases for subscriptions and non-consumable items - those that cannot be purchased again.
Use theGetPurchases()
method to get the user's list of purchases.
long requestId = URuStoreBillingClient::Instance()->GetPurchases(
[]( long requestId, TSharedPtr<FURuStorePurchasesResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreRuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
![img](/help/en/assets/images/GetPurchases-01-v0-fb65fdde28ef1b5ac065dc58e2d4f544.jpg)
The Success
callback returns the FURuStorePurchasesResponse
structure in the Response
parameter (see below). below).
ResponseGetPurchases
USTRUCT(BlueprintType)
struct FURuStorePurchasesResponse: public FURuStoreResponseWithCode
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
TArray<FURuStorePurchase> purchases;
};
purchases
— list of requested purchases.
Purchase Structure
USTRUCT(BlueprintType)
struct FURuStorePurchase
{
GENERATED_USTRUCT_BODY()
FURuStorePurchase()
{
purchaseId = "";
productId = "";
invoiceId = "";
description = "";
language = "";
purchaseTime = FDateTime(0);
orderId = "";
amountLabel = "";
amount = 0;
currency = "";
quantity = 0;
purchaseState = EURuStorePurchaseState::CANCELLED;
developerPayload = "";
subscriptionToken = "";
}
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
FString invoiceId;
UPROPERTY(BlueprintReadOnly)
FString description;
UPROPERTY(BlueprintReadOnly)
FString language;
UPROPERTY(BlueprintReadOnly)
FDateTime purchaseTime;
UPROPERTY(BlueprintReadOnly)
FString purchaseTimeLabel;
UPROPERTY(BlueprintReadOnly)
FString orderId;
UPROPERTY(BlueprintReadOnly)
FString amountLabel;
UPROPERTY(BlueprintReadOnly)
int amount;
UPROPERTY(BlueprintReadOnly)
FString currency;
UPROPERTY(BlueprintReadOnly)
int quantity;
UPROPERTY(BlueprintReadOnly)
EURuStorePurchaseState purchaseState;
UPROPERTY(BlueprintReadOnly)
FString developerPayload;
UPROPERTY(BlueprintReadOnly)
FString subscriptionToken;
};
Purchase state
UENUM(BlueprintType)
enum class EURuStorePurchaseState : uint8
{
CREATED UMETA(DisplayName = "CREATED"),
INVOICE_CREATED UMETA(DisplayName = "INVOICE_CREATED"),
CONFIRMED UMETA(DisplayName = "CONFIRMED"),
PAID UMETA(DisplayName = "PAID UMETA"),
CANCELLED UMETA(DisplayName = "CANCELLED"),
CONSUMED UMETA(DisplayName = "CONSUMED"),
PAUSED UMETA(DisplayName = "PAUSED"),
CLOSED UMETA(DisplayName = "CLOSED")
};
-
purchaseId
— purchase ID.. -
productId
— product ID.. -
description
— product description inlanguage
. -
invoiceId
— invoice ID.. -
language
— language specified with the BCP 47 encoding.. -
.purchaseTime
— time of purchase. -
orderId
— unique payment identifier generated by the application (uuid);. -
amountLable
— formatted purchase price, including the currency symbol inlanguage
. -
amount
— price in minor units of currency.. -
currency
— ISO 4217 currency code. -
quantity
— product quantity.. -
purchaseState
— purchase state.:
;CREATED
- purchase created.INVOICE_CREATED
— created, waiting for payment.;
;PAID
— consumable purchases only - intermediate status, funds reserved in buyer's account. Purchase pending confirmation from developer.CONFIRMED
— final status, purchase confirmed (for subscriptions and non-consumable items). Funds sent to the developer. Repeat item purchase is blocked by the store;
;CONSUMED
— for consumable items - final status, purchase consumption confirmed. You can re-purchase an item.CANCELLED
— purchase cancelled - payment has not been made or a refund has been made to the buyer (for subscriptions, once refunded, the purchase does not becomeCANCELLED
);
;PAUSED
- for subscriptions - subscription shifted to HOLD period.
.TERMINATED
— subscription closed.
-
developerPayload
— уline specified by the developer that contains additional information about the order.. -
subscriptionToken
— token for server validation..
The Failure
callback returns the FURuStoreError
structure with the error information in the Error
parameter.
All possible FURuStoreError
errors are described in Error Handling.
Getting purchase info
Use theGetPurchaseInfo
method to retrive purchase details.
long requestId = URuStoreBillingClient::Instance()->GetPurchaseInfo(
purchaseId,
[]( long requestId, TSharedPtr<FURuStorePurchaseInfoResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
![img](/help/en/assets/images/GetPurchaseInfo-v0-c25ffd8ddfff4edaa395b9e2cba3126a.jpg)
purchaseId
— purchase ID.
The Success
callback returns the FURuStorePurchase
structure in the Response
parameter (see below).
Purchase Structure
USTRUCT(BlueprintType)
struct FURuStorePurchase
{
GENERATED_USTRUCT_BODY()
FURuStorePurchase()
{
purchaseId = "";
productId = "";
invoiceId = "";
description = "";
language = "";
purchaseTime = FDateTime(0);
orderId = "";
amountLabel = "";
amount = 0;
currency = "";
quantity = 0;
purchaseState = EURuStorePurchaseState::CANCELLED;
developerPayload = "";
subscriptionToken = "";
}
UPROPERTY(BlueprintReadOnly)
FString purchaseId;
UPROPERTY(BlueprintReadOnly)
FString productId;
UPROPERTY(BlueprintReadOnly)
FString invoiceId;
UPROPERTY(BlueprintReadOnly)
FString description;
UPROPERTY(BlueprintReadOnly)
FString language;
UPROPERTY(BlueprintReadOnly)
FDateTime purchaseTime;
UPROPERTY(BlueprintReadOnly)
FString purchaseTimeLabel;
UPROPERTY(BlueprintReadOnly)
FString orderId;
UPROPERTY(BlueprintReadOnly)
FString amountLabel;
UPROPERTY(BlueprintReadOnly)
int amount;
UPROPERTY(BlueprintReadOnly)
FString currency;
UPROPERTY(BlueprintReadOnly)
int quantity;
UPROPERTY(BlueprintReadOnly)
EURuStorePurchaseState purchaseState;
UPROPERTY(BlueprintReadOnly)
FString developerPayload;
UPROPERTY(BlueprintReadOnly)
FString subscriptionToken;
};
Purchase state
UENUM(BlueprintType)
enum class EURuStorePurchaseState : uint8
{
CREATED UMETA(DisplayName = "CREATED"),
INVOICE_CREATED UMETA(DisplayName = "INVOICE_CREATED"),
CONFIRMED UMETA(DisplayName = "CONFIRMED"),
PAID UMETA(DisplayName = "PAID UMETA"),
CANCELLED UMETA(DisplayName = "CANCELLED"),
CONSUMED UMETA(DisplayName = "CONSUMED"),
PAUSED UMETA(DisplayName = "PAUSED"),
CLOSED UMETA(DisplayName = "CLOSED")
};
-
purchaseId
— purchase ID.. -
productId
— product ID.. -
description
— product description inlanguage
. -
invoiceId
— invoice ID.. -
language
— language specified with the BCP 47 encoding.. -
.purchaseTime
— time of purchase. -
orderId
— unique payment identifier generated by the application (uuid);. -
amountLable
— formatted purchase price, including the currency symbol inlanguage
. -
amount
— price in minor units of currency.. -
currency
— ISO 4217 currency code. -
quantity
— product quantity.. -
purchaseState
— purchase state.:
;CREATED
- purchase created.INVOICE_CREATED
— created, waiting for payment.;
;PAID
— consumable purchases only - intermediate status, funds reserved in buyer's account. Purchase pending confirmation from developer.CONFIRMED
— final status, purchase confirmed (for subscriptions and non-consumable items). Funds sent to the developer. Repeat item purchase is blocked by the store;
;CONSUMED
— for consumable items - final status, purchase consumption confirmed. You can re-purchase an item.CANCELLED
— purchase cancelled - payment has not been made or a refund has been made to the buyer (for subscriptions, once refunded, the purchase does not becomeCANCELLED
);
;PAUSED
- for subscriptions - subscription shifted to HOLD period.
.TERMINATED
— subscription closed.
-
developerPayload
— уline specified by the developer that contains additional information about the order.. -
subscriptionToken
— token for server validation..
The Failure
callback returns the FURuStoreError
structure with the error information. All possible FURuStoreError
errors are described in Error Handling.
Status model (purchaseState
)
- A status-based consumables subscription (
CONSUMABLES
)
![img](/help/en/assets/images/CONSUMABLES-v0-bf7aa17ffc46aac0531f9898aadeea55.png)
- A status-based non-consumables subscription (
NON-CONSUMABLES
):
![img](/help/en/assets/images/NON-CONSUMABLES-v0-a78cd9b635ef5c2d972c41265a1380df.png)
- A status-based subscription purchase model (
SUBSCRIPTIONS
)
![img](/help/en/assets/images/SUBSCRIPTIONS-v0-ee95282f22314f22bed73f8e5a9b256c.png)
Confirming purchase
Products that require confirmation
The RuStore application consists of the following types of products:
SUBSCRIPTION
— subscription (can be purchased for a period of time, such as a streaming service subscription)..NON_CONSUMABLE
— non-consumables (one-time purchases, such as disabling ads in an app).
.CONSUMABLE
— consumables (multiple-time purchases, such as crystals in the app);
Only CONSUMABLE
type products require confirmation if they are in PurchaseState.PAID
state.
Calling confirmation method
Use theConfirmPurchase
method to call a product purchase. The release of the goods must be accompanied by a purchase confirmation request. Once the confirmation is called, the purchase will have a CONSUMED
status.
long requestId = RuStoreBillingClient::Instance()->ConfirmPurchase(
purchaseId,
[]( long requestId, TSharedPtr<FURuStoreError, ESPMode::ThreadSafe> error) {
// Process error
},
[]( long requestId, TSharedPtr<FURuStoreConfirmPurchaseResponse, ESPMode::ThreadSafe> response) {
// Process response
}
);
![img](/help/en/assets/images/ConfirmPurchase-v0-f6f295ab79e70bd5048d3d81ddd61887.jpg)
purchaseId
— purchase ID..
The Failure
callback returns the FURuStoreError
structure with the error information in the Error
parameter. All possible FURuStoreError
errors are described in Error Handling.
Canceling purchase
Use theDeletePurchase
method to cancel a purchase.
** Purchase cancellation request**
long requestId = URuStoreBillingClient::Instance()->DeletePurchase(
purchaseId,
[]( long requestId, TSharedPtr<FURuStoreDeletePurchaseResponse, ESPMode::ThreadSafe> response) {
// Process response
},
[]( long requestId, TSharedPtr<FURuStoreRuStoreError, ESPMode::ThreadSafe> error) {
// Process error
}
);
![img](/help/en/assets/images/DeletePurchase-v0-86b2a93a51c296279e4b000bb45e5a41.jpg)
purchaseId
— purchase ID..
Note. Use this method if your app logic is related to purchase cancellation. The purchase is canceled automatically after a 20-min timeout, or upon a second purchase from the same customer.
The Failure
callback returns the FURuStoreError
structure with the error information in the Error
parameter. All possible FURuStoreError
errors are described in Error Handling.
Processing unfinished payments
Uncompleted payments must be processed by the developer.
To confirm a CONSUMABLE
purchase type in PAID
status, you can call the confirm-purchase method (see Getting purchase info).
In the case of purchase cancellations, consider your internal process when using payment processing methods. As for some developers, it provides for pre-consumption checks or purchase cancellation. In this case, request the status of such purchase separately.
For example, if a user has paid for an item you can't supply to them for some reason, call the cancel purchase method on the PAID
status to cancel the purchase.
In cases where the receive shopping list method returns a purchase with INVOICE_CREATED
status, you can use the cancel purchase method. For example, if you don't want to see a purchase with these statuses in your shopping list. You don't have to do it yourself, as RuStore handles the cancellation of such purchases on its side.
In some cases, after paying through a banking app (SBP, SberPay, TinkoffPay, etc.), the purchase status may still return INVOICE_CREATED
, when you subsequently return to app. This is caused by the purchase processing time by the bank. Therefore, the developer needs to correctly link the shopping list obtaining function to the life cycle on the screen.
You acn also cancel a purchase in INVOICE_CREATED
status only through user interaction with the app. For example, create a separate button for this purpose.
Logging
If you want to log payment library events, add parameter enableLogs = true
in the FURuStoreBillingClientConfig
structure when calling the Init
method.
FURuStoreBillingClientConfig config;
config.consoleApplicationId = "123456";
config.deeplinkScheme = "yourscheme";
config.allowNativeErrorHandling = false;
config.enableLogs = true;
URuStoreBillingClient::Instance()->Init(config);
![img](/help/en/assets/images/logging-v0-9c62e16c3d61f895a63f4fc60f2eba55.jpg)
In this case, the BillingClientLogger
object will be used, which implements the output of messages to Logcat
.
class BillingClientLogger(private val tag: String) : ExternalPaymentLogger {
override fun d(e: Throwable?, message: () -> String) {
Log.d(tag, message.invoke(), e)
}
override fun e(e: Throwable?, message: () -> String) {
Log.e(tag, message.invoke(), e)
}
override fun i(e: Throwable?, message: () -> String) {
Log.i(tag, message.invoke(), e)
}
override fun v(e: Throwable?, message: () -> String) {
Log.v(tag, message.invoke(), e)
}
override fun w(e: Throwable?, message: () -> String) {
Log.w(tag, message.invoke(), e)
}
}
Changing UI theme
To dynamically change theme, use SetTheme
.
EURuStoreTheme theme = EURuStoreTheme::DARK;
URuStoreBillingClient::Instance()->SetTheme(theme);
![img](/help/en/assets/images/SetTheme-v0-8dd7d23a8cf1d8ab5e1101932cd9150a.jpg)
theme
- theme type from theEURuStoreTheme
enumeration.
Theme type
UENUM(BlueprintType)
enum class EURuStoreTheme : uint8
{
DARK UMETA(DisplayName = "DARK"),
LIGHT UMETA(DisplayName = "LIGHT")
};
DARK
— dark theme.LIGHT
— light theme.
To retrieve the information about the set theme, use the GetTheme
method.
EURuStoreTheme theme = URuStoreBillingClient::Instance()->GetTheme();
![img](/help/en/assets/images/GetTheme-v0-3a1fb8b376b8947fed6b5665bf4660de.jpg)
Errors processing
Possible errors
RuStoreNotInstalledException
— RuStore not installed on user's device;RuStoreOutdatedException
— RuStore, installed on the user's device, does not support payment processing functions.;RuStoreUserUnauthorizedException
— user not authorized on RuStore;RuStoreRequestLimitReached
— not enough time has passed since the process was last shown.;RuStoreReviewExists
— this user has already rated your app.;RuStoreInvalidReviewInfo
— problems withReviewInfo
;RuStoreException
— basic RuStore error, from which all other errors are inherited..
Error structure
USTRUCT(BlueprintType)
struct RUSTORECORE_API FURuStoreRuStoreError
{
GENERATED_USTRUCT_BODY()
FURuStoreRuStoreError()
{
name = "" ;
description = "" ;
}
UPROPERTY(BlueprintReadOnly)
FString name;
UPROPERTY(BlueprintReadOnly)
FString description;
};
name
– error name..description
– error description..
Auto error handling
When the PurchaseProduct
method is called, errors are handled automatically.
If the allowNativeErrorHandling == true
parameter was passed during SDK initialisation, an error dialog will be displayed to the user when an error occurs, apart from calling the appropriate Failure
handler.
You can change this behavior at any time using the SetAllowNativeErrorHandling()
method.
RuStoreBillingClient::Instance()->SetAllowNativeErrorHandling(false);
![img](/help/en/assets/images/SetAllowNativeErrorHandling-false-v0-a98d3104be8381ef44e68db1f432044f.jpg)
true
— show dialogue.false
— hide dialogue.
Error codes
The following is a description of possible errors in errorCode
.
HTTP code | Error code | Description |
---|---|---|
400 | 40001 | Incorrect request parameters: mandatory parameters are not filled in/incorrect parameters format |
400 | 40003 | No application found |
400 | 40004 | inactive application status |
400 | 40005 | Product not found |
400 | 40006 | inactive product status |
400 | 40007 | Invalid product type. Supported types: consumable , non-consumable , subscription . |
400 | 40008 | A purchase with this order_id already exists |
400 | 40009 | The current client has a purchase of this product with the status invoice_created . Your are required to offer the client to pay for/cancel the purchase |
400 | 40010 | For consumable product type. The current customer already has purchased this product with the status paid . First you need to confirm the purchase on the device, and then you can send the following purchase request for this product |
400 | 40011 | For non-consumable product type. The current client already has purchased this product with the status pre_confirmed /confirmed . Such product has already been purchased. This product cannot be sold more than once. |
400 | 40012 | Forsubscription product type. The current client already has purchased this product with the status pre_confirmed /confirmed . Such product has already been purchased. This product cannot be sold more than once. |
400 | 40013 | Forsubscription product type. When requesting the subscription service for a list of products GET/products (serviceId , user_id ) data were not received |
400 | 40014 | The required attribute(s) was not received in the request. |
400 | 40015 | Failed to change status when updating purchase (no transition allowed). |
400 | 40016 | When purchasing a subscription for a non-consumable product, the number quantity > 1 is specified |
400 | 40017 | Product removed, no new purchases available. |
400 | 40018 | You cannot consume type product . |
401 | 40101 | Invalid token. |
401 | 40102 | Token lifetime has expired. |
403 | 40301 | Access to the requested resource is denied (unauthorized). |
403 | 40302 | The current call is not authorized (method prohibited) for the token. |
403 | 40303 | The application ID in the request does not match the one specified in the token. |
403 | 40305 | Incorrect token type. |
404 | 40401 | Not found. |
408 | 40801 | The notification timeout period specified in the request has expired. |
500 | 50*** | Internal payment service error. |