Finance OS / API

Customer Wallets

Крипто-кошельки ваших клиентов: вы выдаёте клиенту адрес пополнения в нужной сети, платформа принимает депозит и ведёт остаток, а вы распоряжаетесь им через API - выводите на внешний адрес, списываете в свою пользу и выплачиваете обратно. Кастоди, подтверждения сети и комплаенс остаются на нашей стороне; вы работаете только с этим набором эндпоинтов.

Что нужно до начала
Клиент уже создан (Customers), ключ имеет доступ к сервису кошельков, а мастер-счёт пополнен - с него оплачиваются платные вызовы платформы и с него же уходят выплаты клиентам (Merchant Balance).

Модель данных

У клиента один кошелёк на монету и по одному адресу на сеть. Монета описывается парой asset + network (например USDT в сети TRON). В балансах и в мастер-счёте та же монета фигурирует как currency: для токенов это составной код {ASSET}_{NETWORK} (USDT_TRON), для нативных монет - просто BTC, LTC.

Имена сетей

network string optional
Верхний регистр: TRON, ETHEREUM, BSC, POLYGON, BASE, BITCOIN, LITECOIN. Точный список доступных вам монет и сетей - в GET /api/v1/merchant/service-pricing.
asset string optional
Тикер монеты в верхнем регистре: USDT, USDC, BTC, LTC.
currency string optional
Код строки баланса: USDT_TRON, USDC_BSC, BTC. Токен всегда несёт сеть в коде - один и тот же тикер в разных сетях это разные строки баланса.
Суммы - строки
Все денежные поля в ответах приходят строками: "150.000000000000000000", "5", "0". Число знаков после точки у разных полей разное и на смысл не влияет - разбирайте значение как decimal и сравнивайте по значению, а не по тексту. Числа с плавающей точкой в денежной арифметике использовать нельзя. В запросах сумма принимается только плоской десятичной строкой: без знака и экспоненты, до 18 знаков после точки. Значения вида "1e3", "+10", "10." отклоняются кодом 422 invalid_request, а не приводятся молча к числу.

Адреса пополнения

POST /api/v1/customers/{uuid}/wallet/addresses
Bearer Token

Выдать адрес клиенту в указанной сети

Идемпотентно: повторный вызов с той же сетью возвращает тот же адрес, новый не выпускается. Адрес закреплён за клиентом навсегда.

Body

chain string required
Сеть: TRON, ETHEREUM, BSC, POLYGON, BASE, BITCOIN, LITECOIN. Регистр не важен, приводится к верхнему.

Responses

{
  "data": {
    "network": "TRON",
    "address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
    "sandbox": null
  }
}
{
  "error": {
    "code": "wallets_disabled",
    "message": "Крипто-кошельки клиентов сейчас недоступны.",
    "request_id": "req_Zx8Cv6Bn4Mk2Lj0Hg9Fd7Sa5"
  }
}
{
  "error": {
    "code": "coin_not_allowed",
    "message": "Эта монета недоступна для вашей учётной записи.",
    "request_id": "req_7Kp2Rt9Wx4Yz1Qb6Nm3Vc8L"
  }
}

Поле sandbox равно true только у синтетических адресов песочницы; в боевом окружении оно null.

GET /api/v1/customers/{uuid}/wallet/addresses
Bearer Token

Все выданные адреса клиента

Массив { network, address, sandbox }, отсортированный по сети. Параметров нет.

Депозиты

Депозит зачисляется сразу после появления транзакции в сети, не дожидаясь подтверждений: баланс клиента растёт мгновенно, а строка журнала при этом остаётся в статусе pending и переходит в confirmed, когда сеть наберёт нужное число подтверждений. По каждому событию уходит вебхук: customer.deposit.detected в момент зачисления и customer.deposit.confirmed после подтверждения.

Правила приёма

