# BaaS

# Payment Routing

To connect to the service and get started, please contact Support (opens new window) or your supervising manager (opens new window).

# Sub-merchant Registration

A sub-merchant can be a legal entity or a sole proprietor.

To get started, a sub-merchant must independently create a Mandarin Personal Account through the standard registration (opens new window) process, completing steps from (1) submitting an application to (4) completing the application.

In addition to the main Personal Account registration process, bulk Personal Account creation is available through the registry. To use this scenario, please contact your supervising manager.

Once your Personal Account is approved, you can proceed to linking the created Sub-Merchant Personal Account to your Marketplace account.

# Creating a Sub-Merchant Account

To create a Sub-Merchant account, use the token, which is available in the Routing section of the Project Settings in the Sub-Merchant Personal Account.

Parameter Type Required Description
accountType string Yes Account type. For a legal entity, it is set to business.
token string Yes Legal entity account token.

The synchronous response contains the account id.

Request

POST https://secure.mandarinpay.com/api/v1/accounts/business
{

"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjaGFudF9pZCI6MiwiaXNzIjoiMzAg0LzQsNGPIDIwMjIg0LMuIn0.unGctyIBkp4EHXw-7bFqWbbkmfhs2yCJ-jAKJGqRP_1"

}

Response if account is successfully created (200 OK)

{
"id": "01dab7d8-be9b-4f87-ba91-801731787725",
"type": "Business"
}

Response if the request is not created (400 Bad request)

{
"error": "Invalid request"
}

# Payment Acceptance (Routing)

