S
docs.syncra.money
API ReferenceMerchant API

Кошелёк: вывод USDT и адрес пополнения (Wallet)

Вывод баланса в криптовалюту USDT через сеть TRON и TRC-20 адрес для пополнения collateral-баланса мерчанта

Вывод средств в криптовалюту (Wallet)

Платформа Syncra V2 позволяет мерчантам конвертировать накопленный фиатный баланс и выводить его на свои внешние криптовалютные адреса в стейблкоинах Tether (USDT).

Вывод осуществляется через блокчейн-сеть TRON (TRC-20) — самый быстрый и дешёвый метод. Адрес получателя всегда передаётся в поле tron_address.

Сети BEP-20 (BNB Smart Chain) и ERC-20 (Ethereum) находятся в разработке и будут активированы в будущих обновлениях. Не передавайте blockchain: "TRC20" — это не валидный идентификатор сети. Поле blockchain в протоколе использует коды сетей (TRON, TON); для вывода USDT сейчас поддерживается только TRON (поведение по умолчанию).


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

Для инициации вывода криптовалюты со своего баланса отправьте POST-запрос:

POST /api/v1/p2p/merchant/wallet/withdraw

Параметры запроса (JSON Body)

ПолеТипОбяз.Описание
amount_usdtint64ДаСумма вывода в USDT, целое число (единицы USDT, не float). Например, 1000 = 1000 USDT. Внутренне конвертируется в центы (amount_usdt * 100) для хранения как int64 в минимальных единицах.
tron_addressstringДаTRC-20 (Tron) адрес получателя (base58check, 34 символа; невалидный адрес → 400). Не передавайте отдельное поле blockchain: "TRC20" — сеть вывода фиксируется как TRON.
idempotency_keystringНетПоле присутствует в контракте, но не проверяется и не требуется: идемпотентность вывода обеспечивает сама платформа — детерминированный ключ вывода строится из (мерчант, адрес, сумма, актуальная комиссия), поэтому повтор идентичного запроса сходится на той же on-chain транзакции и никогда не порождает второй перевод. Передавать можно для симметрии с PayIn/PayOut — значение игнорируется.

Пример запроса

{
  "amount_usdt": 1000,
  "tron_address": "TYHCiW3XN5sP9cWJ5T4Dfs9Y18h46t9w1a",
  "idempotency_key": "f3b8a1c2-4d5e-4f6a-9b0c-1d2e3f4a5b6c"
}

Пример ответа (200 OK, авто-одобрение)

Поля ответа — верхний уровень, без обёртки data. status в синхронном ответе — COMPLETED (авто-путь: транзакция отправлена в блокчейн, transaction_id несёт on-chain хэш) или PENDING_MANUAL (ручной путь: заявка встала в очередь одобрения оператора). Это синхронный вердикт запроса; доменный статус самой заявки (в листингах и вебхуках) — см. Статусы заявки на вывод:

{
  "status": "COMPLETED",
  "transaction_id": "0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b...",
  "amount_usdt": "1000",
  "tron_address": "TYHCiW3XN5sP9cWJ5T4Dfs9Y18h46t9w1a",
  "created_at": "2026-07-12T17:22:00Z",
  "fee_usdt_cents": "150",
  "net_usdt_cents": "99985"
}

Пример ответа (200 OK, ручное одобрение)

Сумма сверх эффективного лимита авто-вывода (или политика MANUAL_ONLY) создаёт заявку в очереди оператора: status: "PENDING_MANUAL", transaction_id пуст, комиссия указана как та, что спишет путь одобрения:

