Skip to main content

In-app Payments SDK for React Native (version 11.1.0)

With RuStore you can integrate payments in your mobile app.

tip

Getting Started​

В файле android/app/build.gradle добавьте следующие строки.

android/app/build.gradle
dependencies {
implementation("com.facebook.react:react-android")
implementation("ru.rustore.sdk-wrapper.react-native:pay:11.1.0")

// ... other dependencies
}

To download dependencies, specify the repository:

build.gradle
repositories {
maven {
url = uri("https://nexus-external.rustore.ru/repository/maven-rustore-exposed")
}
}

Register a native module​

For the library to work, you need to register the native module in MainApplication.kt:

import com.facebook.react.PackageList
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultReactNativeHost
import ru.rustore.react.pay.RuStoreReactPayPackage

// ...

override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(RuStoreReactPayPackage())
}
}

JavaScript interface​

The project implements a JavaScript interface for working with the native Android module. All methods are located in the directory src/libs/RuStoreReactPay/ of the repository with an example implementation that needs to be transferred to the project.

Main files​

  • index.tsx - the main module with methods for working with payments
  • types.ts - TypeScript types for working with payments

Deeplink processing in RuStore SDK allows you to effectively interact with third-party applications, when making payments through banking applications (SBP, SberPay, etc.). This allows you to take the user to the payment screen, and after completing the transaction, return you to your application.

To configure work with deeplink in your application and Pay SDK, specify deeplinkScheme using sdk_pay_scheme_value in your AndroidManifest.xml file and pass Intent to the native module from your MainActivity.

Attention
  • When using deeplinks, specifying the scheme is mandatory.
  • If you try to make a payment without specifying a scheme, an error will occur. *Only ASCII characters are allowed. The format must comply with the RFC-3986 specification.

DeeplinkScheme specification:

android/app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="your.app.package.name">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name="ru.rustore.sdk.pay.internal.presentation.ui.PayActivity"
android:exported="false"
android:launchMode="singleTask"
tools:replace="android:launchMode" />

<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<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="yourappscheme" />
</intent-filter>
</activity>

<meta-data
android:name="sdk_pay_scheme_value"
android:value="yourappscheme" />

</application>
</manifest>
tip

Replace yourappscheme with the name of your scheme. For example, ru.package.name.rustore.scheme.

Then pass Intent to the native module in your MainActivity - at startup and when returning to the application via deeplink:

MainActivity.kt
class MainActivity : ReactActivity() {

// ...

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
handleIntent(intent)
}
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntent(intent)
}

private fun handleIntent(intent: Intent?) {
intent?.let {
RuStoreReactPayModule.processIntent(it)
}
}
}

To restore the state of your application when returning from a deeplink, use the android:launchMode="singleTop" attribute on MainActivity (listed in the example manifest above).

SDK Initialization​

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

AndroidManifest.xml
<meta-data
android:name="console_app_id_value"
android:value="@string/CONSOLE_APPLICATION_ID" />

In strings.xml replace the line with your app_id.

strings.xml
<string name="CONSOLE_APPLICATION_ID">your_app_id</string>

CONSOLE_APPLICATION_ID — 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
  • ApplicationId specified in build.gradle must match the applicationId of the APK file that you published in RuStore Console.
  • The keystore signature must match the signature that was used to sign the app published in the RuStore Console. Make sure that buildType used (example: debug) uses the same signature as the published app (example: release).

information

For security purposes, the SDK sets android:usesCleartextTraffic="false" by default to prevent data transfer over unsecured HTTP and protect against Man-in-the-Middle attacks. If your application requires the use of HTTP, you can change this attribute to true, but do so at your own risk, as this increases the chance of data interception and tampering. We recommend allowing unsecured traffic only in exceptional circumstances and for trusted domains, preferring HTTPS for all network communications.

Required Permissions and Security Parameters​

The Pay SDK automatically adds some permissions and parameters to the application's manifest that are necessary for the functionality related to payment security.

Other Permissions

The Pay SDK may also require other standard permissions, such as:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

SDK Methods​

