Wallets
Казначейские крипто-кошельки мерчанта: реестр поддерживаемых монет, депозит-адреса для приёма средств, балансы и вывод на внешний адрес. Кошельки принадлежат самому мерчанту (это его казначейство), а не конкретному customer'у - поэтому endpoints живут под /api/v1/wallets, без привязки к {uuid}.
ℹ
Мультичейн-монеты
Один и тот же ассет (например USDT) доступен в нескольких сетях (TRON, ETHEREUM, BSC, POLYGON, BASE). Параметр пути {coin} - это символ ассета (USDT, BTC, …). Для мультичейн-ассетов дополнительно указывайте network, иначе вернётся 422 invalid_request (неоднозначность). Сети - это блокчейны, которые нужны вашему клиенту, а не поставщики.
⚠
Окружение по префиксу ключа
Sandbox или live определяется префиксом ключа, а не заголовком: sk_test_ → sandbox, sk_live_ → live. В sandbox все балансы нулевые, депозит-адрес - детерминированный не-реальный адрес (не пополняйте его), а вывод только симулируется. См. Sandbox.
Реестр монет
GET
/api/v1/wallets/coins
⚷
Bearer Token
Список доступных вам монет
Возвращает монеты, доступные вашему ключу (администратор Finance OS может ограничить набор per-merchant allowlist'ом). Для каждой монеты - сеть, тип, контракт токена, точность и минимумы.
Responses
{
"data": [
{
"asset": "USDT",
"symbol": "USDT",
"name": "Tether USD",
"network": "TRON",
"kind": "token",
"contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"decimals": 6,
"min_deposit": "0.000000000000000000",
"min_withdraw": "0.000000000000000000",
"markup": { "deposit_pct": 0, "withdraw_pct": 0 }
},
{
"asset": "USDT",
"symbol": "USDT",
"name": "Tether USD",
"network": "ETHEREUM",
"kind": "token",
"contract": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"decimals": 6,
"min_deposit": "0.000000000000000000",
"min_withdraw": "0.000000000000000000",
"markup": { "deposit_pct": 0, "withdraw_pct": 0 }
},
{
"asset": "BTC",
"symbol": "BTC",
"name": "Bitcoin",
"network": "BITCOIN",
"kind": "native",
"contract": null,
"decimals": 8,
"min_deposit": "0.000000000000000000",
"min_withdraw": "0.000000000000000000",
"markup": { "deposit_pct": 0, "withdraw_pct": 0 }
}
]
}
Поля монеты
asset
string
optional
Символ ассета (используется как
{coin} в пути).symbol
string
optional
Тикер для отображения.
name
string
optional
Человекочитаемое имя.
network
string
optional
Блокчейн-сеть:
TRON, ETHEREUM, BITCOIN, LITECOIN, BSC, POLYGON, BASE.kind
enum
optional
native или token.contract
string?
optional
Адрес контракта для
token; null для native.decimals
integer
optional
Точность ассета в сети.
min_deposit
string
optional
Минимальная сумма депозита (десятичная строка; настраивается администратором, может быть 0).
min_withdraw
string
optional
Минимальная сумма вывода (десятичная строка).
markup
object
optional
Историческое поле,
deposit_pct и withdraw_pct всегда 0: это ваш собственный счёт финансирования, надбавки самому себе не бывает. Надбавка на вывод клиента задаётся фиксированной суммой по монете и видна в витрине тарифа GET /api/v1/merchant/service-pricing.| Name | Type | Required | Description |
|---|---|---|---|
asset
|
string
|
optional |
Символ ассета (используется как {coin} в пути).
|
symbol
|
string
|
optional | Тикер для отображения. |
name
|
string
|
optional | Человекочитаемое имя. |
network
|
string
|
optional |
Блокчейн-сеть: TRON, ETHEREUM, BITCOIN, LITECOIN, BSC, POLYGON, BASE.
|
kind
|
enum
|
optional |
native или token.
|
contract
|
string?
|
optional |
Адрес контракта для token; null для native.
|
decimals
|
integer
|
optional | Точность ассета в сети. |
min_deposit
|
string
|
optional | Минимальная сумма депозита (десятичная строка; настраивается администратором, может быть 0). |
min_withdraw
|
string
|
optional | Минимальная сумма вывода (десятичная строка). |
markup
|
object
|
optional |
Историческое поле, deposit_pct и withdraw_pct всегда 0: это ваш собственный счёт финансирования, надбавки самому себе не бывает. Надбавка на вывод клиента задаётся фиксированной суммой по монете и видна в витрине тарифа GET /api/v1/merchant/service-pricing.
|
Балансы
GET
/api/v1/wallets
⚷
Bearer Token
Балансы казначейства по всем монетам
Баланс каждой доступной монеты + оценка в USD. В sandbox все значения нулевые.
Responses
{
"data": [
{ "asset": "USDT", "symbol": "USDT", "network": "TRON", "balance": "1500.250000", "usd": 1500.25 },
{ "asset": "USDT", "symbol": "USDT", "network": "ETHEREUM", "balance": "0", "usd": 0 },
{ "asset": "BTC", "symbol": "BTC", "network": "BITCOIN", "balance": "0.05000000", "usd": 3250.00 }
]
}
Баланс одной монеты
GET
/api/v1/wallets/{coin}/balance
⚷
Bearer Token
Баланс по конкретной монете
Для мультичейн-ассета уточните сеть query-параметром
?network=TRON.Query
network
string
optional
Сеть для мультичейн-ассета (макс. 20 символов). Без неё неоднозначный ассет вернёт
422.| Name | Type | Required | Description |
|---|---|---|---|
network
|
string
|
optional |
Сеть для мультичейн-ассета (макс. 20 символов). Без неё неоднозначный ассет вернёт 422.
|
Responses
{
"data": {
"asset": "USDT",
"network": "TRON",
"balance": "1500.250000",
"usd": 1500.25
}
}
Депозит-адрес
POST
/api/v1/wallets/{coin}/address
⚷
Bearer Token
Получить адрес для приёма средств
Возвращает адрес казначейства в выбранной сети. Отправляйте на него только указанный ассет в указанной сети - балансы обновятся после подтверждения транзакции в блокчейне. В sandbox возвращается детерминированный не-реальный адрес (флаг
sandbox: true); реальных средств туда не отправляйте.Body
network
string
optional
Сеть для мультичейн-ассета (макс. 20 символов).
| Name | Type | Required | Description |
|---|---|---|---|
network
|
string
|
optional | Сеть для мультичейн-ассета (макс. 20 символов). |
Responses
{
"data": {
"asset": "USDT",
"network": "TRON",
"address": "TXYZ1234567890abcdef..."
}
}
{
"data": {
"asset": "USDT",
"network": "TRON",
"address": "SBXTRON8F2A1C...",
"sandbox": true
}
}
Вывод
POST
/api/v1/wallets/{coin}/withdraw
⚷
Bearer Token
Вывод на внешний адрес
Инициирует on-chain-вывод из казначейства на внешний адрес. Ответ
202 Accepted означает, что запрос принят в обработку; итоговый статус подтверждается по факту транзакции в сети.⚠
Вывод по умолчанию выключен
Реальный вывод - дормантная операция за kill-switch'ем и включается администратором Finance OS индивидуально. Пока он выключен, live-запрос вернёт 503 service_unavailable - обрабатывайте это как «временно недоступно» и повторяйте позже. В sandbox вывод всегда симулируется (без движения средств, флаг sandbox: true).
Body
to
string
required
Внешний адрес-получатель (макс. 120 символов).
amount
string
required
Сумма в единицах ассета, десятичная строка до 18 знаков после точки (
^\d+(\.\d{1,18})?$).network
string
optional
Сеть для мультичейн-ассета (макс. 20 символов).
| Name | Type | Required | Description |
|---|---|---|---|
to
|
string
|
required | Внешний адрес-получатель (макс. 120 символов). |
amount
|
string
|
required |
Сумма в единицах ассета, десятичная строка до 18 знаков после точки (^\d+(\.\d{1,18})?$).
|
network
|
string
|
optional | Сеть для мультичейн-ассета (макс. 20 символов). |
Responses
{
"data": {
"status": "accepted",
"asset": "USDT",
"network": "TRON",
"amount": "25.5",
"to": "TExternalRecipientAddr...",
"tx_hash": "9f2b0c...",
"pricing": { "markup_pct": 0 }
}
}
{
"data": {
"status": "accepted",
"asset": "USDT",
"network": "TRON",
"amount": "25.5",
"to": "TExternalRecipientAddr...",
"pricing": { "markup_pct": 0 },
"sandbox": true
}
}
{
"error": {
"code": "service_unavailable",
"message": "Сервис временно недоступен. Попробуйте позже.",
"request_id": "req_8f3ca1b209d74e55a1c0f2e7"
}
}
Лимиты частоты
Запросов в минуту
Выдача депозит-адреса (<code>POST /api/v1/wallets/{coin}/address</code>)
30
optional
Корзина изменяющих вызовов казначейских кошельков.
Вывод (<code>POST /api/v1/wallets/{coin}/withdraw</code>)
6
optional
Отдельная узкая корзина: вызов двигает деньги в сеть.
| Name | Type | Required | Description |
|---|---|---|---|
Выдача депозит-адреса (<code>POST /api/v1/wallets/{coin}/address</code>)
|
30
|
optional | Корзина изменяющих вызовов казначейских кошельков. |
Вывод (<code>POST /api/v1/wallets/{coin}/withdraw</code>)
|
6
|
optional | Отдельная узкая корзина: вызов двигает деньги в сеть. |
Чтение реестра монет и балансов отдельной корзиной не ограничено. При превышении приходит 429 rate_limited с заголовком Retry-After: спите указанное число секунд и повторяйте с экспоненциальной задержкой.
Коды ошибок
Ошибки отдаются в едином конверте { "error": { "code", "message", "request_id" } }. При ошибке валидации добавляется поле fields с детализацией по параметрам.
Примеры кода
# Реестр монет
curl -X GET https://fin-os.io/api/v1/wallets/coins \
-H "Authorization: Bearer sk_test_..."
# Все балансы казначейства
curl -X GET https://fin-os.io/api/v1/wallets \
-H "Authorization: Bearer sk_test_..."
# Баланс одной монеты (мультичейн → уточните network)
curl -X GET "https://fin-os.io/api/v1/wallets/USDT/balance?network=TRON" \
-H "Authorization: Bearer sk_test_..."
# Депозит-адрес
curl -X POST https://fin-os.io/api/v1/wallets/USDT/address \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{"network": "TRON"}'
# Вывод на внешний адрес (может вернуть 503, пока вывод не включён)
curl -X POST https://fin-os.io/api/v1/wallets/USDT/withdraw \
-H "Authorization: Bearer sk_test_..." \
-d '{"to": "TExternalRecipientAddr...", "amount": "25.5", "network": "TRON"}'
const FINOS = 'https://fin-os.io/api/v1';
const SECRET = process.env.FINOS_SECRET_KEY; // sk_test_ или sk_live_
const H = { 'Authorization': `Bearer ${SECRET}`, 'Content-Type': 'application/json' };
// Депозит-адрес казначейства для монеты в конкретной сети
async function depositAddress(coin, network) {
const res = await fetch(`${FINOS}/wallets/${coin}/address`, {
method: 'POST',
headers: H,
body: JSON.stringify({ network }),
});
const { data } = await res.json();
return data; // { asset, network, address, sandbox? }
}
// Вывод; корректно обрабатываем дормантный 503
async function withdraw(coin, to, amount, network) {
const res = await fetch(`${FINOS}/wallets/${coin}/withdraw`, {
method: 'POST',
headers: H,
body: JSON.stringify({ to, amount, network }),
});
if (res.status === 503) {
// Вывод временно недоступен - повторите позже
throw new Error('withdraw temporarily unavailable');
}
const { data } = await res.json();
return data; // 202: { status: 'accepted', ..., tx_hash }
}
use Illuminate\Support\Facades\Http;
class FinosWallets
{
private string $base = 'https://fin-os.io/api/v1';
public function __construct(private string $secretKey) {}
public function coins(): array
{
return Http::withToken($this->secretKey)
->get("{$this->base}/wallets/coins")
->json('data');
}
public function depositAddress(string $coin, ?string $network = null): array
{
return Http::withToken($this->secretKey)
->post("{$this->base}/wallets/{$coin}/address", array_filter([
'network' => $network,
]))
->json('data');
}
public function withdraw(string $coin, string $to, string $amount, ?string $network = null): array
{
$res = Http::withToken($this->secretKey)
->post("{$this->base}/wallets/{$coin}/withdraw", array_filter([
'to' => $to,
'amount' => $amount,
'network' => $network,
]));
if ($res->status() === 503) {
throw new \RuntimeException('Withdraw temporarily unavailable, retry later.');
}
return $res->json('data');
}
}
import requests, os
FINOS = 'https://fin-os.io/api/v1'
KEY = os.environ['FINOS_SECRET_KEY'] # sk_test_ или sk_live_
H = {'Authorization': f'Bearer {KEY}'}
def coins():
r = requests.get(f'{FINOS}/wallets/coins', headers=H)
r.raise_for_status()
return r.json()['data']
def deposit_address(coin, network=None):
body = {'network': network} if network else {}
r = requests.post(f'{FINOS}/wallets/{coin}/address', headers=H, json=body)
r.raise_for_status()
return r.json()['data']
def withdraw(coin, to, amount, network=None):
body = {'to': to, 'amount': amount}
if network:
body['network'] = network
r = requests.post(f'{FINOS}/wallets/{coin}/withdraw', headers=H, json=body)
if r.status_code == 503:
raise RuntimeError('Withdraw temporarily unavailable, retry later.')
r.raise_for_status()
return r.json()['data']
# usage
addr = deposit_address('USDT', 'TRON')
print('Deposit to:', addr['address'])