{
  "status": "PENDING_MANUAL",
  "transaction_id": "",
  "amount_usdt": "50000",
  "tron_address": "TYHCiW3XN5sP9cWJ5T4Dfs9Y18h46t9w1a",
  "created_at": "2026-07-12T17:23:00Z",
  "fee_usdt_cents": "150",
  "net_usdt_cents": "4999985"
}
ПолеТипОписание
statusstringСинхронный вердикт: COMPLETED | PENDING_MANUAL.
transaction_idstringOn-chain TX-хэш (только при COMPLETED; пуст на ручном пути).
amount_usdtint64Эхо суммы запроса (целые USDT, строкой).
fee_usdt_centsint64Комиссия вывода в USDT-центах: фактически списанная (авто-путь) или та, что спишет путь одобрения.
net_usdt_centsint64Чистая сумма зачисления получателю: amount_usdt*100 − fee_usdt_cents.

Суммы в пределах эффективного лимита автоодобрения (пер-мерчант override или база тенанта; см. расчёт комиссии) обрабатываются мгновенно и возвращают COMPLETED. Суммы сверх лимита (или политика MANUAL_ONLY) переходят в PENDING_MANUAL и требуют одобрения администратора.


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

У вывода USDT две статусные поверхности — не смешивайте их:

1. Статус в синхронном ответе POST /wallet/withdraw

СтатусОписание
COMPLETEDАвто-одобрение: on-chain транзакция отправлена (transaction_id = TX-хэш), средства списаны, ledger-запись проведена.
PENDING_MANUALЗаявка в очереди ручного одобрения оператора (политика MANUAL_ONLY или сумма сверх эффективного лимита). transaction_id пуст.

Терминальные отказы в этом поле не появляются — ошибки вывода отдаются как RFC 9457 problem+json (например, 400 при невалидном TRON-адресе, 400 FAILED_PRECONDITION при недостатке баланса).

2. Доменный статус заявки (domain.WithdrawalStatus)

Живёт в строке заявки (p2p_pending_withdrawals), виден в истории выводов и в вебхуках (p2p.finance.withdrawal_completed несёт status: "APPROVED"):

СтатусОписаниеПереход
PENDINGЗаявка создана (ручной путь), средства зарезервированы, ожидает одобрения оператора.APPROVED или CANCELLED.
APPROVEDОдобрена, транзакция отправлена в блокчейн, ledger списан.Терминальный.
CANCELLEDОтклонена оператором или отменена до broadcast; резерв возвращается на баланс.Терминальный.

V1 Compatibility Adapter транслирует APPROVEDCOMPLETED автоматически для legacy-интеграций. PROCESSING зарезервирован на будущее (подтверждение блоков между APPROVED и финалом) и текущим кодом не эмитируется. В листинге выводов дополнительно различаются PENDING (ждёт одобрения) и COMPLETED (broadcast прошёл, TX-хэш известен).


Расчёт комиссии вывода (before submit)

GET /api/v1/p2p/merchant/wallet/withdraw-fee?amount_usdt_cents=100000

Read-only калькулятор комиссии до отправки заявки: резолвит ту же per-counterparty политику вывода, что и денежный путь (пер-мерчант override, иначе база тенанта), поэтому квота не может разойтись с фактически списанной комиссией. Деньги не двигаются.

Параметры (Query)

ПараметрТипОбяз.Описание
amount_usdt_centsint64НетСумма планируемого вывода в USDT-центах (внимание: не в целых USDT, как amount_usdt создания). Когда задана (> 0), ответ дополнительно несёт net_amount_usdt_cents.

Пример ответа (200 OK)

{
  "base_fee_usdt_cents": "150",
  "override_applied": false,
  "total_fee_usdt_cents": "150",
  "net_amount_usdt_cents": "99850"
}
ПолеТипОписание
base_fee_usdt_centsint64База тенанта (p2p_system_config.withdrawal_fee_usdt_cents).
override_appliedbooltrue = пер-мерчант override заменил базу.
total_fee_usdt_centsint64Фактически применяемая комиссия: override при наличии, иначе база.
net_amount_usdt_centsint64amount − total_fee (0, если сумма не передана). Может быть ≤ 0, если комиссия покрывает всю сумму — такой вывод денежный путь отклонит (комиссия должна быть меньше суммы).