Standard API requests for payment acceptance are used, as described in the documentation. Single-stage payment (api_payments.md#single-stage-payment), recurring payment (auto-debit) (api_payments.md#recurring-payment-auto-debit), and two-stage payment (api_payments.md#two-stage-payment) are possible (in this case, authorization remains standard, and payment distribution occurs upon completion of settlements).

In this case, the routing.destination object containing the payment distribution scheme is added to the pay request. To accept payments, the sum of the amount values ​​from the routing object must equal the top-level amount!

IMPORTANT! When using two-step payment, the routing object is added to the second request with "action": "pay"

The payer can enter card details on the payment page or the embedded Mandarin Custom Pay payment form.

Parameter Type Required Description
routing Yes An object containing routing parameters.
routing.destination string Yes An array containing payment recipients.
routing.destination. accountId string Yes Recipient account ID.
routing.destination. amount.value string Yes The amount transferred to the recipient's account. For accepting payments, the platform fee will be deducted from this amount. Separator is a period.
routing.destination.amount.currency string Yes The currency of the amount transferred to the recipient's account. Currently, it is always RUB.
routing.destination.platformFeeAmount.value string Yes The platform fee, deducted from the amount transferred to the recipient's account. Separator is a period.
routing.destination.platformFeeAmount.currency string Yes The currency of the platform fee. Currently, it is always RUB.
routing.destination.description string No Description

In the example below, 5,000 rubles are debited from the payer's card and will be credited to the following recipients:

  • 3,950 rubles to account 16f90c5e-6bc3-11eb-9439-0242ac130002, which belongs to a legal entity.
  • 50 rubles to the platform account.
  • 950 rubles to account 8ba85f01-8cc8-4161-b45d-ce6442e678ae, which belongs to another legal entity.
  • another 50 rubles to the platform account. Total: 100 rubles to the platform account.

Request one-step payment

POST https://api.mandarin.io/secure/transactions
{ 
"payment": { 
"action": "pay", 
"orderId": "your_unique_order_id", 
"amount": { 
"value": "5000.00", 
"currency": "RUB" 
}, 
"orderActualTill": "2020-02-20 12:34:56+00:00" 
}, 
"routing": { 
"destination": [{ 
"accountId": "16f90c5e-6bc3-11eb-9439-0242ac130002", 
"amount": { 
"value": "4000.00", 
"currency": "RUB" 
}, 
"platformFeeAmount": { 
"value": "50.00", 
"currency": "RUB" 
}, 
"description": "" 
}, 
{ 
"accountId": "8ba85f01-8cc8-4161-b45d-ce6442e678ae", 
"amount": { 
"value": "1000.00", 
"currency": "RUB" 
}, 
"platformFeeAmount": { 
"value": "50.00",
"currency": "RUB"
},
"description": ""
}
]
},
"customerInfo": {
"email": "user@example.com",
"phone": "+79001234567"
}
}

The response to the request matches the standard response for creating transactions.

Response if the transaction is successfully created (200 OK)

{
"id": "43913ddc000c4d3990fddbd3980c1725",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=0eb51e74-e704-4c36-b5cb-8f0227621518",
"jsOperationId": "9874694yr87y73e7ey39ed80"
}

Response if the transaction is not created (400 Bad request)

{
"error": "Invalid request"
}

# Tokenization (Routing)

Standard tokenization requests are used for tokenization. The card token can then be used to create recurring charges, payments with a saved card in interactive mode, or payments with a saved card without entering the CVV code and without completing the checkout process. 3d-secure](api_payments.md#payment-by-saved-card-without-entering-cvv-cvc-code-and-without-passing-3d-secure)

# Payment Cancellation (Routing)

Standard API requests for refunds on previously completed payments are used, in accordance with the documentation.

To cancel a successful card debit transaction ("action": "pay"), use "action": "reversal" and the id of the previously completed transaction as target.transaction.

In this case, the routing.source object is added to the pay request, containing the refund distribution scheme between Sub-merchant accounts. To accept payments: the sum of the amount values ​​from the routing object must equal the top-level amount!

Cancellation is possible for the entire The transaction amount, as well as a partial cancellation (partial cancellation). An unlimited number of partial cancellations of a single payment transaction is allowed within the payment amount. Active participation of the payer is not required.

Parameter Required Parameter Required
routing Yes An object containing routing parameters.
routing.source string Yes An array containing payers.
routing.source.accountId string Yes The payer's account identifier.
routing.source.amount.value string Yes The amount transferred to the payer's account. Separator is a period.
routing.source.amount.currency string Yes The currency of the amount debited from the account Payer's Fee. Currently always RUB.
routing.source.platformFeeAmount. value string Yes Used when refunding the retained fee; can be 0. Separator: period.
routing.source.platformFeeAmount. currency string Yes Platform fee currency. Currently always RUB.
routing.source.description string No Description.

The synchronous response and asynchronous callback-notification may contain a wider range of parameters than in the example.

Request

POST https://secure.mandarinpay.com/api/transactions
{
"payment": {
"action": "reversal",
"orderId": "your_unique_order_id",
"price": "5000.00" 
}, 
"target": { 
"transaction": "43913ddc000c4d3990fddbd3980c1725" 
}, 
"customValues": [ 
{"name": "first parameter to save and show", "value": "p1"}, 
{"name": "second parameter to save and show", "value": "p2"} 
], 
"metadata": { 
"first_parameter_to_callback_and_not_to_show": "p1", 
"second_parameter_to_callback_and_not_to_show": "p2" 
}, 
"routing": { 
"source": [{ 
"accountId": "16f90c5e-6bc3-11eb-9439-0242ac130002", 
"amount": { 
"value": "4000.00", 
"currency": "RUB" 
}, 
"platformFeeAmount": { 
"value": "50.00", 
"currency": "RUB" 
}, 
"description": "" 
}, 
{ 
"accountId": "8ba85f01-8cc8-4161-b45d-ce6442e678ae", 
"amount": { 
"value": "1000.00", 
"currency": "RUB" 
}, 
"platformFeeAmount": { 
"value": "50.00", 
"currency": "RUB" 
}, 
"description": "" 
} 
] 
}, 
"urls": { 
"callback": "http://...", 
"return": "http://..." 
}
}

Reply if successful Transaction creation (200 OK)

{
"id": "43913ddc000c4d3990fddbd3980c1725"
}

Response if the transaction is not created (400 Bad request)

{
"error": "Invalid request"
}

# Funds Transfer (Routing)

Funds are transferred to Sub-merchants automatically the next business day after the payment date.

# Working with Virtual Accounts

# Creating and Maintaining Virtual Accounts

# Creating a Virtual Account (ESP)

Production https://payment-tokens.mandarin.io/api/v1/tokens/generate

Sandbox https://sandbox-payment-tokens.mandarin.io/api/v1/tokens/generate

Request

curl --location 'https://payment-tokens.mandarin.io/api/v1/tokens/generate'\
--header 'Mid: 395' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data-raw '{ 
"first_name": "Ivan", 
"last_name": "Ivanov", 
"middle_name": "Ivanovich", 
"birth_date": "1990-12-22", 
"citizenship": "RU", 
"registration_address": "Moscow, Petrovka st., 2, apt. 1", 
"living_address": "Moscow, Petrovka st., 2, apt. 1", 
"document": { 
"document_type": "Passport", 
"serial": "1234", 
"number": "123456", 
"issue_date": "2002-04-24T15:23:14.969Z", 
"birth_place": "Moscow", 
"issuer": "Fili Davydkovo District Department of Internal Affairs", 
"issue_code": "404-004", 
"expiration_date": null 
}, 
"inn": "1234567890", 
"snils": "140-120-150 35", 
"phones": [ 
{ 
"phone": "79004001234", 
"type": "Personal" 
} 
], 
"email": "ivanoff@mail.ru", 
"phone_check": true, 
"terms_agreement": true, 
"is_public_official_person": false, 
"presence_of_beneficiary": false, 
"beneficiary_information": false,
"exist_fatf_government_bills": false,
"affiliation_with_foreign_taxpayers": false
}'