Available public interactors:

  • PurchaseInteractor - an interactor that allows you to work with payments and has several public methods.

    • RuStoreReactPay.getPurchase(purchaseId: string): Promise<{ productPurchase?: ProductPurchase; subscriptionPurchase?: SubscriptionPurchase }> - allows you to get information about a purchase by its ID.
    • RuStoreReactPay.getPurchases(params?: { productType?: ProductType; purchaseStatus?: ProductPurchaseStatus | SubscriptionPurchaseStatus; acknowledgementState?: AcknowledgementState; }): Promise<Array<{ productPurchase?: ProductPurchase; subscriptionPurchase?: SubscriptionPurchase }>> - allows you to receive user purchases. This method supports optional filtering by type of goods (consumable, non-consumable goods or subscriptions), by purchase status (the statuses PAID, CONFIRMED, ACTIVE and PAUSED are supported), as well as by product delivery state (PENDING, ACKNOWLEDGED). By default, filters are disabled, and all user purchases (regardless of product type) in the PAID, CONFIRMED ACTIVE and PAUSED statuses will be returned.
    • RuStoreReactPay.getPurchaseAvailability(): Promise<PurchaseAvailability> - returns the result of checking the availability of working with payments.
    • RuStoreReactPay.purchase(params: { productId: string; orderId?: string; quantity?: number; developerPayload?: string; appUserId?: string; appUserEmail?: string; preferredPurchaseType?: PreferredPurchaseType; sdkTheme?: SdkTheme; purchaseEventListener?: PurchaseEventListener; }): Promise<ProductPurchaseResult> - allows you to make a purchase of a product indicating the desired type of payment - one-stage (ONE_STEP) or two-stage (TWO_STEP). For this payment method, all payment methods are available on the payment curtain. If the parameter is not specified, by default it starts with payment in one stage.
    Important!

    If the payment type TWO_STEP is specified, an attempt will be made to launch a two-stage payment, but the final result will directly depend on which payment method (card, SBP, etc.) is selected by the user.

    *Please note that payment type TWO_STEP is not available:

    • When choosing the payment method SBP. *When purchasing subscriptions.

    • Two-stage payment is available only for a certain set of payment methods (currently only for cards and SberPay). If a payment method is selected that does not support holding, then the purchase will be triggered according to a one-stage scenario.

    • RuStoreReactPay.purchaseTwoStep(params: { productId: string; orderId?: string; quantity?: number; developerPayload?: string; appUserId?: string; appUserEmail?: string; sdkTheme?: SdkTheme; purchaseEventListener?: PurchaseEventListener; }): Promise<ProductPurchaseResult> - launches a scenario for a guaranteed two-stage purchase of a product. When using this method, the user has access to a limited set of payment methods on the payment curtain - only those that support two-step payment. During the payment process, the buyer's funds are first held, which are debited only after the purchase is confirmed using the confirmTwoStepPurchase method.
    • RuStoreReactPay.confirmTwoStepPurchase(params: { purchaseId: string; developerPayload?: string; }): Promise<void> - confirmation of a purchase made using two-step payment.
    • RuStoreReactPay.cancelTwoStepPurchase(purchaseId: string): Promise<void> - canceling a purchase made using two-step payment.
    • RuStoreReactPay.updateAcknowledgementState(purchaseId: string, acknowledgementState: AcknowledgementState, developerPayload?: string): Promise<AcknowledgementState> - allows you to change the product delivery state for a purchase and returns the actual state after the operation is completed.
    • RuStoreReactPay.getBillingSubscriptions(): Promise<BillingSubscription[]> - allows you to get a list of subscriptions issued in the SDK Billing Client.
  • ProductInteractor - an interactor that allows you to work with products:

    • RuStoreReactPay.getProducts(ids: string[]): Promise<Product[]> - allows you to get information on active products published in the RuStore console.
    Important

    This method returns no more than 1000 products and works without authorization or the presence of RuStore installed on the user’s device.

  • UserInteractor - an interactor that allows you to get the user's authorization status UserAuthorizationStatus. This model can have 2 states:

    • AUTHORIZED - the user is authorized in RuStore
    • UNAUTHORIZED - the user is not authorized in RuStore. Additional method: RuStoreReactPay.getUserAuthorizationStatus(): Promise<boolean> - true corresponds to AUTHORIZED, false - UNAUTHORIZED.
  • block RuStoreUtils - a set of public methods, such as:

    • isRuStoreInstalled - checks for the presence of the RuStore application on the user's device.
    • openRuStoreDownloadInstruction - opens a web page for downloading the RuStore application.
    • openRuStore - launches the RuStore application.
    • openRuStoreAuthorization - launches the RuStore application for authorization. After successful user authorization, the RuStore application will automatically close.

Retrieving product list​

To retrieve the products added to your application via the RuStore Console, you must use the method:s getProducts.

// Getting a list of products
RuStoreReactPay.getProducts(productIds)
.then((products) => {
// products — массив Product[]
products.forEach((product) => {
console.log(product.productId);
});
})
.catch((err) => {
console.log('products err:', err);
});

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 a list of products. The product model is shown below.

export type Product = {
productId: string;
type: ProductType;
amountLabel: string;
price?: number;
currency: string;
imageUrl: string;
title: string;
description?: string;
subscriptionInfo?: SubscriptionInfo;
};
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • type — product type. CONSUMABLE_PRODUCT/NON_CONSUMABLE_PRODUCT/SUBSCRIPTION (consumable/non-consumable/subscription).
  • amountLabel — formatted purchase price, including currency symbol.
  • price — price in minimum currency units.
  • currency — ISO 4217 currency code.
  • imageUrl — image URL.
  • title — product name in language.
  • description — descriptions in language.
    • subscriptionInfo — subscription information (will be non-null if product type is SUBSCRIPTION).
    .

Structure of subscription information

The subscriptionInfo model contains information about the subscription product.

export type SubscriptionInfo = {
periods: SubscriptionPeriod[];
};

Subscription Period Information Structure

export type SubscriptionPeriod =
| {
type: "MAIN" | "TRIAL" | "PROMO";
duration: string;
currency: string;
price: number;
}
| {
type: "GRACE" | "HOLD";
duration: string;
};

Types of subscription periods

  1. TRIAL (free trial period)
  • duration - duration of the period in ISO 8601 format (for example, "P7D" - 7 days, "P1M" - 1 month)
  • currency - ISO 4217 currency code
  • price - price in minimum currency units
  1. PROMO (promotional period)
  • duration - duration of the period in ISO 8601 format
  • currency - ISO 4217 currency code
  • price - price in minimum currency units
  1. MAIN (main period)
  • duration - duration of the period in ISO 8601 format
  • currency - ISO 4217 currency code
  • price - price in minimum currency units
  1. GRACE (grace period)
  • duration - duration of the period in ISO 8601 format
  1. HOLD (suspension period)
  • duration - duration of the period in ISO 8601 format