Рекомендованный минимум optional
Справочное значение min_deposit из GET /api/v1/merchant/service-pricing. Поступления меньше минимума тоже зачисляются, но экономического смысла в них мало: комиссия последующего вывода фиксированная и от суммы не зависит - показывайте минимум клиенту в интерфейсе пополнения.
Зачисление бесплатно optional
За пополнение не берут ничего ни платформа, ни вы: клиенту зачисляется ровно та сумма, которая пришла на адрес. Надбавки на пополнение в контуре нет - зарабатываете вы на выводе.
Только свои монеты optional
Зачисляются токены из поддерживаемого списка и нативные монеты UTXO-сетей (BTC, LTC). Нативная монета сети TRON и EVM-сетей на адрес клиента не зачисляется - это служебные средства сети.
Один адрес - одна сеть optional
Отправка в другой сети на тот же адрес не будет распознана. Адрес всегда используйте вместе с network, в которой он выдан.
Комплаенс-проверка optional
Каждое поступление проходит автоматический скрининг отправителя. Пока вердикта нет, поле aml_status равно pending; вывод по такому клиенту временно отклоняется кодом aml_screening_in_progress.
Заморозка optional
При высоком риске сумма поступления переводится в locked, приходит вебхук customer.deposit.frozen, решение принимает комплаенс-офицер платформы. Снятие заморозки - вебхук customer.deposit.released.

Балансы клиента

GET /api/v1/customers/{uuid}/wallet
Bearer Token

Крипто-балансы по всем доступным монетам

Возвращает строку на каждую доступную вам монету, включая нулевые - состав списка не зависит от того, приходили ли по монете деньги.

Responses

{
  "data": [
    {
      "asset": "USDT",
      "symbol": "USDT",
      "network": "TRON",
      "currency": "USDT_TRON",
      "available": "150.0000000000",
      "locked": "0.0000000000"
    },
    {
      "asset": "USDT",
      "symbol": "USDT",
      "network": "BSC",
      "currency": "USDT_BSC",
      "available": "0",
      "locked": "0"
    }
  ],
  "meta": {
    "customer_status": "active"
  }
}
available и locked
available - остаток, которым можно распоряжаться прямо сейчас. locked - сумма, временно недоступная: замороженное комплаенсом поступление либо средства под уже принятой заявкой на вывод. Общий остаток клиента - сумма обоих полей.

Журнал движений

GET /api/v1/customers/{uuid}/wallet/transactions
Bearer Token

Крипто-движения клиента (постраничная выборка)

Query parameters

coin string optional
Фильтр по тикеру монеты, например USDT.
direction enum optional
in - поступления и выплаты вам в пользу клиента; out - выводы и списания с клиента.
status enum optional
pending, confirmed, failed.
per_page integer optional
Размер страницы, 1..100.
Default: 25
page integer optional
Номер страницы.
Default: 1

Объект транзакции

Поля

id string optional
Идентификатор строки журнала (UUID). Он же используется как курсор в единой истории клиента.
network string optional
Сеть операции.
asset string optional
Тикер монеты.
direction enum optional
in или out - с точки зрения клиента.
amount string optional
Сумма операции без комиссий.
address string|null optional
Адрес зачисления (у поступления) или адрес получателя (у вывода). У внутренних расчётов - служебное значение вида internal:merchant:….
counterparty string|null optional
Адрес отправителя у поступления, адрес назначения у вывода либо человекочитаемая подпись у внутренних расчётов.
tx_hash string|null optional
Хеш транзакции в сети. null, если операция внутренняя или отправка ещё не состоялась.
status enum optional
Стабильный словарь: pending, confirmed, failed - и ничего больше. Ветвите логику по нему.
state enum optional
Только у заявок на вывод: стадия обработки (см. ниже). У поступлений и внутренних расчётов поля нет вовсе.
confirmations integer optional
Число подтверждений сети на момент ответа.
aml_status enum optional
pending - проверка идёт; clear - вопросов нет; flagged - есть риск (обычно вместе с заморозкой); skipped - проверка неприменима (внутренние расчёты).
frozen bool optional
Сумма по этой строке сейчас заморожена.
fee.platform string optional
Комиссия платформы, удержанная сверх суммы. У поступлений - 0.
fee.merchant string optional
Ваша надбавка, удержанная сверх суммы, - она зачисляется на ваш мастер-счёт. У поступлений - 0: зачисление бесплатно.
confirmed_at datetime|null optional
Момент подтверждения (ISO 8601) или null.
created_at datetime optional
Момент создания строки (ISO 8601).