История депозитов (TRC-20 incoming)

GET /api/v1/p2p/merchant/wallet/deposits

Входящие TRC-20 депозиты мерчанта с custodial-статусами: ledger-кредит + жизненный цикл sweep-воркера принимающего адреса. Keyset-пагинация AIP-158 (page_size 1–100, по умолчанию 20; page_token/next_page_token).

Пример ответа (200 OK)

{
  "data": [
    {
      "block_timestamp": "2026-07-12T17:20:01Z",
      "amount_usdt_cents": "100000",
      "tx_hash": "0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b...",
      "trc20_address": "TCBYf3t6D2VshYVQLh55GGBDWTZvjQRoHd",
      "status": "SWEPT"
    }
  ],
  "next_page_token": ""
}
ПолеТипОписание
block_timestampstring(RFC3339)Время on-chain блока + глубина финальности (19 подтверждений).
amount_usdt_centsint64Зачисленная сумма, USDT-центы.
tx_hashstringOn-chain TRON-хэш.
trc20_addressstringАдрес зачисления (реконструирован из истории адресов контрагента).
statusstringCREDITED (средства остаются на адресе зачисления) / SWEEP_PENDING (sweep ещё не дошёл или в полёте) / SWEEP_FAILED (последний sweep не удался, retry) / SWEEP_STUCK (исход broadcast неизвестен, оператор) / SWEPT (sweep прошёл, средства на hot wallet).

История выводов

GET /api/v1/p2p/merchant/wallet/withdrawals

История выводов: очередь ручных одобрений, смёрженная с исполненными ledger-списаниями, дедуплицированная по on-chain TX-хэшу. Та же пагинация AIP-158, что и у депозитов.

Пример ответа (200 OK)

{
  "data": [
    {
      "created_at": "2026-07-12T17:22:00Z",
      "amount_usdt_cents": "100000",
      "fee_usdt_cents": "150",
      "net_usdt_cents": "99850",
      "tx_hash": "0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b...",
      "status": "COMPLETED",
      "tron_address": "TYHCiW3XN5sP9cWJ5T4Dfs9Y18h46t9w1a"
    }
  ],
  "next_page_token": ""
}
ПолеТипОписание
created_atstring(RFC3339)Время заявки (ручная очередь) или ledger-списания (авто-путь).
amount_usdt_centsint64Запрошенная gross-сумма, USDT-центы.
fee_usdt_centsint64Комиссия, USDT-центы (0 для истории до внедрения fee-механизма).
net_usdt_centsint64Чистая on-chain сумма = gross − fee.
tx_hashstringOn-chain хэш; пуст, пока вывод не отправлен в сеть.
statusstringPENDING (ждёт одобрения) / APPROVED (одобрен, не отправлен) / COMPLETED (broadcast прошёл) / CANCELLED (отклонён оператором). FAILED — зарезервирован, не персистится.
tron_addressstringАдрес назначения.

События вебхуков

СобытиеСтатус заявкиОписание
p2p.finance.withdrawal_completedAPPROVEDВывод USDT завершён (on-chain tx отправлена)
p2p.finance.withdrawal_failedCANCELLEDВывод отклонён оператором / отменён до broadcast; резерв возвращён на баланс

Webhook при завершении вывода

Когда заявка достигает терминального успеха (APPROVED), Syncra отправляет на ваш webhook URL событие (плоский CallbackEventPayload, без вложенного data — см. Callbacks):

{
  "event": "p2p.finance.withdrawal_completed",
  "deal_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "merchant_id": "8f870a31-b88d-4cb0-a882-628d08cbda88",
  "tenant_id": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 100000,
  "currency": "USDT",
  "status": "APPROVED",
  "timestamp": "2026-07-12T17:22:30Z"
}

Подпись webhook передаётся в заголовке X-Signature (см. Callbacks). Подробнее об обработке webhook и проверке подписи — в разделе Callbacks → Проверка подписи.