Answer Examples

The method returns an array of Product objects.

Example Consumable Product Model
{
productId: 'conProduct1',
type: 'CONSUMABLE_PRODUCT',
amountLabel: '100.00 руб.',
price: 10000,
currency: 'RUB',
imageUrl: 'https://your_image_consumable_product.png',
title: 'Name of the Consumed Product',
description: 'Description of the product consumed',
}
Non-Consumable Product Model Example
{
productId: 'nonConProduct1',
type: 'NON_CONSUMABLE_PRODUCT',
amountLabel: '200.00 руб.',
price: 20000,
currency: 'RUB',
imageUrl: 'https://your_image_non_consumable_product.png',
title: 'Name of Non-Consumable Product',
description: 'Description of the Non-Consumable Product',
}
Subscription Model Example
{
productId: 'sub_1',
type: 'SUBSCRIPTION',
amountLabel: '300.00 руб.',
price: 30000,
currency: 'RUB',
imageUrl: 'https://your_image_subscription.png',
title: 'Name of your subscription',
description: 'Description of your subscription',
subscriptionInfo: {
periods: [
{ type: 'TRIAL', duration: 'P1M', currency: 'RUB', price: 0 },
{ type: 'PROMO', duration: 'P5D', currency: 'RUB', price: 149 },
{ type: 'MAIN', duration: 'P1Y', currency: 'RUB', price: 299 },
{ type: 'GRACE', duration: 'P3D' },
{ type: 'HOLD', duration: 'P5D' },
],
},
}

Determine user authorization status​

The result of this method is the Promise<boolean>: true — user is authorized in RuStore, false — user is not authorized in RuStore (or RuStore is not installed on the user's device).

RuStoreReactPay.getUserAuthorizationStatus()
.then((isAuthorized) => {
if (isAuthorized) {
// Logic for when the user is authorized in RuStore
} else {
// Logic for when the user is NOT authorized in RuStore
}
})
.catch((error) => {
// Handling error
});

Check payment availability​

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

  • The application has the ability to make purchases in RuStore Console.
  • The user and the application must not be blocked in RuStore.

The method returns a PurchaseAvailability object:

PurchaseAvailability Model
export type PurchaseAvailability = {
availability: boolean;
cause?: string;
};
  • availability - a sign of availability of purchases.
  • cause - the reason for the unavailability of purchases (filled in if availability is false).
Call the getPurchaseAvailability method
// Receive information about the availability of purchases
RuStoreReactPay.getPurchaseAvailability().then((value) => {
// value.availability — shopping availability indicator
if (value.availability) {
// Shopping is available
} else {
// Purchases are unavailable due to value.cause
}
}).catch((error) => {
// Error handling
});

Purchase product​

Notes on one-step and two-step payments
  • 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.
Payment type restrictions for subscriptions

At the moment, a subscription purchase (SubscriptionPurchase) can only be made using a one-step payment ('ONE_STEP').

Important

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 choice of purchase type

To call a product purchase with a choice of stages of payment, use the purchase method. The method takes a single object argument.

Calling the product purchase method
RuStoreReactPay.purchase(params: {
productId: string | null;
orderId?: string | null;
quantity?: number | null;
developerPayload?: string | null;
appUserId?: string | null;
appUserEmail?: string | null;
preferredPurchaseType?: PreferredPurchaseType | null;
sdkTheme?: SdkTheme | null;
purchaseEventListener?: PurchaseEventListener | null;
}): Promise<ProductPurchaseResult>
  • preferredPurchaseType — the desired purchase type: single-stage (ONE_STEP) or two-stage (TWO_STEP).
Important

This method is launched by default using the single-stage payment scenario (preferredPurchaseType: 'ONE_STEP'), i.e., without funds being held.

For two-stage payment, you need to specify 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 holding funds)

To invoke the purchase of a product in a two-step scenario, use the purchaseTwoStep method.

info

When calling this method, the user will have access to a limited set of payment methods - only those that support two-step payment.

Restrictions on payment types for subscriptions

At the moment, a subscription purchase (SubscriptionPurchase) can only be made using a one-step payment ('ONE_STEP').

Calling a two-step product purchase method
RuStoreReactPay.purchaseTwoStep(params: {
productId: string | null;
orderId?: string | null;
quantity?: number | null;
developerPayload?: string | null;
appUserId?: string | null;
appUserEmail?: string | null;
sdkTheme?: SdkTheme | null;
purchaseEventListener?: PurchaseEventListener | null;
}): Promise<ProductPurchaseResult>

Working with PurchaseEventListener

The purchase and purchaseTwoStep methods can be passed an optional parameter purchaseEventListener - an object with optional callbacks that allow you to track the stages of the purchase. Each callback accepts an object with purchaseId and invoiceId fields.

  • onPurchaseCreated — the purchase has been created (the invoice has been generated);
  • onPaymentStarted — payment has started;
  • onPaymentCompleted — payment completed successfully;
  • onPaymentFailed — payment error;
  • onPurchaseCancelled - canceling a purchase.

Type signature​

type PurchaseEventListenerParams = {
purchaseId?: string | null;
invoiceId?: string | null;
};

type PurchaseEventListener = {
onPurchaseCreated?: (params: PurchaseEventListenerParams) => void;
onPaymentStarted?: (params: PurchaseEventListenerParams) => void;
onPaymentCompleted?: (params: PurchaseEventListenerParams) => void;
onPaymentFailed?: (params: PurchaseEventListenerParams) => void;
onPurchaseCancelled?: (params: PurchaseEventListenerParams) => void;
};