Response in case of a successful request to create a virtual account (VAT) (200 OK)

{
"id": "06dca2f1-4e1c-44e7-8848-3e9e3adba875",
"status": "Processing",
"created_at": "2025-11-21T10:33:27.021823Z",
"processed_at": null,
"finished_at": null
}

# Checking VAT status

Request

GET https://payment-tokens.mandarin.io/api/v1/tokens/{payment_token_id}/status

Response if the status is successfully received (200 OK)

{
"id": "06dca2f1-4e1c-44e7-8848-3e9e3adba875",
"status": "Success",
"created_at": "2025-11-21T10:33:27.021823Z",
"processed_at": "2025-11-21T10:33:32.431478Z",
"finished_at": "2025-11-21T10:33:33.022295Z"
}

# Balance Receive ESP

Request

curl --location 'https://payment-tokens.mandarin.io/api/v1/tokens/{{payment_token_id}}/wallet/balance' \
--header 'Authorization: Bearer Token' \
--header 'Mid: 3019'

Response if balance is successfully received (200 OK)

{
"wallet_id": "fsdfrg3amt",
"balance": 1500075,
"currency": "RUB"
}

# Payment Transactions

All payment transactions are processed through a single endpoint.

POST https://secure.mandarinpay.com/api/transactions

The operation is asynchronous. The final status is transmitted in a callback notification.

# Internal Operations

Depositing funds to an ESP (business → wallet)

Request

curl --location 'https://secure.mandarinpay.com/api/transactions' \
--header 'Content-Type: application/json' \
--header 'Mid: 777' \
--header 'Authorization: Bearer Token' \
--data-raw '{
"payment": {
"action": "payout",
"orderId": "your_unique_order_id",
"price": "10.00",
"orderActualTill": "2026-02-20 12:34:56+00:00"
},
"target": {
"paymentToken": "payment_token_id"
}, 
"customerInfo": { 
"email": "user@example.com", 
"phone": "+79001234567" 
}, 
"customValues": [ 
{ "name": "first parameter to save and show", "value": "p1" }, 
{ "name": "second parameter to save and show", "value": "p2" } 
], 
"metadata": { 
"first_parameter_to_callback_and_not_to_show": "p1", 
"second_parameter_to_callback_and_not_to_show": "p2" 
}, 
"urls": { 
"callback": "http://...", 
"return": "http://..." 
}
}'

Response in case of successful transaction creation (200 OK)