TRC-20 адрес для пополнения (Deposit Address)

Помимо вывода, кошелёк мерчанта имеет TRC-20 адрес для зачисления USDT-обеспечения (collateral) на операционный баланс мерчанта. Пополнения с этого адреса расходуются на выплаты (PayOut), крипто-выводы и комиссии платформы.

Deposit address — это адрес самого мерчанта для пополнения своего операционного баланса. Игроки не платят на этот адрес: в сделках PayIn игроки переводят по реквизитам трейдеров (карта/СБП/IBAN), полученным на платёжной странице (см. PayIn).

Адрес управляется двумя операциями:

МетодЭндпоинтНазначение
GET/wallet/deposit-addressRead-only: текущий активный адрес.
POST/wallet/deposit-addressГенерация (первичная) или ротация адреса.

Получение текущего адреса

GET /api/v1/p2p/merchant/wallet/deposit-address

Возвращает текущий активный TRC-20 адрес мерчанта. Поля tenant_id / merchant_id в запросе — advisory (при HMAC-аутентификации реальный скоуп берётся из подписанного токена — claims-win, см. Коды ошибок).

Пример ответа (200 OK)

Вместе с адресом возвращается updated_at — время последней генерации/ротации адреса (RFC3339):

{
  "trc20_address": "TYHCiW3XN5sP9cWJ5T4Dfs9Y18h46t9w1a",
  "updated_at": "2026-08-23T18:58:54Z"
}

Если адрес ещё не сгенерирован (404 Not Found)

Стандартная RFC 9457-обёртка (detail — вложенный JSON gRPC-деталей):

{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "{\"code\":5,\"message\":\"deposit address not provisioned yet — POST /api/v1/p2p/merchant/wallet/deposit-address to generate one\",\"details\":[]}",
  "instance": "/api/v1/p2p-engine"
}

Генерация и ротация адреса

POST /api/v1/p2p/merchant/wallet/deposit-address

Генерирует адрес (первый вызов) или ротирует его (повторные вызовы): платформа атомарно резервирует следующий BIP44 derivation index, выводит адрес через tron-wallet-api и сохраняет его в строке мерчанта. Тело запроса необязательно — скоуп resolves из аутентификационного контекста.

Пример ответа (200 OK)

{
  "trc20_address": "TYHCiW3XN5sP9cWJ5T4Dfs9Y18h46t9w1a",
  "wallet_derivation_index": 17
}

Что происходит со старым адресом при ротации

  • Новый адрес немедленно заменяет старый в строке мерчанта: GET /wallet/deposit-address и все последующие пополнения ориентируются на новый адрес.
  • Все ранее выпущенные адреса навсегда остаются в постоянном block-polling-наборе платформы (p2p_counterparty_addresses): USDT, отправленные на старый адрес после ротации, не теряются — они продолжают отслеживаться и зачисляться на баланс мерчанта.
  • После ротации сохранённый на вашей стороне адрес следует обновить (сверьте его через GET /wallet/deposit-address).

Существует два POST-пути генерации. Каноничный путь для сервер-сервер интеграции мерчанта — POST /api/v1/p2p/merchant/wallet/deposit-address (без merchant_id в пути, скоуп — из токена). Legacy-путь POST /api/v1/p2p/merchants/{merchant_id}/deposit-address остаётся рабочим и используется для admin-impersonation (оператор платформы действует от имени мерчанта); при HMAC-аутентификации merchant_id в пути обязан совпадать с claims токена, при merchant-JWT — только с собственным мерчантом (IDOR-защита).


Связанные материалы

  • Баланс — мультивалютные балансы мерчанта.
  • Идемпотентность — как идемпотентность вывода обеспечивается платформой.
  • Callbacks — webhook-уведомления, включая p2p.finance.withdrawal_completed.
  • Коды ошибок — обработка INSUFFICIENT_BALANCE и других ошибок.

On this page