Usage example​

// Create a listener
const purchaseEventListener: PurchaseEventListener = {
onPurchaseCreated: ({ purchaseId, invoiceId }) => {
console.log(`Purchase created: ${purchaseId}, check: ${invoiceId}`);
},
onPaymentStarted: ({ purchaseId, invoiceId }) => {
console.log(`Payment has started: ${purchaseId}, check: ${invoiceId}`);
},
onPaymentCompleted: ({ purchaseId, invoiceId }) => {
console.log(`Payment successful: ${purchaseId}, check: ${invoiceId}`);
},
onPaymentFailed: ({ purchaseId, invoiceId }) => {
console.error(`Payment error: ${purchaseId}, check: ${invoiceId}`);
},
onPurchaseCancelled: ({ purchaseId, invoiceId }) => {
console.log(`Purchase canceled: ${purchaseId}, check: ${invoiceId}`);
},
};

// Pass the listener to the purchase method parameters object
try {
const result = await RuStoreReactPay.purchase({
productId: 'your_product_id',
appUserId: 'user_123',
appUserEmail: 'user@example.com',
preferredPurchaseType: 'ONE_STEP',
sdkTheme: 'LIGHT',
purchaseEventListener,
});
console.log('Result:', result);
} catch (error) {
console.error('Error:', error);
}
  • 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 — an additional order information string that you can set when confirming a purchase. This string overrides the value set during initialization. Maximum length: 250 characters. Characters are not escaped (if quotes are used, escaping is required). Maximum length is 250 characters.
  • appUserId — the internal user ID in your application (optional parameter). A string with a maximum length of 128 characters.
    tip

    For 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 the email 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.
  • sdkTheme — payment interface theme: 'LIGHT' (light) or 'DARK' (dark). Optional parameter, default is light theme.
  • purchaseEventListener - listener for purchase process events (see example above). Optional parameter.

Purchase result structure​

ProductPurchaseResult — the result of a successful digital product payment (for one-step payments) or a successful fund hold (for two-step payments).

interface ProductPurchaseResult {
orderId?: string;
purchaseId: string;
productId: string;
invoiceId: string;
purchaseType: PurchaseType;
productType: ProductType;
quantity: number;
sandbox: boolean;
}
  • ProductPurchaseResult — the result of a successful digital product payment (for one-step payments) or a successful fund hold (for two-step payments).

    • purchaseId - purchase identifier. Used to get purchase information in the SDK using the get purchase information method and for server-side subscription validation.
    • productId - identifier of the purchased product, specified when creating it in the RuStore developer console.
    • invoiceId - invoice identifier. Used for server-side payment validation, searching for payments in the developer console, and is also displayed to the buyer in the payment history in the RuStore mobile app.
    • orderId - unique payment identifier, specified by the developer or generated automatically (uuid).
    • purchaseType - purchase type (ONE_STEP/TWO_STEP/UNDEFINED - one-step/two-step/undefined).
    • productType - product type (NON_CONSUMABLE_PRODUCT - non-consumable product, CONSUMABLE_PRODUCT - consumable product, SUBSCRIPTION - subscription).
    • quantity - product quantity specified at the start of the purchase.
    • sandbox - a flag indicating a test payment in the sandbox. If true - the purchase was made in test mode.

Confirming purchase​

Confirmation is required only for purchases that were launched using a two-stage payment scenario, i.e. with holding funds. Such purchases, after successful holding, will be in PAID status.

Proof of purchase is required to charge the customer's card. To do this you must use the confirmTwoStepPurchase method.

// Confirmation of two-stage purchase
RuStoreReactPay.confirmTwoStepPurchase({ purchaseId })
.then(() => {
// Process success
})
.catch((error) => {
// Process error
});
  • purchaseId — product ID.
  • developerPayload — an additional order information string that you can set when confirming a purchase. This string overrides the value set during initialization. Maximum length: 250 characters. Characters are not escaped (if quotes are used, escaping is required)

Cancelling purchase​

Through the SDK, you can cancel only those purchases that were launched using a two-stage payment scenario, i.e. with holding funds.

Such purchases after successful payment will be in PAID status. After cancellation, purchases will switch to REVERSED status.

Use purchase cancellation in cases where, after payment (holding funds), you cannot provide the buyer with the goods.

To cancel a purchase (hold), use the cancelTwoStepPurchase method:

RuStoreReactPay.cancelTwoStepPurchase(purchaseId)
.then(() => {
// Process success
})
.catch((error) => {
// Process error
});
  • purchaseId — product ID.

Handling product delivery confirmation​

To update the purchase acknowledgement state, use the updateAcknowledgementState method.

Confirmation of delivery of goods upon purchase
RuStoreReactPay.updateAcknowledgementState(
'PURCHASE_ID',
'ACKNOWLEDGED',
'DEVELOPER_PAYLOAD',
)
.then((state) => {
// state — the state of the product delivery after the operation is completed
})
.catch((error) => {
// Error handling
});

Logic is optional and does not affect payments. It allows you to store the state of purchase processing on the RuStore side, so that when you receive a shopping list with separate filtering, you can select only unprocessed purchases and issue goods based on them.

After a successful payment, the default status for issuing goods is PENDING.

For payments made in earlier versions of the SDK, where this logic was not yet supported, the UNKNOWN status is used. If necessary, this status can be changed to any other.