Responses

{
  "data": [
    {
      "id": "7c1f2b90-4a3e-4a1f-9c62-8b0f4a7d2e11",
      "network": "TRON",
      "asset": "USDT",
      "direction": "in",
      "amount": "150.000000000000000000",
      "address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
      "counterparty": "TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb",
      "tx_hash": "3f0c1b7a94e2d5c86a1f0b2d4e7c9a51b3d6f8e0a2c4b6d8f0e1a3c5b7d9f2e4",
      "status": "confirmed",
      "confirmations": 21,
      "aml_status": "clear",
      "frozen": false,
      "fee": { "platform": "0.000000000000000000", "merchant": "0.000000000000000000" },
      "confirmed_at": "2026-08-17T12:11:40+00:00",
      "created_at": "2026-08-17T12:04:11+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 25,
    "total": 1,
    "last_page": 1
  }
}
status и state - разные поля
status отвечает на вопрос «деньги дошли?» и никогда не выходит за три значения. state появляется только у заявок на вывод и отвечает на вопрос «на каком шаге заявка сейчас». Не подменяйте одно другим: интеграция, читающая стадию из status, увидит только pending.

Принудительная сверка

POST /api/v1/customers/{uuid}/wallet/sync
Bearer Token

Перечитать поступления по адресам клиента

Аварийный инструмент на случай «клиент отправил, а депозита не видно». Обходит адреса клиента, находит не зачисленные поступления и проводит их обычным порядком. Жёсткий лимит: 6 запросов в минуту.

Body

chain string optional
Ограничить сверку одной сетью. Без параметра проверяются все адреса клиента.

Responses

{
  "data": {
    "network": "TRON",
    "new_deposits": 1,
    "synced_at": "2026-08-17T12:20:03+00:00"
  }
}

new_deposits - сколько поступлений зачислено именно этим вызовом. Ноль означает, что новых денег на адресах нет; это нормальный ответ, а не ошибка. Сверка покрывает TRON и UTXO-сети; в EVM-сетях поступления приходят по подписке и в отдельной сверке не нуждаются.

Вывод на внешний адрес

Вывод - двухшаговый сценарий: сначала предпросмотр quote (сколько спишется, что пройдёт по лимитам), затем создание заявки. Заявка обрабатывается асинхронно: ответ приходит сразу, деньги уходят в сеть фоном, а вы следите за стадией по вебхукам либо опросом статуса.

Предпросмотр

GET /api/v1/customers/{uuid}/wallet/withdraw/quote
Bearer Token

Расчёт вывода без движения денег

Денег не двигает, заявку не создаёт. Можно вызывать из формы на каждое изменение суммы.
, "+10", "10." отклоняются кодом 422.'], ]" />

Responses

{
  "data": {
    "asset": "USDT",
    "network": "TRON",
    "amount": "100",
    "fee_platform": "5",
    "fee_merchant": "1.0000000000",
    "total_debit": "106.0000000000",
    "receives": "100",
    "balance": "150.0000000000",
    "daily_limit": "30000",
    "daily_used": "0.0000000000",
    "daily_left": "30000.0000000000",
    "max_per_tx": "10000",
    "min_withdraw": "10.000000000000000000",
    "network_fee_from_amount": false,
    "aml_precheck": false,
    "allowed": true,
    "reason": null
  }
}
{
  "data": {
    "asset": "USDT",
    "network": "TRON",
    "amount": "50000",
    "fee_platform": "5",
    "fee_merchant": "1.0000000000",
    "total_debit": "50006.0000000000",
    "receives": "50000",
    "balance": "150.0000000000",
    "daily_limit": "30000",
    "daily_used": "0.0000000000",
    "daily_left": "30000.0000000000",
    "max_per_tx": "10000",
    "min_withdraw": "10.000000000000000000",
    "network_fee_from_amount": false,
    "aml_precheck": false,
    "allowed": false,
    "reason": {
      "code": "withdraw_limit_exceeded",
      "gate": "max_per_tx",
      "error": "Сумма больше лимита на одну операцию (10000 USDT)."
    }
  }
}

Комиссии, лимиты и минимумы в примерах - иллюстративные: действующие значения вашей учётной записи всегда берите из витрины GET /api/v1/merchant/service-pricing либо из самого расчёта.

Надбавка - фиксированная сумма, а не процент
fee_merchant - ваша надбавка на вывод: фиксированная сумма в единицах выводимой монеты, заданная отдельно для каждой пары монета+сеть. Работа платформы и сети на выводе 10 и 10 000 USDT одинакова, поэтому процент давал бы стократную разницу в цене за одну и ту же операцию. Верхнюю границу надбавки по каждой монете устанавливает платформа; по монетам, где она равна нулю, надбавка недоступна. Действующие значения - в витрине GET /api/v1/merchant/service-pricing, блок withdraw.markup. На пополнение надбавки нет вовсе: зачисление бесплатно, клиенту приходит ровно то, что пришло на адрес.

Поля расчёта

amount string optional
Сумма, которую вы запросили.
fee_platform string optional
Фиксированная комиссия платформы за операцию в этой сети. Сетевые издержки покрывает платформа - отдельной платы за них нет.
fee_merchant string optional
Ваша надбавка - фиксированная сумма, заданная вами для этой пары монета+сеть, в единицах выводимой монеты. От суммы вывода не зависит. Удерживается с клиента и зачисляется на ваш мастер-счёт.
total_debit string optional
Сколько всего спишется с клиента: amount + fee_platform + fee_merchant.
receives string optional
Сколько получит адрес назначения.
balance string optional
Доступный остаток клиента по этой монете на момент расчёта.
daily_limit string optional
Суточный лимит вывода на одного клиента, в эквиваленте USDT. Окно скользящее: считаются операции за последние 24 часа, полночь лимит не обнуляет.
daily_used string optional
Сколько клиент вывел за последние 24 часа, в эквиваленте USDT.
daily_left string optional
Остаток суточного лимита. Освобождается по мере того, как операции выходят за окно в 24 часа.
max_per_tx string optional
Лимит на одну операцию, в эквиваленте USDT.
min_withdraw string optional
Минимальная сумма вывода для этой монеты.
network_fee_from_amount bool optional
Для UTXO-сетей (BITCOIN, LITECOIN) - true: сеть удержит свою плату из отправляемой суммы, и получатель получит немного меньше amount. Для токенов - false.
aml_precheck bool optional
Всегда false: предпросмотр не выполняет комплаенс-проверку адреса назначения. Она делается в момент создания заявки.
allowed bool optional
Пройдут ли проверки при создании заявки прямо сейчас.
reason object|null optional
При allowed: false - причина отказа: code (тот же, что вернёт боевой вызов), gate (какая проверка не пройдена) и error (текст для человека).

Создание заявки

POST /api/v1/customers/{uuid}/wallet/withdraw
Bearer Token

Вывести средства клиента на внешний адрес

Двигает реальные деньги. Заголовок Idempotency-Key обязателен. Лимит - 6 запросов в минуту.

Заголовки

Idempotency-Key string required
Ваш уникальный ключ операции. Повтор с тем же ключом и теми же параметрами вернёт ту же заявку с кодом 200 и полем duplicate: true, второй раз деньги не спишутся. Тот же ключ с другими параметрами - 409 conflict и ни копейки движения.
, "+10", "10." отклоняются кодом 422.'], ]" />

Responses

{
  "data": {
    "id": "b3a91d55-7c02-4c6e-91ad-5f3d2c4b8e70",
    "network": "TRON",
    "asset": "USDT",
    "direction": "out",
    "amount": "100.000000000000000000",
    "address": "TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb",
    "counterparty": "TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb",
    "tx_hash": null,
    "status": "pending",
    "state": "processing",
    "confirmations": 0,
    "aml_status": "skipped",
    "frozen": false,
    "fee": { "platform": "5.000000000000000000", "merchant": "1.000000000000000000" },
    "confirmed_at": null,
    "created_at": "2026-08-17T12:31:07+00:00",
    "duplicate": false
  }
}
{
  "error": {
    "code": "idempotency_key_required",
    "message": "Требуется заголовок Idempotency-Key.",
    "request_id": "req_Qw3Er5Ty7Ui9Op1As2Df4Gh6"
  }
}
{
  "error": {
    "code": "aml_blocked",
    "message": "Операция отклонена комплаенс-проверкой.",
    "request_id": "req_M9n8B7v6C5x4Z3a2S1d0F1gH"
  }
}

Что проверяется перед списанием

Проверки идут в фиксированном порядке, и первая непройденная возвращает свой код. Тот же порядок и те же коды использует предпросмотр, поэтому расхождений между quote и боевым вызовом не бывает.

Вывод включён withdraw_disabled optional
Вывод средств клиентов доступен вашей учётной записи. 403.
Клиент активен customer_blocked optional
Клиент не заблокирован ни вами, ни комплаенсом. 409.
Монета доступна coin_not_allowed optional
Монета поддерживается, разрешена вашей учётной записи и допускает отправку. 422.
Сумма корректна amount_below_minimum optional
Сумма должна быть положительной и не ниже min_withdraw монеты. Ноль или отрицательное значение отклоняется кодом invalid_request, положительная сумма ниже минимума - кодом amount_below_minimum. 422.
Адрес валиден invalid_address optional
Формат адреса соответствует указанной сети. 422.
Адрес внешний coin_not_allowed optional
Адрес получателя не принадлежит платформе. Переводы внутри платформы делаются операциями charge / payout, а не он-чейн выводом. 422.
Лимиты withdraw_limit_exceeded optional
Сумма не превышает max_per_tx, а вместе с выведенным за последние 24 часа - daily_limit. Окно скользящее, поэтому лимит освобождается постепенно. 422.
Нет незавершённых проверок aml_screening_in_progress optional
По клиенту нет поступлений, ожидающих комплаенс-вердикта. Повторите позже. 409.
Хватает средств insufficient_funds optional
Доступного остатка хватает на сумму вместе с обеими комиссиями. 402.
Адрес назначения чист aml_blocked optional
Синхронная комплаенс-проверка адреса получателя. Отказ приходит до списания, уходит вебхук customer.withdrawal.blocked. 422.

Стадии заявки

Поле state

processing status: pending optional
Заявка принята, деньги с клиента списаны, отправки в сеть ещё не было.
sending status: pending optional
Команда на отправку отдана, результат ещё не известен.
sent status: pending optional
Транзакция ушла в сеть, в tx_hash есть хеш, идёт набор подтверждений. Вебхук customer.withdrawal.sent.
confirmed status: confirmed optional
Сеть подтвердила. Терминальная стадия. Вебхук customer.withdrawal.confirmed.
failed status: failed optional
Отправить не удалось. Сумма, комиссия платформы и ваша надбавка возвращены клиенту, надбавка сторнирована с мастер-счёта. Терминальная стадия. Вебхук customer.withdrawal.failed.
Терминальные стадии
Заявка закрыта только в confirmed и failed. Все остальные стадии означают «ещё в работе» - не разблокируйте заказ и не начисляйте бонусы раньше терминальной стадии.
GET /api/v1/customers/{uuid}/wallet/withdrawals/{withdrawalId}
Bearer Token

Статус заявки на вывод

{withdrawalId} - значение data.id из ответа на создание заявки. Возвращает тот же объект транзакции с актуальными status и state.

Расчёты с клиентом: charge и payout

Внутренние расчёты между вами и клиентом: мгновенные, без он-чейн транзакции и без сетевых комиссий. charge списывает с клиента в вашу пользу и зачисляет сумму на мастер-счёт, payout - обратная операция за ваш счёт.

POST /api/v1/customers/{uuid}/wallet/charge
Bearer Token

Списать с клиента в свою пользу

POST /api/v1/customers/{uuid}/wallet/payout
Bearer Token

Выплатить клиенту со своего мастер-счёта

Заголовки

Idempotency-Key string required
Обязателен для обеих операций. Правила те же, что у вывода: повтор с теми же параметрами - 200 и duplicate: true, с другими - 409.
, "+10", "10." отклоняются кодом 422.'], ['name' => 'reason', 'type' => 'string', 'desc' => 'Назначение операции для ваших отчётов, до 240 символов. Попадает в описание строки мастер-счёта.'], ]" />

Responses

{
  "data": {
    "id": "5d20fa71-9a4c-4b1e-8f77-1c3e6a0b9d24",
    "network": "TRON",
    "asset": "USDT",
    "direction": "out",
    "amount": "12.500000000000000000",
    "address": "internal:merchant:7",
    "counterparty": "Списание в пользу мерчанта",
    "tx_hash": null,
    "status": "confirmed",
    "confirmations": 0,
    "aml_status": "skipped",
    "frozen": false,
    "fee": { "platform": "0.000000000000000000", "merchant": "0.000000000000000000" },
    "confirmed_at": "2026-08-17T12:40:55+00:00",
    "created_at": "2026-08-17T12:40:55+00:00",
    "operation": "charge",
    "merchant_balance": "312.5000000000",
    "duplicate": false
  }
}
{
  "error": {
    "code": "service_balance_insufficient",
    "message": "Недостаточно средств на сервисном счёте. Пополните мастер-счёт.",
    "request_id": "req_a1B2c3D4e5F6g7H8i9J0kLmN",
    "currency": "USDT",
    "required": "50",
    "available": "12.4000000000"
  }
}

Дополнительные поля ответа

operation enum optional
charge или payout.
merchant_balance string optional
Остаток мастер-счёта в валюте операции после проводки.
duplicate bool optional
true, если это повтор по ранее использованному Idempotency-Key: ответ прежний, денег не двигали. HTTP-код при этом 200, а не 201.
charge, payout и физическая ликвидность
Обе операции меняют только внутренние остатки. Клиент, которому вы начислили payout, может вывести эти деньги в сеть обычной заявкой - платформа сама обеспечит нужную ликвидность на его адресе, дополнительных действий от вас не требуется.

Песочница

POST /api/v1/test/customers/{uuid}/simulate-deposit
Bearer Token

Сымитировать поступление на кошелёк клиента (только sk_test_)

Прогоняет полный конвейер зачисления: баланс, строка журнала, вебхук customer.deposit.detected, комплаенс-проверка. Боевым ключом эндпоинт отвечает 404.

Body

coin string required
Тикер монеты.
network string optional
Сеть, если тикер существует в нескольких.
amount number required
Сумма поступления, больше нуля.

Responses

{
  "data": {
    "id": "1e7b6a54-0c2f-4b39-9d81-6f2a4c8e0b17",
    "network": "TRON",
    "asset": "USDT",
    "direction": "in",
    "amount": "100.000000000000000000",
    "address": "SBXTRON4F2A9C1E7B6A540C2F4B399D816F2A4C",
    "counterparty": "SBXSENDER",
    "tx_hash": "sbx:1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d",
    "status": "pending",
    "confirmations": 0,
    "aml_status": "pending",
    "frozen": false,
    "fee": { "platform": "0.000000000000000000", "merchant": "0.000000000000000000" },
    "confirmed_at": null,
    "created_at": "2026-08-17T12:45:00+00:00"
  },
  "sandbox": true
}

Подробнее об отличиях окружений - Sandbox.

Права ключа

Чтение (адреса, балансы, журнал, статус заявки, предпросмотр) доступно любому ключу вашей учётной записи. Операции, двигающие деньги - вывод, charge, payout - требуют роли владельца или администратора; ключ сотрудника получит на них 403 forbidden.

Лимиты частоты

Запросов в минуту

Чтение (балансы, адреса, журнал, статус, quote) 120 optional
Общая корзина на все читающие вызовы кошельков.
Выдача адреса, симуляция депозита 30 optional
Общая корзина мутирующих вызовов: эти 30 в минуту делятся между выдачей адреса, симуляцией депозита и блокировкой/разблокировкой клиента - это не 30 на каждый эндпоинт.
charge / payout 30 optional
Своя корзина расчётов.
Вывод 6 optional
Самая узкая корзина: каждый вызов двигает деньги в сеть.
Принудительная сверка 6 optional
Аварийный инструмент, не для регулярного опроса.

При превышении приходит 429 rate_limited с заголовком Retry-After. Корзины независимы: частый опрос балансов не мешает вызвать вывод.

Коды ошибок раздела

wallets_disabled 403 optional
Крипто-кошельки клиентов недоступны вашей учётной записи.
withdraw_disabled 403 optional
Вывод средств клиентов сейчас недоступен.
forbidden 403 optional
У ключа нет прав на операцию с деньгами (роль сотрудника).
idempotency_key_required 400 optional
Не передан обязательный заголовок Idempotency-Key.
invalid_request 422 optional
Ошибка валидации запроса, например сумма вывода 0 или меньше.
coin_not_allowed 422 optional
Монета или сеть недоступны, либо адрес получателя принадлежит платформе.
amount_below_minimum 422 optional
Сумма меньше минимальной для этой монеты.
invalid_address 422 optional
Адрес не соответствует формату указанной сети.
withdraw_limit_exceeded 422 optional
Превышен лимит на операцию или суточный лимит клиента.
aml_blocked 422 optional
Адрес назначения отклонён комплаенс-проверкой.
aml_screening_in_progress 409 optional
По клиенту идёт проверка поступления - повторите позже.
customer_blocked 409 optional
Клиент заблокирован, операции по нему запрещены.
conflict 409 optional
Idempotency-Key уже использован с другими параметрами.
insufficient_funds 402 optional
На счёте клиента не хватает средств с учётом комиссий.
service_balance_insufficient 402 optional
Не хватает средств на мастер-счёте (актуально для payout). Ответ содержит currency, required и available.
service_unavailable 503 optional
Контур временно недоступен - повторите позже.

Полный реестр и формат конверта - Error Codes.

Примеры кода

KEY="sk_live_..."
B="https://fin-os.io/api/v1"
UUID="5f8d7a3c-1234-4567-89ab-cdef01234567"

# 1. Выдать клиенту адрес в TRON
curl -X POST $B/customers/$UUID/wallet/addresses \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"chain": "TRON"}'