{ 
"id": "43913ddc000c4d3990fddbd3980c1725",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=0eb51e74-e704-4c36-b5cb-8f0227621518",
"jsOperationId": "9874694yr87y73e7ey39ed80"
}

Response if the transaction is not created (400 Bad Request)

{
"error": "Invalid request"
}

Withdrawing funds from the ESP to a business account (wallet → business)

Request

curl --location 'https://secure.mandarinpay.com/api/transactions'\
--header 'Content-Type: application/json' \
--header 'Mid: 777' \
--header 'Authorization: Bearer Token' \
--data-raw '{ 
"payment": { 
"action": "pay", 
"orderId": "your_unique_orde1f313fr_id", 
"price": "10.00", 
"orderActualTill": "2026-02-20 12:34:56+00:00" 
}, 
"target": { 
"paymentToken": "payment_token_id" 
}, 
"customerInfo": { 
"email": "user@example.com", 
"phone": "+79001234567" 
}, 
"customValues": [ 
{ "name": "first parameter to save and show", "value": "p1" }, 
{ "name": "second parameter to save and show", "value": "p2" } 
], 
"metadata": { 
"first_parameter_to_callback_and_not_to_show": "p1", 
"second_parameter_to_callback_and_not_to_show": "p2" 
}, 
"urls": { 
"callback": "http://...", 
"return": "http://..." 
}
}'

Response in case of successful transaction creation (200 OK)

{
"id": "9b3c8a1f7e52d4096b0c2f8d3a5e17b4",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=f2a85b1c-3e9d-4871-a0b4-6c83d9f1e502",
"jsOperationId": "p3j8m267t1n9f4k5d0q8b3v6"
}

Response if the transaction is not created (400 Bad request)

{
"error": "Invalid request"
}

# External transactions (withdrawals from ESP)

To a card by card number (wallet → knownCardNumber)

Request

curl --location 'https://secure.mandarinpay.com/api/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data-raw '{ 
"payment": { 
"action": "payout", 
"orderId": "1756292752", 
"price": "100" 
}, 
"customerInfo": { 
"email": "noreply@example.ru", 
"phone": "+72244861047" 
}, 
"source": { 
"paymentToken": "63eed817-c56e-4aac-ad38-15113ed13744" 
}, 
"destination": {
"knownCardNumber": "2202202244861047"
}
}'

Response if the transaction was successfully created (200 OK)

{
"id": "e7a2f1b409d83c6a25e0b8d14c9f3a72",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=7d14c9a3-0b8e-42f6-95c1-e3a6f0d8b247",
"jsOperationId": "k5h8293xq4m7p1tg6r0n8s2v3"
}

Response if the transaction was not created (400 Bad request)

{
"error": "Invalid request"
}

To a bound card (wallet → bound card)

Request

curl --location 'https://secure.mandarinpay.com/api/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data-raw '{ 
"payment": { 
"action": "payout", 
"orderId": "1756292807", 
"price": "100" 
}, 
"customerInfo": { 
"email": "noreply@example.ru", 
"phone": "+72244861047" 
}, 
"source": { 
"paymentToken": "63eed817-c56e-4aac-ad38-15113ed13744"
},
"destination": {
"card": "63eed817-c56e-4aac-ad38-15113ed13722"
}
}'

Response if the transaction was successfully created (200 OK)

{
"id": "a7f4c2098e3b15d60f8a2e1b7c390d4f",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=1d8f3b9a-6e05-4c12-9a7d-0c4a8b5f3e12",
"jsOperationId": "j384m76t9k5f1d2w0n8q7x3r5"
}

Response if the transaction is not created (400 Bad request)

{ 
"error": "Invalid request"
}

On SBP (1-step)

curl --location 'https://secure.mandarinpay.com/api/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data-raw '{ 
"payment": { 
"action": "payout", 
"orderId": "1756292895", 
"price": "100" 
}, 
"customerInfo": { 
"phone": "+7926087626",
"email": "test@example.ru",
"firstName": "Ivan",
"middleName": "Valerievich",
"lastName": "Ivanov"
},
"source": {
"paymentToken": "63eed817-c56e-4aac-ad38-15113ed13744"
},
"destination": {
"sbp": {
"bankId": "100000000008",
"bankBic": "044525593"
}
}
}'