The processing status can be changed in both directions: for example, transferring a purchase from PENDING to ACKNOWLEDGED, and also returning it to the previous status if you need to recall a previously issued product, for example after a payment has been returned.

When this method is called, the value of developerPayload can be updated. If a parameter is passed, the current value will be overwritten. If no parameter is passed, the current value of developerPayload will be retained.

The method returns the actual status of the item issuance after the operation is completed - it may differ from the requested one.

  • purchaseId — product ID.
  • acknowledgementState - new purchase confirmation state. Available values: 'PENDING', 'ACKNOWLEDGED', 'UNKNOWN'.
  • developerPayload — an additional order information string that you can set when confirming a purchase. This string overrides the value set during initialization. Maximum length: 250 characters. Characters are not escaped (if quotes are used, escaping is required) (optional).

Retrieving purchase information​

Go get purchase information, use the getPurchase method.
// Get information about a specific purchase
RuStoreReactPay.getPurchase(purchaseId: string): Promise<{
productPurchase?: ProductPurchase;
subscriptionPurchase?: SubscriptionPurchase;
}>

// Get a shopping list with filtering
RuStoreReactPay.getPurchases(params?: {
productType?: ProductType;
purchaseStatus?: ProductPurchaseStatus | SubscriptionPurchaseStatus;
acknowledgementState?: AcknowledgementState;
}): Promise<Array<{
productPurchase?: ProductPurchase;
subscriptionPurchase?: SubscriptionPurchase;
}>>

The method returns information about a specific purchase in any status. The purchase model is listed in the purchase types section

Retrieving purchase list​

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

Calling the method to get the user's shopping list
RuStoreReactPay.getPurchases()
.then((purchases) => {
purchases.forEach((purchase) => {
// each purchase can contain either a productPurchase or subscriptionPurchase object
const { productPurchase, subscriptionPurchase } = purchase;
if (productPurchase) {
console.log(`Product ID: ${productPurchase.productId}, Status: ${productPurchase.status}`);
} else if (subscriptionPurchase) {
console.log(`Product ID: ${subscriptionPurchase.productId}, Status: ${subscriptionPurchase.status}`);
}
});
})
.catch((error) => {
// Error handling
});

This method allows you to filter purchases by product type, purchase status and product delivery state:

Product types:

  • Consumable goods - 'CONSUMABLE_PRODUCT'
  • Non-consumable goods - 'NON_CONSUMABLE_PRODUCT'
  • Subscriptions - 'SUBSCRIPTION'

Purchase statuses:

  • For products:

    • PAID: Successful holding of funds, the purchase is awaiting confirmation from the developer.
    • CONFIRMED: Purchase confirmed, funds debited.
  • For subscriptions:

    • ACTIVE: Subscription is active.
    • PAUSED: Subscription in the Hold period (for example, due to insufficient funds on the card), attempts to write off continue in accordance with the subscription tariff settings.

Product delivery state:

  • PENDING: The product has been paid for, but delivery has not yet been confirmed.
  • ACKNOWLEDGED: Product delivery is confirmed.

Passing the 'UNKNOWN' value is equivalent to no filter - you cannot select purchases specifically in the UNKNOWN state.

By default, filters are disabled; if no values ​​are specified, the method will return all user purchases in the statuses PAID, CONFIRMED, ACTIVE and PAUSED, regardless of the product type.

Calling a method for getting a user's shopping list with filtering
// Example call with filters by product type, purchase status and product delivery state
// Pass an object with the required productType, purchaseStatus and acknowledgementState fields
RuStoreReactPay.getPurchases({
// productType: 'CONSUMABLE_PRODUCT',
// purchaseStatus: 'PAID',
// acknowledgementState: 'PENDING',
})
.then((purchases) => {
purchases.forEach((purchase) => {
const { productPurchase, subscriptionPurchase } = purchase;
if (productPurchase) {
console.log(`Product ID: ${productPurchase.productId}, Status: ${productPurchase.status}`);
} else if (subscriptionPurchase) {
console.log(`Product ID: ${subscriptionPurchase.productId}, Status: ${subscriptionPurchase.status}`);
}
});
})
.catch((error) => {
// Error handling
});

Purchase types​

In the SDK, there is a base Purchase interface that unifies the common fields for all purchase types. It has two implementations:

  • ProductPurchase — for consumable and non-consumable purchases.
  • SubscriptionPurchase — for subscriptions.

This separation allows each purchase type to expose its own specific properties and behavior.

Purchase type
export type Purchase = {
productPurchase?: ProductPurchase;
subscriptionPurchase?: SubscriptionPurchase;
};

The getPurchase and getPurchases methods return Purchase objects. Each object contains either a filled productPurchase field (one-time purchase) or subscriptionPurchase (subscription).

One-time purchase model ProductPurchase​

One-time purchase model
export type ProductPurchase = {
purchaseId: string;
invoiceId: string;
orderId?: string;
purchaseType: PurchaseType;
status: ProductPurchaseStatus;
description: string;
purchaseTime?: string;
price: number;
amountLabel: string;
currency: string;
developerPayload?: string;
sandbox: boolean;
productId: string;
quantity: number;
acknowledgementState: AcknowledgementState;
productType: ProductType;
};