# 2. Балансы клиента
curl -X GET $B/customers/$UUID/wallet -H "Authorization: Bearer $KEY"

# 3. Предпросмотр вывода
curl -G $B/customers/$UUID/wallet/withdraw/quote \
  -H "Authorization: Bearer $KEY" \
  --data-urlencode "coin=USDT" \
  --data-urlencode "network=TRON" \
  --data-urlencode "address=TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb" \
  --data-urlencode "amount=100"

# 4. Вывод (Idempotency-Key обязателен)
curl -X POST $B/customers/$UUID/wallet/withdraw \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wd-2026-08-17-0001" \
  -d '{"coin":"USDT","network":"TRON","address":"TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb","amount":"100"}'

# 5. Статус заявки
curl -X GET $B/customers/$UUID/wallet/withdrawals/$WITHDRAWAL_ID \
  -H "Authorization: Bearer $KEY"

# 6. Списать с клиента комиссию сервиса
curl -X POST $B/customers/$UUID/wallet/charge \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: chg-2026-08-17-0001" \
  -d '{"coin":"USDT","network":"TRON","amount":"12.5","reason":"Абонентская плата за август"}'
const B   = 'https://fin-os.io/api/v1';
const KEY = process.env.FINOS_SECRET_KEY;

const H = { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json' };

async function call(path, opts = {}) {
  const res  = await fetch(`${B}${path}`, { ...opts, headers: { ...H, ...(opts.headers || {}) } });
  const body = await res.json();
  if (!res.ok) throw Object.assign(new Error(body.error.message), body.error);
  return body;
}

// Адрес пополнения
const address = (await call(`/customers/${uuid}/wallet/addresses`, {
  method: 'POST', body: JSON.stringify({ chain: 'TRON' }),
})).data;

// Предпросмотр: показываем клиенту итоговое списание
const q = new URLSearchParams({ coin: 'USDT', network: 'TRON', address: dest, amount });
const quote = (await call(`/customers/${uuid}/wallet/withdraw/quote?${q}`)).data;
if (!quote.allowed) throw new Error(quote.reason.error);
console.log('спишется', quote.total_debit, 'получит', quote.receives);

// Вывод. Ключ идемпотентности - ваш идентификатор операции, не случайный на каждый ретрай
const withdrawal = (await call(`/customers/${uuid}/wallet/withdraw`, {
  method: 'POST',
  headers: { 'Idempotency-Key': `wd-${orderId}` },
  body: JSON.stringify({ coin: 'USDT', network: 'TRON', address: dest, amount }),
})).data;

// Терминальные стадии: confirmed и failed. Остальное - «ещё в работе»
console.log(withdrawal.status, withdrawal.state); // pending processing
use Illuminate\Support\Facades\Http;

$base = 'https://fin-os.io/api/v1';
$api  = Http::withToken(config('services.finos.secret_key'))->acceptJson()->baseUrl($base);

// Адрес пополнения (идемпотентно)
$address = $api->post("/customers/{$uuid}/wallet/addresses", ['chain' => 'TRON'])->json('data');

// Предпросмотр вывода
$quote = $api->get("/customers/{$uuid}/wallet/withdraw/quote", [
    'coin'    => 'USDT',
    'network' => 'TRON',
    'address' => $destination,
    'amount'  => '100',
])->json('data');

if (! $quote['allowed']) {
    throw new \RuntimeException($quote['reason']['error']);
}

// Вывод: ключ идемпотентности привязан к вашей операции
$response = $api->withHeaders(['Idempotency-Key' => "wd-{$orderId}"])
    ->post("/customers/{$uuid}/wallet/withdraw", [
        'coin'    => 'USDT',
        'network' => 'TRON',
        'address' => $destination,
        'amount'  => '100',
    ]);

if ($response->failed()) {
    $err = $response->json('error');
    match ($err['code']) {
        'insufficient_funds'        => notifyTopUp($uuid),
        'withdraw_limit_exceeded'   => showLimits($quote),
        'aml_blocked'               => sendToCompliance($destination),
        'aml_screening_in_progress' => retryLater(),
        default                     => report($err),
    };
}

$withdrawal = $response->json('data');   // status=pending, state=processing
import os, requests

B   = 'https://fin-os.io/api/v1'
KEY = os.environ['FINOS_SECRET_KEY']
H   = {'Authorization': f'Bearer {KEY}'}

# Адрес пополнения
address = requests.post(f'{B}/customers/{uuid}/wallet/addresses',
                        headers=H, json={'chain': 'TRON'}).json()['data']

# Журнал: только поступления, подтверждённые сетью
txs = requests.get(f'{B}/customers/{uuid}/wallet/transactions',
                   headers=H,
                   params={'direction': 'in', 'status': 'confirmed', 'per_page': 50}
                   ).json()

# Вывод с ключом идемпотентности
r = requests.post(
    f'{B}/customers/{uuid}/wallet/withdraw',
    headers={**H, 'Idempotency-Key': f'wd-{order_id}'},
    json={'coin': 'USDT', 'network': 'TRON', 'address': destination, 'amount': '100'},
)

if r.status_code in (200, 201):
    wd = r.json()['data']
    # duplicate=True означает повтор ключа: деньги уже были списаны первым вызовом
    print(wd['id'], wd['status'], wd['state'], wd['duplicate'])
else:
    err = r.json()['error']
    print(err['code'], err['message'], err['request_id'])