Merchant Balance
Мастер-счёт - предоплатный сервисный счёт вашей учётной записи. С него списываются платные вызовы платформы и выплаты вашим клиентам, на него приходят удержанные с клиентов надбавки. Это не кошелёк клиента и не касса: денег клиентов на мастер-счёте нет, движения по нему видите только вы.
- Платные вызовы - AML-проверки списываются отсюда. Пустой счёт означает
402на каждой проверке. - Выплаты клиентам - операция
payoutв Customer Wallets идёт за счёт мастер-счёта. - Ваш доход - надбавки, удержанные при выводах клиентов, и суммы
chargeзачисляются сюда.
Валюты счёта
На счёте по одной строке на валюту. Расчётная строка - USDT: именно с неё списываются услуги платформы, и она присутствует в ответе всегда, даже нулевая. USDT из любой сети падает в одну строку USDT - сеть фиксируется в записи леджера, но отдельной строки баланса не создаёт. Остальные монеты ведутся своим кодом: токен - {ASSET}_{NETWORK} (USDC_BSC), нативная монета - тикером (BTC).
Баланс
/api/v1/merchant/balance
Строки всех валют мастер-счёта
Responses
{
"data": [
{ "currency": "USDT", "available": "312.5000000000", "locked": "0.0000000000" },
{ "currency": "USDC_BSC", "available": "40.0000000000", "locked": "0.0000000000" }
]
}
{
"data": [
{ "currency": "USDT", "available": "0", "locked": "0" }
],
"sandbox": true
}
available - доступно к расходованию, locked - зарезервировано. В песочнице ответ синтетический и всегда содержит признак sandbox: true: реальных балансов тестовый ключ не касается.
Пополнение
Счёт пополняется двумя способами: переводом криптовалюты на выданный вам адрес и внутренним переводом со счёта финансирования владельца учётной записи.
Адрес пополнения
/api/v1/merchant/balance/deposit-address
Выдать адрес пополнения мастер-счёта в указанной сети
Body
chain
string
required
TRON, ETHEREUM, BSC, POLYGON, BASE. Неподдерживаемая сеть - 422 coin_not_allowed.| Name | Type | Required | Description |
|---|---|---|---|
chain
|
string
|
required |
Сеть пополнения. Допустимы только сети, в которых вам доступны стейблкоины: TRON, ETHEREUM, BSC, POLYGON, BASE. Неподдерживаемая сеть - 422 coin_not_allowed.
|
Responses
{
"data": {
"network": "TRON",
"address": "TJmVfKq3Zx8Yb1nQpR6cW4hS2dT7uL0aE9"
}
}
merchant.balance.credited.
Перевод со счёта финансирования
/api/v1/merchant/balance/topup-from-treasury
Пополнить мастер-счёт с личного счёта владельца
Заголовки
Idempotency-Key
string
required
duplicate: true и денег не двигает; тот же ключ с другой суммой или сетью - 409 conflict.| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key
|
string
|
required |
Обязателен. Повтор с тем же ключом и теми же параметрами возвращает результат первой проводки с duplicate: true и денег не двигает; тот же ключ с другой суммой или сетью - 409 conflict.
|
"+10", "10." отклоняются кодом 422.'],
['name' => 'chain', 'type' => 'string', 'default' => 'TRON', 'desc' => 'Сеть, из которой берутся средства владельца.'],
['name' => 'currency', 'type' => 'string', 'desc' => 'На пополнении игнорируется: мастер-счёт пополняется стейблом и зачисление всегда идёт в строку USDT.'],
]" />
Responses
{
"data": {
"direction": "topup",
"network": "TRON",
"currency": "USDT",
"amount": "100",
"balance": "412.5000000000",
"wallet_balance": "900.00000000",
"duplicate": false
}
}
{
"error": {
"code": "insufficient_funds",
"message": "Недостаточно средств для операции.",
"request_id": "req_7Kp2Rt9Wx4Yz1Qb6Nm3Vc8L"
}
}
Вывод с мастер-счёта
/api/v1/merchant/balance/transfer-to-treasury
Перевести средства мастер-счёта на счёт финансирования владельца
"+10", "10." отклоняются кодом 422.'],
['name' => 'currency', 'type' => 'string', 'default' => 'USDT', 'desc' => 'Валюта строки мастер-счёта: USDT, USDC_BSC, BTC и т.д. Выйти можно любой валютой, которая есть на счёте.'],
['name' => 'chain', 'type' => 'string', 'default' => 'TRON', 'desc' => 'Нужна только для агрегированной строки USDT - она одна на все сети, и сеть выхода надо указать. Составной код (USDC_BSC) и нативные монеты несут сеть в себе.'],
]" />
Заголовки
Idempotency-Key
string
required
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key
|
string
|
required | Обязателен, правила те же, что у пополнения. |
Responses
{
"data": {
"direction": "transfer_out",
"network": "TRON",
"currency": "USDT",
"amount": "50",
"balance": "362.5000000000",
"wallet_balance": "950.00000000",
"duplicate": false
}
}
{
"error": {
"code": "service_balance_insufficient",
"message": "Недостаточно средств на сервисном счёте. Пополните мастер-счёт.",
"request_id": "req_M9n8B7v6C5x4Z3a2S1d0F1gH",
"currency": "USDT",
"required": "50",
"available": "12.4000000000"
}
}
Поля ответа обоих переводов
direction
enum
optional
topup - деньги пришли на мастер-счёт, transfer_out - ушли с него.network
string
optional
currency
string
optional
amount
string
optional
balance
string
optional
wallet_balance
string
optional
duplicate
bool
optional
true - это повтор по уже использованному ключу, движения денег не было.| Name | Type | Required | Description |
|---|---|---|---|
direction
|
enum
|
optional |
topup - деньги пришли на мастер-счёт, transfer_out - ушли с него.
|
network
|
string
|
optional | Сеть, в которой прошёл внутренний перевод. |
currency
|
string
|
optional | Валюта строки мастер-счёта. |
amount
|
string
|
optional | Реально проведённая сумма. При повторе ключа возвращается сумма первой проводки, а не переданная в повторе. |
balance
|
string
|
optional | Остаток мастер-счёта после операции. |
wallet_balance
|
string
|
optional | Остаток счёта финансирования владельца после операции. |
duplicate
|
bool
|
optional |
true - это повтор по уже использованному ключу, движения денег не было.
|
sandbox: true и реальных балансов не касаются: баланс всегда нулевой, леджер пуст. Форма ответа внутренних переводов при этом совпадает с боевой - приходят и wallet_balance, и duplicate, только значения синтетические (оба баланса "0", duplicate: false), поэтому строгий разбор ответа можно отлаживать прямо в песочнице. Тариф (service-pricing) в обоих окружениях отдаёт одни и те же действующие условия.
Леджер
/api/v1/merchant/balance/transactions
Движения по мастер-счёту (курсорная выборка)
starting_after из поля meta.next_cursor, пока meta.has_more равно true.Query parameters
type
string
optional
422 invalid_request.currency
string
optional
USDT.from
date
optional
to
date
optional
per_page
integer
optional
25starting_after
string
optional
id последней полученной записи. Продолжает выборку строго после неё.| Name | Type | Required | Description |
|---|---|---|---|
type
|
string
|
optional |
Фильтр по типу операции (см. таблицу ниже). Неизвестное значение - 422 invalid_request.
|
currency
|
string
|
optional |
Фильтр по валюте строки, например USDT.
|
from
|
date
|
optional | Начало периода включительно (с начала суток). |
to
|
date
|
optional | Конец периода включительно (до конца суток). |
per_page
|
integer
|
optional |
Размер страницы, 1..100.
Default:
25 |
starting_after
|
string
|
optional |
Курсор: id последней полученной записи. Продолжает выборку строго после неё.
|
Типы операций (поле type)
topup_deposit
credit
optional
topup_internal
credit
optional
charge
credit
optional
withdraw_markup
credit
optional
aml_fee_refund
credit
optional
aml_fee
debit
optional
payout
debit
optional
transfer_out
debit
optional
adjustment
credit / debit
optional
description указано основание.| Name | Type | Required | Description |
|---|---|---|---|
topup_deposit
|
credit
|
optional | Пополнение переводом на адрес мастер-счёта. |
topup_internal
|
credit
|
optional | Пополнение со счёта финансирования владельца. |
charge
|
credit
|
optional | Списание с клиента в вашу пользу. |
withdraw_markup
|
credit
|
optional | Ваша надбавка, удержанная при выводе клиента. Фиксированная сумма по монете, в единицах этой монеты. |
aml_fee_refund
|
credit
|
optional | Возврат платы за проверку, которая не дала результата. |
aml_fee
|
debit
|
optional | Плата за AML-проверку. |
payout
|
debit
|
optional | Выплата клиенту. |
transfer_out
|
debit
|
optional | Перевод на счёт финансирования владельца. |
adjustment
|
credit / debit
|
optional |
Корректировка, проведённая оператором платформы. В description указано основание.
|
Responses
{
"data": [
{
"id": "0b9a7c31-58d2-4e6f-9a11-c4d8e2f60b73",
"currency": "USDT",
"type": "aml_fee",
"direction": "debit",
"amount": "0.2000000000",
"balance_after": "312.3000000000",
"description": "AML-проверка адреса",
"created_at": "2026-08-17T13:02:44+00:00"
},
{
"id": "f41c8de0-2b57-4a90-8c63-71e5a9d04b28",
"currency": "USDT",
"type": "charge",
"direction": "credit",
"amount": "12.5000000000",
"balance_after": "312.5000000000",
"description": "Списание с клиента 5f8d7a3c-1234-4567-89ab-cdef01234567 - Абонентская плата за август",
"created_at": "2026-08-17T12:40:55+00:00"
}
],
"meta": {
"per_page": 25,
"returned": 2,
"has_more": false,
"next_cursor": null
}
}
Поля записи
id
string
optional
currency
string
optional
type
enum
optional
direction
enum
optional
credit - зачисление, debit - списание. Знак несёт именно это поле, amount всегда положительна.amount
string
optional
balance_after
string
optional
description
string|null
optional
charge и payout включает переданный вами reason.created_at
datetime
optional
| Name | Type | Required | Description |
|---|---|---|---|
id
|
string
|
optional | Идентификатор записи (UUID). Используется как курсор. |
currency
|
string
|
optional | Валюта строки счёта. |
type
|
enum
|
optional | Смысл операции (таблица выше). |
direction
|
enum
|
optional |
credit - зачисление, debit - списание. Знак несёт именно это поле, amount всегда положительна.
|
amount
|
string
|
optional | Сумма операции. |
balance_after
|
string
|
optional | Остаток строки счёта сразу после операции. |
description
|
string|null
|
optional |
Человекочитаемое описание. Для charge и payout включает переданный вами reason.
|
created_at
|
datetime
|
optional | Время операции (ISO 8601). |
Тариф и лимиты
/api/v1/merchant/service-pricing
Действующие цены, комиссии и лимиты вашей учётной записи
Responses
{
"data": {
"currency": "USDT",
"aml": {
"check_price": "0.2",
"billing_enabled": true,
"exempt": false,
"charged": true
},
"withdraw": {
"fees": [
{ "asset": "USDT", "network": "TRON", "fee": "5", "min_withdraw": "10.000000000000000000", "min_deposit": "1.000000000000000000", "native": false },
{ "asset": "USDT", "network": "BSC", "fee": "1", "min_withdraw": "10.000000000000000000", "min_deposit": "1.000000000000000000", "native": false },
{ "asset": "USDT", "network": "ETHEREUM", "fee": "10", "min_withdraw": "20.000000000000000000", "min_deposit": "10.000000000000000000", "native": false },
{ "asset": "BTC", "network": "BITCOIN", "fee": "0", "min_withdraw": "0.000300000000000000", "min_deposit": "0.000100000000000000", "native": true }
],
"limits": {
"max_per_tx": "10000",
"daily_per_customer": "30000"
},
"markup": [
{ "coin_id": 1, "label": "USDT / TRON", "asset": "USDT", "network": "TRON", "native": false, "fee": "5", "markup": "1.0000000000", "max": "10.0000000000", "editable": true },
{ "coin_id": 2, "label": "USDT / BSC", "asset": "USDT", "network": "BSC", "native": false, "fee": "1", "markup": "0.5000000000", "max": "10.0000000000", "editable": true },
{ "coin_id": 3, "label": "USDT / ETHEREUM", "asset": "USDT", "network": "ETHEREUM", "native": false, "fee": "10", "markup": "0.0000000000", "max": "10.0000000000", "editable": true },
{ "coin_id": 4, "label": "BTC / BITCOIN", "asset": "BTC", "network": "BITCOIN", "native": true, "fee": "0", "markup": "0.0000000000", "max": "0.0000000000", "editable": false }
]
},
"balance": {
"low_threshold": "5"
}
}
}
Комиссии, лимиты и минимумы выше - пример ответа, а не ваш тариф: действующие значения учётной записи отдаёт этот же вызов, его и опрашивайте перед показом условий клиенту.
max); у монет с нулевой границей надбавка недоступна - editable: false. На пополнение надбавки нет: зачисление бесплатно. AML-проверки - ваш расход, а не товар: перепродавать их с надбавкой нельзя.
Поля витрины
currency
string
optional
aml.check_price
string
optional
aml.billing_enabled
bool
optional
aml.exempt
bool
optional
aml.charged
bool
optional
withdraw.fees[]
array
optional
fee - фиксированная комиссия платформы за вывод клиента, min_withdraw и min_deposit - минимальные суммы, native - нативная ли монета сети. Минимумы меняются платформой - не зашивайте их в код, читайте отсюда.withdraw.limits.max_per_tx
string
optional
withdraw.limits.daily_per_customer
string
optional
withdraw.markup[]
array
optional
withdraw.markup[].coin_id
integer
optional
withdraw.markup[].label
string
optional
USDT / TRON.withdraw.markup[].asset
string
optional
withdraw.markup[].network
string
optional
withdraw.markup[].native
bool
optional
withdraw.markup[].fee
string
optional
withdraw.fees[].withdraw.markup[].markup
string
optional
fee_merchant расчёта вывода.withdraw.markup[].max
string
optional
withdraw.markup[].editable
bool
optional
false, если граница равна нулю: по такой монете надбавка недоступна, пока платформа не разрешит её отдельно.balance.low_threshold
string
optional
USDT, ниже которого приходит вебхук merchant.balance.low.| Name | Type | Required | Description |
|---|---|---|---|
currency
|
string
|
optional | Расчётная валюта услуг платформы. |
aml.check_price
|
string
|
optional | Цена одной платной AML-проверки. |
aml.billing_enabled
|
bool
|
optional | Тарификация проверок включена на платформе. |
aml.exempt
|
bool
|
optional | Ваша учётная запись освобождена от оплаты проверок. |
aml.charged
|
bool
|
optional | Итог: будет ли списана плата за ваш следующий боевой вызов проверки. |
withdraw.fees[]
|
array
|
optional |
Строка на каждую доступную монету: fee - фиксированная комиссия платформы за вывод клиента, min_withdraw и min_deposit - минимальные суммы, native - нативная ли монета сети. Минимумы меняются платформой - не зашивайте их в код, читайте отсюда.
|
withdraw.limits.max_per_tx
|
string
|
optional | Лимит на одну операцию вывода, в эквиваленте USDT. |
withdraw.limits.daily_per_customer
|
string
|
optional | Суточный лимит вывода на одного клиента, в эквиваленте USDT. Окно скользящее - последние 24 часа, а не календарные сутки. |
withdraw.markup[]
|
array
|
optional | Ваша надбавка на выводы клиентов - строка на каждую доступную монету. Это фиксированная сумма в единицах монеты, а не процент. |
withdraw.markup[].coin_id
|
integer
|
optional | Внутренний идентификатор монеты в справочнике платформы. |
withdraw.markup[].label
|
string
|
optional |
Человекочитаемое имя монеты, например USDT / TRON.
|
withdraw.markup[].asset
|
string
|
optional | Тикер монеты. |
withdraw.markup[].network
|
string
|
optional | Сеть. |
withdraw.markup[].native
|
bool
|
optional | Нативная ли монета сети. |
withdraw.markup[].fee
|
string
|
optional |
Комиссия платформы за вывод в этой сети - та же, что в withdraw.fees[].
|
withdraw.markup[].markup
|
string
|
optional |
Ваша действующая надбавка по этой монете, в единицах монеты. Именно она попадает в fee_merchant расчёта вывода.
|
withdraw.markup[].max
|
string
|
optional | Верхняя граница надбавки по этой монете. Устанавливает платформа; сохранённое значение выше границы автоматически урезается до неё - и при сохранении, и при каждом расчёте. |
withdraw.markup[].editable
|
bool
|
optional |
false, если граница равна нулю: по такой монете надбавка недоступна, пока платформа не разрешит её отдельно.
|
balance.low_threshold
|
string
|
optional |
Порог остатка USDT, ниже которого приходит вебхук merchant.balance.low.
|
Предупреждение о низком остатке
Как только доступный остаток строки USDT опускается ниже порога balance.low_threshold, на ваш подписанный эндпоинт уходит вебхук merchant.balance.low с полями currency, balance и threshold. Предупреждение отправляется не чаще одного раза в сутки, поэтому оно не заменяет мониторинг: опрашивайте GET /api/v1/merchant/balance перед пиковой нагрузкой. На остатке ровно в порог вебхука нет.
Вебхук merchant.balance.credited приходит при зачислении перевода на адрес мастер-счёта - используйте его, чтобы не опрашивать баланс в ожидании пополнения. Оба события отправляются только в боевом окружении. Подробности - Webhooks.
Права
Чтение баланса, леджера и тарифа
любой ключ
optional
Выдача адреса пополнения
владелец, администратор
optional
403 forbidden.Перевод на счёт финансирования
владелец, администратор
optional
Пополнение со счёта финансирования
только владелец
optional
| Name | Type | Required | Description |
|---|---|---|---|
Чтение баланса, леджера и тарифа
|
любой ключ
|
optional | Доступно всем ключам вашей учётной записи. |
Выдача адреса пополнения
|
владелец, администратор
|
optional |
Иначе 403 forbidden.
|
Перевод на счёт финансирования
|
владелец, администратор
|
optional | Деньги уходят владельцу учётной записи. |
Пополнение со счёта финансирования
|
только владелец
|
optional | Списываются личные средства владельца, поэтому распоряжаться ими может только он сам. |
Лимиты частоты
Чтение (баланс, леджер, тариф) - 120 запросов в минуту, своей корзиной. Выдача адреса пополнения (30 в минуту) и внутренние переводы мастер-счёта - пополнение и вывод (20 в минуту) - делят одну общую корзину записи: их лимиты считаются от единого счётчика, а не независимо друг от друга. Частый опрос баланса переводам при этом не мешает - читающая корзина отдельная.
Коды ошибок раздела
forbidden
403
optional
idempotency_key_required
400
optional
Idempotency-Key.invalid_request
422
optional
type в фильтре леджера или иная ошибка валидации.coin_not_allowed
422
optional
conflict
409
optional
Idempotency-Key уже использован с другими параметрами, либо счёт финансирования владельца недоступен.insufficient_funds
402
optional
service_balance_insufficient
402
optional
currency, required, available.service_unavailable
503
optional
| Name | Type | Required | Description |
|---|---|---|---|
forbidden
|
403
|
optional | У ключа нет нужной роли, либо учётная запись не связана с мерчантом. |
idempotency_key_required
|
400
|
optional |
Во внутреннем переводе не передан заголовок Idempotency-Key.
|
invalid_request
|
422
|
optional |
Некорректная сумма, неизвестный type в фильтре леджера или иная ошибка валидации.
|
coin_not_allowed
|
422
|
optional | Сеть или валюта недоступны вашей учётной записи. |
conflict
|
409
|
optional |
Idempotency-Key уже использован с другими параметрами, либо счёт финансирования владельца недоступен.
|
insufficient_funds
|
402
|
optional | На счёте финансирования владельца не хватает средств для пополнения. |
service_balance_insufficient
|
402
|
optional |
Не хватает средств на самом мастер-счёте. Ответ дополнен полями currency, required, available.
|
service_unavailable
|
503
|
optional | Мастер-счёт временно недоступен или адрес пополнения не удалось выдать - повторите позже. |
Полный реестр и формат конверта - Error Codes.
Примеры кода
KEY="sk_live_..."
B="https://fin-os.io/api/v1"
# 1. Текущий баланс
curl -X GET $B/merchant/balance -H "Authorization: Bearer $KEY"
# 2. Адрес пополнения в TRON
curl -X POST $B/merchant/balance/deposit-address \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"chain": "TRON"}'
# 3. Пополнить со счёта финансирования владельца
curl -X POST $B/merchant/balance/topup-from-treasury \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: topup-2026-08-17-01" \
-d '{"amount": "100", "chain": "TRON"}'
# 4. Расходы на проверки за август
curl -G $B/merchant/balance/transactions \
-H "Authorization: Bearer $KEY" \
--data-urlencode "type=aml_fee" \
--data-urlencode "from=2026-08-01" \
--data-urlencode "to=2026-08-31" \
--data-urlencode "per_page=100"
# 5. Действующий тариф
curl -X GET $B/merchant/service-pricing -H "Authorization: Bearer $KEY"
const B = 'https://fin-os.io/api/v1';
const KEY = process.env.FINOS_SECRET_KEY;
const H = { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' };
// Остаток расчётной строки USDT
async function serviceBalance() {
const { data } = await (await fetch(`${B}/merchant/balance`, { headers: H })).json();
return data.find(r => r.currency === 'USDT')?.available ?? '0';
}
// Полный леджер за период: идём по курсору, пока has_more
async function ledger(params = {}) {
const rows = [];
let cursor = null;
do {
const q = new URLSearchParams({ per_page: '100', ...params });
if (cursor) q.set('starting_after', cursor);
const body = await (await fetch(`${B}/merchant/balance/transactions?${q}`, { headers: H })).json();
rows.push(...body.data);
cursor = body.meta.has_more ? body.meta.next_cursor : null;
} while (cursor);
return rows;
}
// Расход на проверки за месяц
const fees = await ledger({ type: 'aml_fee', from: '2026-08-01', to: '2026-08-31' });
console.log(fees.reduce((s, r) => s + Number(r.amount), 0));
use Illuminate\Support\Facades\Http;
$api = Http::withToken(config('services.finos.secret_key'))
->acceptJson()
->baseUrl('https://fin-os.io/api/v1');
// Хватит ли на пачку проверок
$pricing = $api->get('/merchant/service-pricing')->json('data');
$balance = collect($api->get('/merchant/balance')->json('data'))
->firstWhere('currency', 'USDT')['available'] ?? '0';
if (bccomp($balance, bcmul($pricing['aml']['check_price'], (string) $plannedChecks, 10), 10) < 0) {
// Пополняем со счёта финансирования: ключ идемпотентности - ваш идентификатор операции
$api->withHeaders(['Idempotency-Key' => "topup-{$invoiceId}"])
->post('/merchant/balance/topup-from-treasury', ['amount' => 100, 'chain' => 'TRON']);
}
// Леджер за период с курсорной пагинацией
$rows = [];
$cursor = null;
do {
$page = $api->get('/merchant/balance/transactions', array_filter([
'type' => 'aml_fee',
'from' => '2026-08-01',
'to' => '2026-08-31',
'per_page' => 100,
'starting_after' => $cursor,
]))->json();
$rows = array_merge($rows, $page['data']);
$cursor = $page['meta']['has_more'] ? $page['meta']['next_cursor'] : null;
} while ($cursor);
import os, requests
from decimal import Decimal
B = 'https://fin-os.io/api/v1'
KEY = os.environ['FINOS_SECRET_KEY']
H = {'Authorization': f'Bearer {KEY}'}
def service_balance():
rows = requests.get(f'{B}/merchant/balance', headers=H).json()['data']
return next((Decimal(r['available']) for r in rows if r['currency'] == 'USDT'), Decimal(0))
def ledger(**params):
params.setdefault('per_page', 100)
cursor = None
while True:
if cursor:
params['starting_after'] = cursor
body = requests.get(f'{B}/merchant/balance/transactions',
headers=H, params=params).json()
yield from body['data']
if not body['meta']['has_more']:
return
cursor = body['meta']['next_cursor']
# Расход на проверки за август
spent = sum(Decimal(r['amount']) for r in ledger(type='aml_fee',
**{'from': '2026-08-01', 'to': '2026-08-31'}))
print(service_balance(), spent)