Inherited fields:

  • purchaseId — product ID.
  • 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.
  • PurchaseType — purchase type:
    • ONE_STEP - one-stage payment;
    • TWO_STEP - two-stage payment;
    • UNDEFINED - number of stages is undefined.
  • description — descriptions in language.
  • purchaseTime — purchase time.
  • price — price in minimum currency units.
  • amountLabel — formatted purchase price, including currency symbol.
  • currency — ISO 4217 currency code.
  • developerPayload — an additional order information string that you can set when confirming a purchase. This string overrides the value set during initialization. Maximum length: 250 characters. Characters are not escaped (if quotes are used, escaping is required)
  • — test payment flag. true — test payment, false — actual payment

Unique fields:

  • productId — product ID assigned to product in RuStore Console (mandatory).
  • productType — product type.
    • NON_CONSUMABLE_PRODUCT;
    • CONSUMABLE_PRODUCT.
  • quantity — product amount (optional, value 1 will be used if not specified).
  • acknowledgementState — product acknowledgement state. Possible values: PENDING (waiting for item delivery), ACKNOWLEDGED (item delivered), UNKNOWN (this logic does not apply to the payment).
  • 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);
    • CONFIRMED — purchase successfully paid for;
    • REFUNDED — purchase successfully refunded;
    • REFUNDING — refunding initiated, request sent to the acquirer;
    • EXECUTING — the purchase is in progress;
    • 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;
    • 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.

Response examples

Example of a consumable product purchase model
{
purchaseId: 'purchaseId',
invoiceId: 'invoiceId',
orderId: 'orderId',
purchaseType: 'ONE_STEP',
status: 'CONFIRMED',
description: 'Purchase description',
purchaseTime: '2026-07-01T12:00:00+03:00',
price: 14100,
amountLabel: '141,00 ₽',
currency: 'RUB',
developerPayload: 'developerPayload',
sandbox: false,
productId: 'game_coins_1000',
quantity: 1,
acknowledgementState: 'PENDING',
productType: 'CONSUMABLE_PRODUCT',
}

Purchase status model​

One-stage payment status model.

Two-stage payment status model.

Subscription model SubscriptionPurchase​

Subscription model SubscriptionPurchase
export type SubscriptionPurchase = {
purchaseId: string;
invoiceId: string;
orderId?: string;
purchaseType: PurchaseType;
status: SubscriptionPurchaseStatus;
description: string;
purchaseTime?: string;
price: number;
amountLabel: string;
currency: string;
developerPayload?: string;
sandbox: boolean;
productId: string;
expirationDate: string;
gracePeriodEnabled: boolean;
acknowledgementState: AcknowledgementState;
};
  • purchaseId — product ID — the purchase identifier. Used to retrieve purchase details in the SDK via the purchase info method.

  • invoiceId — invoice ID — the invoice identifier. Used for server-side payment validation, for searching payments in the Developer Console, and is shown to the buyer in their payment history.

  • orderId — a unique payment identifier provided 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.
  • status — subscription flow status:

    • INVOICE_CREATED — an invoice has been created; the subscription is waiting for payment.
    • CANCELLED — the subscription invoice was canceled.
    • EXPIRED — the time to pay the initial invoice has expired; no subscription was created.
    • PROCESSING — the first subscription payment is being processed.
    • REJECTED — the first subscription payment was rejected. The subscription was not created.
    • ACTIVE — the subscription is active.
    • PAUSED — the subscription is paused due to payment issues.
    • TERMINATED — all retry attempts for the subscription failed. The subscription was automatically closed due to payment issues.
    • CLOSED — the subscription was canceled by the user or the developer. After the paid period ended, the subscription was closed.
  • description — purchase description.

  • purchaseTime — purchase time.

  • price — price in minimum currency units.

  • amountLabel — formatted purchase price, including currency symbol.

  • currency — ISO 4217 currency code.

  • developerPayload — an additional order information string that you can set when confirming a purchase. This string overrides the value set during initialization. Maximum length: 250 characters. Characters are not escaped (if quotes are used, escaping is required).

  • — test payment flag. true — test payment, false — actual payment.

  • productId — product ID assigned to product in RuStore Console (mandatory) — the product identifier assigned in RuStore Console (required).

  • expirationDate — the subscription end date.

  • gracePeriodEnabled — a flag indicating whether the grace period is enabled for the subscription.

  • acknowledgementState - product delivery state. Possible values: PENDING (awaiting product delivery), ACKNOWLEDGED (product delivered), UNKNOWN (logic is not applicable to the payment).

Response examples

Example of a subscription purchase model
{
purchaseId: 'sub_purchase_12345',
invoiceId: 'inv_sub_67890',
orderId: 'order_sub_abcde',
purchaseType: 'ONE_STEP',
status: 'ACTIVE',
description: 'Monthly Premium subscription',
purchaseTime: '2026-07-01T12:00:00+03:00',
price: 29900,
amountLabel: '299,00 ₽',
currency: 'RUB',
developerPayload: 'user_id:123;source:profile',
sandbox: false,
productId: 'premium_monthly_v1',
expirationDate: '2026-08-01T12:00:00+03:00',
gracePeriodEnabled: true,
acknowledgementState: 'ACKNOWLEDGED',
}

Subscription status model​

Getting a list of subscriptions issued in the SDK Billing Client​

Getting a list of subscriptions issued in the SDK Billing Client
RuStoreReactPay.getBillingSubscriptions()
.then((subscriptions) => {
subscriptions.forEach((subscription) => {
// subscription.subscriptionToken — token for server-side validation
console.log(`Product ID: ${subscription.productId}, Status: ${subscription.status}`);
});
})
.catch((error) => {
// Error handling
});

The method returns a list of subscriptions registered in the Billing Client SDK.