Response if the transaction is successfully created (200 OK)

{
"id": "43913ddc000c4d3990fddbd3980c1725",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=0eb51e74-e704-4c36-b5cb-8f0227621518",
"jsOperationId": "9874694yr87y73e7ey39ed80"
}

Response if the transaction is not created (400 Bad Request)

{
"error": "Invalid request"
}

On the FPS with confirmation (2-step)

Creating a payout

curl --location 'https://secure.mandarinpay.com/api/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data-raw '{ 
"payment": { 
"action": "payout", 
"orderId": "1756291493", 
"price": "100" 
}, 
"customerInfo": { 
"phone": "+7926087626", 
"email": "test@example.ru", 
"firstName": "Ivan", 
"middleName": "Valerievich", 
"lastName": "Ivanov" 
}, 
"source": { 
"paymentToken": "63eed817-c56e-4aac-ad38-15113ed13744" 
}, 
"destination": { 
"sbp": { 
"bankId": "100000000008", 
"bankBic": "044525593" 
}
}
}'

Response if the transaction was successfully created (200 OK)

{
"id": "e8f2a1b90c7d34f562a8e0b9d1c7f3a5",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=9d4c7a1f-3b28-4e65-8f09-2a5b6c0d7e31",
"jsOperationId": "z5q8n2r7k1m4f9t0p3w6b8x2v"
}

Response if the transaction was not created (400 Bad request)

{
"error": "Invalid request"
}

Receiving Full Name

POST https://secure.mandarinpay.com/api/sbp/{id}/status

Payment Confirmation

POST https://secure.mandarinpay.com/api/sbp/{id}/confirm

Payment Rejection

POST https://secure.mandarinpay.com/api/sbp/{id}/reject

# Transit Transactions

Payout to Card with Transit via ESP

Request

curl --location 'https://secure.mandarinpay.com/api/transactions'\
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data-raw '{ 
"payment": { 
"action": "payout", 
"orderId": "1756291886", 
"price": "100" 
}, 
"customerInfo": { 
"email": "noreply@example.ru", 
"phone": "+72244861047" 
}, 
"transit": { 
"paymentToken": "63eed817-c56e-4aac-ad38-15113ed13744" 
}, 
"target": { 
"card": "63eed817-c56e-4aac-ad38-15113ed13722"
}
}'

Response if the transaction was successfully created (200 OK)

{
"id": "8c3f9a2d1e7b0456f0c8d2e5a1b7f3d9",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=0eb51e74-e704-4c36-b5cb-8f0227621518",
"jsOperationId": "9874694yr87y73e7ey39ed80"
}

Response if the transaction was not created (400 Bad request)

{
"error": "Invalid request"
}

# Payment Transactions

Topping up an ESP with a linked card

Request

curl --location 'https://secure.mandarinpay.com/api/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data-raw '{
"payment": {
"action": "pay",
"orderId": "1756293713",
"price": "1"
},
"customerInfo": {
"email": "noreply@example.ru",
"phone": "+72244861047"
},
"source": {
"card": "63eed817-c56e-4aac-ad38-15113ed13722"
},
"destination": {
"paymentToken": "63eed817-c56e-4aac-ad38-15113ed13721"
}
}'

Response if the transaction is successfully created (200 OK)

{
"id": "43913ddc000c4d3990fddbd3980c1725",
"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=0eb51e74-e704-4c36-b5cb-8f0227621518",
"jsOperationId": "9874694yr87y73e7ey39ed80"
}

Response if the transaction is not created (400 Bad request)

{
"error": "Invalid request"
}

Important notes for merchants

All scenarios are implemented by a sequence of calls to existing API methods. There are no separate endpoints for "payout," "acceptance," "refinancing," or "funds distribution." Scenarios are generated by platform-side logic. The same API paths are used for sandbox and production. The differences lie in the service domains and the merchant_id and secret values. All operations are asynchronous and require callback notifications.