The user must be authorized in RuStore for the method to work. If called by an unauthorized user, the method returns an error.

Subscriptions obtained by this method are not included in the results of the getPurchase and getPurchases methods - this is a separate data source.

The SDK provides only the method itself: when and under what conditions to call it is determined by the business logic of your application.

Model of a subscription purchase issued in the SDK Billing Client​

Model of a subscription issued in the SDK Billing Client
export type BillingSubscription = {
purchaseId: string;
invoiceId: string;
orderId?: string;
purchaseType: PurchaseType;
status: SubscriptionPurchaseStatus;
description: string;
purchaseTime?: string;
price: number;
amountLabel: string;
currency: string;
developerPayload?: string;
sandbox: boolean;
productId: string;
expirationDate: string;
gracePeriodEnabled: boolean;
subscriptionToken: string;
};

Unlike the ProductPurchase and SubscriptionPurchase models, such subscriptions are not included in the results of the getPurchase and getPurchases methods - they are returned only by the getBillingSubscriptions method.

Model fields:

  • purchaseId — product ID.
  • 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.
  • purchaseType — purchase type:
    • ONE_STEP - one-stage payment;
    • TWO_STEP - two-stage payment;
    • UNDEFINED - number of stages is undefined.
  • status - subscription status of the SubscriptionPurchaseStatus type.
  • description — descriptions in language.
  • purchaseTime — purchase time.
  • price — price in minimum currency units.
  • amountLabel — formatted purchase price, including currency symbol.
  • currency — ISO 4217 currency code.
  • developerPayload — an additional order information string that you can set when confirming a purchase. This string overrides the value set during initialization. Maximum length: 250 characters. Characters are not escaped (if quotes are used, escaping is required)
  • — test payment flag. true — test payment, false — actual payment
  • productId — product ID assigned to product in RuStore Console (mandatory).
  • expirationDate - subscription expiration date.
  • gracePeriodEnabled - flag indicating whether the grace period is active for the subscription.
  • subscriptionToken — purchase token for server validation .

Subscription statuses SubscriptionPurchaseStatus:

  • INVOICE_CREATED — an invoice for payment has been created, the subscription is awaiting payment;
  • CANCELLED - subscription was canceled by the user;
  • EXPIRED - subscription has expired;
  • PROCESSING - payment is being processed;
  • REJECTED - payment rejected;
  • ACTIVE — subscription is active;
  • PAUSED - subscription is suspended due to payment problems;
  • TERMINATED — subscription debit attempts have ended (all were unsuccessful). Subscription closed automatically due to payment problems;
  • CLOSED - the subscription was canceled by the user or developer. The paid period has expired, the subscription is closed.

Response examples

Example of a subscription model issued in the SDK Billing Client
{
purchaseId: 'sub_purchase_12345',
invoiceId: 'inv_sub_67890',
orderId: 'order_sub_abcde',
purchaseType: 'ONE_STEP',
status: 'ACTIVE',
description: 'Monthly Premium subscription',
purchaseTime: '2026-07-01T12:00:00+03:00',
price: 29900,
amountLabel: '299,00 ₽',
currency: 'RUB',
developerPayload: 'user_id:123;source:profile',
sandbox: false,
productId: 'premium_monthly_v1',
expirationDate: '2026-08-01T12:00:00+03:00',
gracePeriodEnabled: true,
subscriptionToken: 'special_validation_token',
}

Error handling​

If an error occurs during the payment process or the user cancels the purchase, the payment method terminates with an error.

To determine that this is a Pay SDK error, use the isRuStorePayError type guard. The error is represented by the RuStorePayError type with a code field (of the RuStoreErrorCode type) and a text message. The purchase cancellation indicator (the user closed the payment sheet) is the ProductPurchaseCancelled code; in this case, it is recommended to additionally check the purchase status using the get purchase information method. Other purchase errors come with the ProductPurchaseException code.

try {
const result = await RuStoreReactPay.purchase({ productId: 'productId' });
// Logic for handling a successful purchase result
} catch (error) {
if (RuStoreReactPay.isRuStorePayError(error)) {
if (error.code === 'ProductPurchaseCancelled') {
// Purchase cancelled - check the status using the get purchase information method
} else {
// Handling other purchase errors: error.code, error.message
}
} else {
// Handling an error unrelated to the Pay SDK
}
}

Server-side purchase validation​

If you need to validate a successful purchase in RuStore, you can use public validation APIs. Different methods are used to validate products and subscriptions:

  • To validate a product purchase, use the invoiceId from the ProductPurchaseResult model returned after the purchase is completed.
  • To validate a subscription purchase, use the purchaseId from the ProductPurchaseResult model returned after the purchase is completed.

The type of product purchased can be determined from the data received in the ProductPurchaseResult response.

You can also get the invoiceId in the Purchase entity. The Purchase entity can be obtained using the getPurchases() method.

Getting invoiceId/purchaseId from the purchase result
// An example of obtaining invoiceId or purchaseId from a purchase result for validation on the server
const params = {
productId: 'productId',
preferredPurchaseType: 'TWO_STEP',
};

RuStoreReactPay.purchase(params)
.then((result) => {
// result.productType — 'CONSUMABLE_PRODUCT', 'NON_CONSUMABLE_PRODUCT' или 'SUBSCRIPTION'
if (
result.productType === 'CONSUMABLE_PRODUCT' ||
result.productType === 'NON_CONSUMABLE_PRODUCT'
) {
const invoiceId = result.invoiceId;
yourApi.validateProduct(invoiceId);
} else if (result.productType === 'SUBSCRIPTION') {
const purchaseId = result.purchaseId;
yourApi.validateSubscription(purchaseId);
}
})
.catch((error) => {
// Handling purchase errors
});
Getting purchaseId from the Purchase model
// Example of getting purchaseId (subscriptionToken) to validate a subscription
RuStoreReactPay.getPurchases()
.then((purchases) => {
purchases.forEach((purchase) => {
// each purchase can be either a product or a subscription
const { productPurchase, subscriptionPurchase } = purchase;
if (subscriptionPurchase) {
const purchaseId = subscriptionPurchase.purchaseId;
yourApi.validateSubscription(purchaseId);
} else if (productPurchase) {
const invoiceId = productPurchase.invoiceId;
yourApi.validateProduct(invoiceId);
}
});
})
.catch((error) => {
// Error handling
});

RuStoreUtils​

RuStoreUtils is a block in the native SDK containing a set of public methods designed to interact with the RuStore application on the user’s device.

To access block methods, the singleton of the RuStoreReactPay class is used.

The isRuStoreInstalled method checks the presence of the RuStore application on the user's device.

Calling the isRuStoreInstalled method
RuStoreReactPay.isRuStoreInstalled().then((isInstalled) => {
if (isInstalled) {
// 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.

Calling the openRuStoreDownloadInstruction method
RuStoreReactPay.openRuStoreDownloadInstruction();

The openRuStore method launches the RuStore mobile application. When calling this method, if the RuStore application is not installed, a Toast notification will be displayed with the message “Failed to open the application.”

Calling the openRuStore method
RuStoreReactPay.openRuStore();

The openRuStoreAuthorization method launches the RuStore mobile application for authorization. After successful user authorization, the RuStore application closes automatically. When calling this method, if the RuStore application is not installed, a Toast notification will be displayed with the message “Failed to open the application.”

Calling the openRuStoreAuthorization method
RuStoreReactPay.openRuStoreAuthorization();

Using RuStoreUtils to check payment scripts

The case of using RuStoreUtils to check the presence of RuStore on a device and work with user authorization is discussed in the article Accepting payments without installing RuStore.

The article provides:

  • Scenarios for working with purchases in the absence of RuStore installed;

  • Examples of sequential calling of installation and authorization verification methods through RuStoreUtils;

  • Features of SDK behavior under different conditions (presence/absence of RuStore, user authorization, etc.).

Error list​

RuStorePaymentNetworkException — SDK network interaction error. The error model returns an error code (the code field), which can be used to determine the cause of the error. A table with error codes is available in the error codes section. The message field contains a description of the error's cause.

export type RuStorePayError = {
code: RuStoreErrorCode;
message: string;
}

Errors come with a code (the code field of type RuStoreErrorCode) and a message (the message field). Possible error codes:

  • RuStorePaymentNetworkException — SDK network communication error;
  • RuStorePaymentCommonException - general payment SDK error;
  • RuStorePayClientAlreadyExist — SDK re-initialization error;
  • RuStorePayClientNotCreated - an attempt to access the public interfaces of the SDK before its initialization;
  • RuStorePayInvalidActivePurchase — payment initiated for unknown product type;
  • RuStorePayInvalidConsoleAppId - the required parameter console_app_id_value for SDK initialization is not specified;
  • RuStorePaySignatureException - invalid response signature. Occurs when trying to commit fraudulent actions;
  • EmptyPaymentTokenException — error in receiving a payment token;
  • InvalidCardBindingIdException — payment error with the saved card;
  • ApplicationSchemeWasNotProvided — the scheme for the reverse deep link is not specified;
  • ProductPurchaseException - product purchase error. The structure of the model is presented in the section structure of purchase result;
  • ProductPurchaseCancelled - the product purchase was canceled (the user closed the payment curtain). The structure of the model is presented in the section structure of purchase result;
  • RuStoreNotInstalledException — RuStore is not installed on the user’s device;
  • RuStoreOutdatedException — the version of RuStore installed on the device does not support payments;
  • RuStoreUserUnauthorizedException — the user is not authorized in RuStore;
  • RuStoreApplicationBannedException - the application is blocked in RuStore;
  • RuStoreUserBannedException - the user is blocked in RuStore.

Error codes​

Error codeDescription
4000001The request is formed incorrectly: a required parameter is missing or filled in incorrectly, the data format is incorrect.
4000002, 4000016, 4040005Application not found.
4000003The application is blocked.
4000004The application signature does not match the registered one.
4000005Company not found.
4000006The company is blocked.
4000007Company monetization is disabled or inactive.
4000014Product not found.
4000015Product not published.
4000017Invalid parameter quantity.
4000018Purchase limit exceeded.
4000020The product has already been purchased.
4000021Incomplete product purchase.
4000022Purchase not found.
4000025No suitable payment method found.
4000026Invalid purchase type for confirmation (must be two-step payment).
4000027Invalid purchase status for confirmation.
4000028Invalid purchase type to cancel (must be two-step payment).
4000029Invalid purchase status for cancellation.
4000030The issued token does not correspond to the product being purchased.
4000041The user already has an active subscription for this product code.
4000045Maximum size exceeded.
4010001Access to the requested resource is denied (unauthorized).
4010002The token's lifetime has expired.
4010003The payment token is invalid.
4030001The payment token was not transferred.
4030002The user is blocked due to security requirements.
4040002, 4040003, 4040004Payment system error.
5000***Internal error.