Интеграция по API
REST API, JSON, HTTPS. Базовый URL:
https://zoltopay.com/gw
Быстрый старт
- Зарегистрируйтесь — API-ключ (формат
gw_…) покажется сразу после регистрации. Потерянный ключ можно перевыпустить в кабинете. - В кабинете → Настройки: укажите адрес выплат, правила выплат и Callback URL, затем нажмите «Создать новый секрет» для подписи вебхуков.
- Ваш сервер создаёт инвойс → перенаправляет клиента на
pay_url(готовая форма оплаты) → ждёт вебхукinvoice.paid→ проверяет подпись и статус → выдаёт товар.
"25.50"), чтобы не терять точность.Авторизация
Каждый запрос — с заголовком:
Authorization: Bearer gw_ваш_ключ
Ключ даёт полный доступ к аккаунту, включая выплаты. Используйте его только на сервере, никогда — в браузере или мобильном приложении. При утечке выпустите новый в кабинете.
Сети и монеты
Список доступных монет — GET /v1/currencies:
{"currencies":[{"currency_id":"USDT.Tron","coin":"USDT","network":"TRON (TRC-20)",
"min_payment_usd":"10","payout_fee_usd":"2.99","decimals":6,"confirmations":20,"native":false,"payout":true}],
"fiat":["USD","EUR","RUB","UAH","KZT","TRY","GBP","AED","CNY","INR"]}
| Поле | Описание |
|---|---|
currency_id | Монета и сеть — передаётся в currency при создании инвойса и выплаты. |
min_payment_usd | Минимальный платёж в этой монете, USD. |
payout_fee_usd | Сетевой сбор за одну выплату, USD. Для монет (не USDT) удерживается в монете выплаты по текущему курсу. |
decimals | Знаков после запятой у монеты. Суммы точнее округляются. |
confirmations | Подтверждений сети, после которых платёж зачисляется и приходит invoice.paid. |
native | Титульная монета сети (TRX, BNB, ETH, BTC …). |
payout | Можно ли выводить в этой монете. |
Все монеты
currency_id | Монета | Сеть | Мин. платёж | Сбор за вывод | Знаков | Подтверждений | Вывод |
|---|---|---|---|---|---|---|---|
USDT.Tron | USDT | TRON (TRC-20) | 10 USD | 2.99 USD | 6 | 20 | да |
TRX.Tron | TRX | TRON | 10 USD | 1.49 USD | 6 | 20 | да |
USDD.Tron | USDD | TRON (TRC-20) | 10 USD | — | 18 | 20 | нет |
USD1.Tron | USD1 | TRON (TRC-20) | 10 USD | — | 18 | 20 | нет |
USDT.BNBSmartChain | USDT | BNB Chain (BEP-20) | 10 USD | 0.99 USD | 18 | 15 | да |
USDC.BNBSmartChain | USDC | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
BNB.BNBSmartChain | BNB | BNB Chain | 10 USD | 0.49 USD | 8 | 15 | да |
DAI.BNBSmartChain | DAI | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
USDE.BNBSmartChain | USDE | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
USDD.BNBSmartChain | USDD | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
USD1.BNBSmartChain | USD1 | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
CAKE.BNBSmartChain | CAKE | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
SHIB.BNBSmartChain | SHIB | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
WLFI.BNBSmartChain | WLFI | BNB Chain (BEP-20) | 10 USD | — | 18 | 15 | нет |
USDT.Ethereum | USDT | Ethereum (ERC-20) | 50 USD | — | 6 | 12 | нет |
USDC.Ethereum | USDC | Ethereum (ERC-20) | 50 USD | — | 6 | 12 | нет |
ETH.Ethereum | ETH | Ethereum | 50 USD | 4.99 USD | 18 | 12 | да |
DAI.Ethereum | DAI | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
PYUSD.Ethereum | PYUSD | Ethereum (ERC-20) | 50 USD | — | 6 | 12 | нет |
USDE.Ethereum | USDE | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
USDD.Ethereum | USDD | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
USD1.Ethereum | USD1 | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
XAUT.Ethereum | XAUT | Ethereum (ERC-20) | 50 USD | — | 6 | 12 | нет |
ARB.Ethereum | ARB | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
SHIB.Ethereum | SHIB | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
PEPE.Ethereum | PEPE | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
WLD.Ethereum | WLD | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
ENA.Ethereum | ENA | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
SAND.Ethereum | SAND | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
CAKE.Ethereum | CAKE | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
WLFI.Ethereum | WLFI | Ethereum (ERC-20) | 50 USD | — | 18 | 12 | нет |
USDT.Polygon | USDT | Polygon | 10 USD | — | 6 | 64 | нет |
USDC.Polygon | USDC | Polygon | 10 USD | — | 6 | 64 | нет |
POL.Polygon | POL | Polygon | 10 USD | 0.49 USD | 18 | 64 | да |
DAI.Polygon | DAI | Polygon | 10 USD | — | 18 | 64 | нет |
SAND.Polygon | SAND | Polygon | 10 USD | — | 18 | 64 | нет |
USDT.Arbitrum | USDT | Arbitrum One | 10 USD | — | 6 | 20 | нет |
USDC.Arbitrum | USDC | Arbitrum One | 10 USD | — | 6 | 20 | нет |
ETH.Arbitrum | ETH | Arbitrum One | 10 USD | 0.99 USD | 18 | 20 | да |
DAI.Arbitrum | DAI | Arbitrum One | 10 USD | — | 18 | 20 | нет |
ARB.Arbitrum | ARB | Arbitrum One | 10 USD | — | 18 | 20 | нет |
PYUSD.Arbitrum | PYUSD | Arbitrum One | 10 USD | — | 6 | 20 | нет |
CAKE.Arbitrum | CAKE | Arbitrum One | 10 USD | — | 18 | 20 | нет |
BTC.Bitcoin | BTC | Bitcoin | 20 USD | 4.99 USD | 8 | 2 | да |
LTC.Litecoin | LTC | Litecoin | 10 USD | 0.49 USD | 8 | 6 | да |
DOGE.Dogecoin | DOGE | Dogecoin | 10 USD | 0.99 USD | 8 | 6 | да |
BCH.Bitcoincash | BCH | Bitcoin Cash | 10 USD | 0.49 USD | 8 | 6 | да |
Клиенту обязательно покажите сеть: перевод в другой сети автоматически не зачисляется.
Приём и вывод
- Приём — во всех монетах из таблицы.
- USDT и USDC в любой сети зачисляются на USD-баланс 1:1. Вывод USD-баланса — только в USDT TRC-20 (
USDT.Tron) или USDT BEP-20 (USDT.BNBSmartChain). - Титульные монеты (TRX, BNB, ETH, POL, BTC, LTC, DOGE, BCH) зачисляются на баланс в этой монете и выводятся в ней же, в своей сети.
- Прочие токены (DAI и др.) только принимаются. Их баланс можно обменять в кабинете на USDT или титульную монету сети, либо включить автоконвертацию при получении.
Форматы адресов
| Сеть | Адрес | Особенности |
|---|---|---|
| TRON | T…, 34 символа | Один адрес для TRX и TRC-20-токенов. |
| BNB Chain, Ethereum, Polygon, Arbitrum | 0x…, 42 символа | Адрес одинаковый во всех EVM-сетях, но зачисляется только перевод в сети инвойса. Перевод из другой сети на тот же адрес не зачислится автоматически. |
| Bitcoin | bc1…, 1…, 3… | — |
| Litecoin | ltc1…, L…, M… | — |
| Dogecoin | D… | — |
| Bitcoin Cash | bitcoincash:q… или q… | — |
Мемо и destination tag не нужны: каждый инвойс получает свой адрес или уникальную сумму.
Газ платит Zoltopay: держать TRX, BNB или ETH на своём адресе для приёма или вывода не нужно. Сетевые расходы на вывод покрывает payout_fee_usd.
Создание инвойса
POST /v1/invoices
| Поле | Тип | Описание | |
|---|---|---|---|
order_id | string | обязательно | Ваш номер заказа. Уникален в пределах аккаунта: повторный запрос с тем же order_id не создаёт новый инвойс, а возвращает существующий (200 OK). |
amount | string | обязательно | Сумма в валюте currency. Минимум 10 USD (для фиата — по курсу). |
currency | string | Фиат (USD, EUR, RUB …) — монету выберет покупатель. Или монета и сеть, напр. USDT.Tron. По умолчанию — монета выплат из настроек. | |
ttl_minutes | int | Срок жизни инвойса, по умолчанию 60. | |
email | string | Email клиента (необязательно). | |
return_url | string | Куда вернуть покупателя со страницы оплаты после оплаты, https://… (необязательно). |
curl -X POST https://zoltopay.com/gw/v1/invoices \
-H "Authorization: Bearer gw_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{"order_id":"ORDER-1001","amount":"25","currency":"USDT.Tron","return_url":"https://shop.example/order/1001"}'
Ответ 201 Created (или 200 OK, если инвойс с таким order_id уже есть):
{
"id": 42,
"order_id": "ORDER-1001",
"amount": "25",
"currency": "USDT.Tron",
"amount_usd": "25.01",
"status": "NEW",
"pay_url": "https://zoltopay.com/checkout/42-9f3c1a7be0d24c55e1aa",
"pay_address": "TXyz...abc",
"amount_to_pay": "25.01",
"addresses": [{"address": "TXyz...abc", "currency_id": "USDT.Tron"}],
"expires_at": "2026-10-20T12:00:00Z",
"created_at": "2026-10-20T11:00:00Z"
}
Счёт в фиате
Передайте в currency код фиатной валюты: USD, EUR, RUB, UAH, KZT, TRY, GBP, AED, CNY, INR. Счёт создаётся без монеты — покупатель выбирает её на странице оплаты (pay_url), сумма в монете считается по текущему курсу.
curl -X POST https://zoltopay.com/gw/v1/invoices -H "Authorization: Bearer gw_ваш_ключ" -H "Content-Type: application/json" -d '{"order_id":"ORDER-1002","amount":"50","currency":"EUR"}'
{
"id": 43,
"order_id": "ORDER-1002",
"amount": "50",
"currency": "EUR",
"amount_usd": "54.12",
"status": "NEW",
"pay_url": "https://zoltopay.com/checkout/43-…",
"expires_at": "2026-10-21T12:00:00Z",
"created_at": "2026-10-21T11:00:00Z"
}
- До выбора монеты в ответе нет
pay_address; после выбораGET /v1/invoices/{id}вернётcoin,pay_address,amount_to_pay. amount_usd— оценка по курсу; после выбора монеты — точная сумма к оплате в USD.- Курсы обновляются каждые 10 минут. Если курс валюты недоступен, создание счёта вернёт
503— повторите позже. - Покупатель выбирает сеть, затем монету: USDT, USDC, BTC, ETH, TRX, BNB, LTC, DOGE и другие. Для USDT/USDC сумма равна сумме в USD; для остальных монет курс фиксируется на 20 минут, потом сумма пересчитывается.
- Оплата в BTC, ETH и других монетах (не USDT/USDC) зачисляется на баланс в этой монете — см.
balancesвGET /v1/balance. В вебхукеinvoice.paidестьcurrencyиamount— монета и сумма платежа.
Форма оплаты (самый быстрый способ)
В ответе на создание инвойса всегда есть pay_url — ссылка на готовую страницу оплаты Zoltopay. Достаточно перенаправить на неё покупателя:
// после POST /v1/invoices
header('Location: ' . $invoice['pay_url']); // PHP
res.redirect(invoice.pay_url); // Node.js / Express
На странице покупатель видит название вашего магазина и номер заказа, точную сумму, монету и сеть, адрес с QR-кодом и кнопками «Копировать», таймер до истечения инвойса. Статус обновляется сам: после поступления платежа страница показывает «Оплата получена» и через 5 секунд возвращает покупателя на return_url (если вы его передали).
- Ссылку можно открыть в той же вкладке, в новой или во фрейме, отправить письмом или в мессенджер.
- Страница истёкшего инвойса предупреждает не платить и предлагает вернуться в магазин.
- Возврат на
return_url— только для удобства покупателя. Факт оплаты подтверждайте вебхукомinvoice.paidили запросомGET /v1/invoices/{id}, а не по факту возврата.
Своя форма оплаты
Если хотите показывать оплату в своём дизайне — используйте pay_address и amount_to_pay из ответа:
- покажите клиенту адрес, сеть (из
currency) и точную суммуamount_to_pay(всегда 2 знака после запятой; может быть больше суммы заказа на 0,01–0,99) — с копированием в один клик и QR-кодом адреса; - предупредите: «переведите ровно эту сумму одним платежом». По сумме платёж находит ваш заказ — если клиент округлит её, платёж уйдёт на ручной разбор;
- покажите таймер до
expires_at.
H2H: своя форма с выбором монеты
Полный аналог нашей страницы оплаты на вашем сайте: счёт выставляется в фиате, покупатель в вашей форме выбирает сеть и монету, вы показываете адрес и точную сумму.
POST /v1/invoices/{id}/quote вернёт 403. Счета в монете (currency: "USDT.Tron") и форма по pay_address работают без H2H.- Список монет.
GET /v1/currencies→ покажите выбор: сначала сеть (network), затем монету (coin). Значение для запроса —currency_id. - Счёт в фиате.
POST /v1/invoicesс"currency": "EUR"(или другой фиат). В ответе пока нет адреса. - Покупатель выбрал монету → ваш сервер вызывает:
POST /v1/invoices/{id}/quoteПоле Тип Описание currencystring обязательно currency_idизGET /v1/currencies, напр.USDT.Tron,BTC.Bitcoin.curl -X POST https://zoltopay.com/gw/v1/invoices/43/quote \ -H "Authorization: Bearer gw_ваш_ключ" \ -H "Content-Type: application/json" \ -d '{"currency":"USDT.Tron"}'Ответ
200 OK— инвойс с адресом и суммой:{ "id": 43, "order_id": "ORDER-1002", "amount": "50", "currency": "EUR", "coin": "USDT.Tron", "amount_usd": "54.12", "status": "NEW", "pay_url": "https://zoltopay.com/checkout/43-…", "pay_address": "TXyz...abc", "amount_to_pay": "54.12", "addresses": [{"address": "TXyz...abc", "currency_id": "USDT.Tron"}], "expires_at": "2026-10-21T12:00:00Z", "quote_expires_at": "2026-10-21T11:20:00Z", "created_at": "2026-10-21T11:00:00Z" } - Форма оплаты. Покажите
pay_address(с QR и копированием), сеть, точнуюamount_to_payв монетеcoinи таймер доquote_expires_at. - Статус. Вебхук
invoice.paidили опросGET /v1/invoices/{id}(не чаще раза в 5–10 секунд).
- Курс. Для USDT/USDC сумма = сумме в USD и действует до
expires_at. Для BTC, ETH и других монет курс фиксируется на 20 минут (quote_expires_at); после этого вызовитеquoteещё раз с той же монетой — сумма пересчитается. - Смена монеты. Пока инвойс
NEW, можно вызватьquoteс другой монетой (всего до 10 вызововquoteна инвойс, включая пересчёт курса). Покажите покупателю новый адрес и сумму, старые больше не используйте. - Ошибки quote:
400— монета недоступна, инвойс не фиатный, оплачен/истёк или исчерпан лимит смен;403— H2H не включён;404— инвойс не найден;503— курс временно недоступен, повторите.
Статус инвойса
GET /v1/invoices/{id}
GET /v1/invoices?limit=50
Возвращает тот же объект, что и при создании, с актуальными status, paid_at. Используйте как основной способ проверки перед выдачей товара и как запасной, если вебхук не дошёл.
Статусы инвойса
| Статус | Значение | Что делать |
|---|---|---|
NEW | Ожидает оплаты | Ждать |
PAID | Оплачен (допуск ±1%) | Выдать товар |
OVERPAID | Оплачен с переплатой | Выдать товар; излишек на вашем балансе |
UNDERPAID | Оплачен не полностью | Решить по своей политике (доплата/возврат) |
EXPIRED | Истёк без оплаты | Создать новый инвойс |
Вебхуки
На ваш Callback URL приходит POST с JSON-телом и заголовками:
Content-Type: application/json
X-Event: invoice.paid
X-Signature: 5f2c… (hex HMAC-SHA256 тела запроса вашим секретом)
Ответьте любым 2xx в течение 15 секунд. Иначе повторим доставку с нарастающей паузой (до 1 часа между попытками, всего 15 попыток). Обработчик должен быть идемпотентным: одно событие может прийти дважды.
| Событие | Тело |
|---|---|
invoice.paid | {"invoice_id":42,"order_id":"ORDER-1001","status":"PAID","paid_usd":"25.01","amount_usd":"25.01","currency":"USDT.Tron","amount":"25.01"}status может быть PAID или OVERPAID; currency/amount — монета и сумма платежа |
invoice.underpaid | {"invoice_id":42,"order_id":"ORDER-1001","status":"UNDERPAID","paid_usd":"20","amount_usd":"20","currency":"USDT.Tron","amount":"20"} |
payment.unmatched | {"payment_id":15,"address":"TXyz...abc","amount":"24","currency":"USDT.Tron","tx_hash":"a1b2…"}платёж не совпал по сумме ни с одним инвойсом — уходит на ручной разбор, свяжитесь с поддержкой |
payout.confirmed | {"payout_id":7,"status":"CONFIRMED","tx_hash":"a1b2…"} |
payout.failed | {"payout_id":7,"status":"FAILED","reason":"…"}сумма и сбор возвращены на баланс |
security.whitelist_added | {"chain":"tron","address":"TAbc...","active_at":"…","ip":"…"}в белый список выплат добавлен адрес |
security.payout_ips_changed | {"ips":"203.0.113.10","ip":"…"} |
security.payout_secret_rotated | {"ip":"…"}выпущен новый секрет выплат, старый не действует |
test | {"event":"test","test":true,"merchant_id":2,"created_at":"…"}кнопка «Тестовый вебхук» в кабинете |
Проверка подписи
Считайте HMAC-SHA256 от сырого тела запроса (до разбора JSON) и сравните с X-Signature в постоянном времени.
PHP
$body = file_get_contents('php://input');
$sig = hash_hmac('sha256', $body, getenv('ZOLTOPAY_WEBHOOK_SECRET'));
if (!hash_equals($sig, $_SERVER['HTTP_X_SIGNATURE'] ?? '')) { http_response_code(401); exit; }
$event = json_decode($body, true);
// дополнительно: GET /v1/invoices/{invoice_id} и проверить status
http_response_code(200);
Node.js (Express)
app.post('/zoltopay/callback', express.raw({ type: 'application/json' }), (req, res) => {
const sig = crypto.createHmac('sha256', process.env.ZOLTOPAY_WEBHOOK_SECRET)
.update(req.body).digest('hex');
const got = req.get('X-Signature') || '';
if (sig.length !== got.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(got)))
return res.sendStatus(401);
const event = JSON.parse(req.body);
res.sendStatus(200);
});
Python
import hmac, hashlib
sig = hmac.new(SECRET.encode(), raw_body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, request.headers.get("X-Signature", "")):
abort(401)
Баланс
GET /v1/balance
{"balance_usd": "152.37", "currency": "USD", "mode": "DIRECT_PAYOUT",
"balances": [{"currency": "USD", "amount": "152.37"}, {"currency": "BTC.Bitcoin", "amount": "0.0012"}]}
balance_usd — баланс в USD (USDT/USDC); balances — все валюты, включая монеты, принятые по фиат-счетам.
Выплаты
Автоматические выплаты (сразу или по порогу) и ручной вывод настраиваются в кабинете. Вывод баланса по API — для автоматизации на вашем сервере. Он выключен по умолчанию и защищён сильнее остального API: даже если ваш API-ключ утечёт, вывести деньги по нему нельзя.
Подключение
- Попросите поддержку включить выплаты по API и согласуйте лимиты.
- Кабинет → «API и вебхуки» → «Выплаты по API» (для каждого действия нужен пароль входа):
- Секрет выплат — отдельный от API-ключа и секрета вебхуков. Показывается один раз, храните его только на сервере.
- Разрешённые IP вашего сервера, через запятую. Подсеть — не шире /24. Если список пуст, выплаты по API запрещены.
- Белый список адресов. Выплата возможна только на адрес из списка, а новый адрес начинает работать через 24 часа.
При каждом изменении придёт вебхук security.* (см. «Вебхуки»). Если вы его не ожидали, сразу удалите адрес в кабинете (без пароля) и напишите в поддержку.
Запрос
POST /v1/payouts
Authorization: Bearer gw_ваш_ключ
X-Timestamp: 1792580000 (unix-секунды, допуск ±5 минут)
X-Signature: hex(HMAC-SHA256(секрет_выплат, X-Timestamp + "." + тело))
| Поле | Тип | Описание | |
|---|---|---|---|
request_id | string | обязательно | Ваш уникальный ключ идемпотентности (до 64 символов). Повтор с тем же request_id не создаст вторую выплату. |
address | string | обязательно | Адрес из белого списка, уже активный (прошло 24 ч). |
amount | string | обязательно | Сумма к получению. С баланса спишется сумма плюс сетевой сбор. Минимум 20 USD. |
currency | string | USDT.Tron, USDT.BNBSmartChain (списание с USD-баланса) или титульная монета (TRX.Tron, BTC.Bitcoin …, списание с баланса этой монеты) — см. «Приём и вывод». По умолчанию — монета выплат из настроек. |
Подписываются ровно те байты, что уходят в теле. Сформируйте JSON один раз и используйте одну и ту же строку и для подписи, и для отправки.
Node.js
const crypto = require('crypto');
const ts = Math.floor(Date.now() / 1000).toString();
const body = JSON.stringify({ request_id: 'wd-1001', address: 'TAbc...', amount: '150', currency: 'USDT.Tron' });
const sig = crypto.createHmac('sha256', process.env.ZOLTOPAY_PAYOUT_SECRET).update(ts + '.' + body).digest('hex');
const res = await fetch('https://zoltopay.com/gw/v1/payouts', { method: 'POST', body, headers: {
'Authorization': 'Bearer ' + process.env.ZOLTOPAY_API_KEY, 'Content-Type': 'application/json',
'X-Timestamp': ts, 'X-Signature': sig } });
PHP
$ts = (string) time();
$body = json_encode(['request_id' => 'wd-1001', 'address' => 'TAbc...', 'amount' => '150', 'currency' => 'USDT.Tron']);
$sig = hash_hmac('sha256', $ts . '.' . $body, getenv('ZOLTOPAY_PAYOUT_SECRET'));
$ch = curl_init('https://zoltopay.com/gw/v1/payouts');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('ZOLTOPAY_API_KEY'), 'Content-Type: application/json',
'X-Timestamp: ' . $ts, 'X-Signature: ' . $sig]]);
$resp = curl_exec($ch);
Python
import hmac, hashlib, json, time, requests
ts = str(int(time.time()))
body = json.dumps({"request_id": "wd-1001", "address": "TAbc...", "amount": "150", "currency": "USDT.Tron"})
sig = hmac.new(PAYOUT_SECRET.encode(), (ts + "." + body).encode(), hashlib.sha256).hexdigest()
requests.post("https://zoltopay.com/gw/v1/payouts", data=body, headers={"Authorization": "Bearer " + API_KEY,
"Content-Type": "application/json", "X-Timestamp": ts, "X-Signature": sig})
Ответ и статусы
202 Accepted — выплата создана; 200 — повтор того же request_id:
{"id":7,"request_id":"wd-1001","address":"TAbc...","amount":"150","currency":"USDT.Tron","status":"SENT"}
| Статус | Значение |
|---|---|
PENDING_REVIEW | Сумма выше порога ручной проверки: деньги зарезервированы, выплата уйдёт после одобрения поддержкой |
QUEUED → SENT | Отправляется в сеть |
CONFIRMED | Транзакция в блокчейне, tx_hash заполнен, придёт вебхук payout.confirmed |
FAILED | Не прошла или отклонена: сумма и сбор возвращены на баланс, придёт вебхук payout.failed |
Проверка статуса: GET /v1/payouts/{id} (подпись не нужна).
Лимиты
Действуют лимиты на одну выплату и на сумму за 24 часа, а также порог ручной проверки. Текущие значения показаны в кабинете. При превышении вернётся 422.
Ошибки выплат
| Код | Ответ | Что делать |
|---|---|---|
| 401 | invalid signature, X-Timestamp is outside… | Проверьте секрет выплат, подписываемые байты и часы сервера (NTP) |
| 403 | API payouts are not enabled… | Обратитесь в поддержку |
| 403 | ip not allowed | Добавьте IP сервера в кабинете |
| 403 | address is not in the payout whitelist / …becomes active at … | Добавьте адрес и дождитесь активации |
| 422 | insufficient balance, …limit… | Не хватает баланса или превышен лимит |
| 400 | payouts are available only in USDT.Tron, USDT.BNBSmartChain and native coins… | Выберите монету с payout: true из GET /v1/currencies |
Ошибки
Тело ошибки: {"error": "описание"}.
| Код | Причина |
|---|---|
| 400 | Неверный JSON или параметры |
| 401 | Нет или неверный API-ключ; для выплат — неверная подпись |
| 403 | Функция не включена для аккаунта (H2H, выплаты по API), IP или адрес выплаты не разрешён |
| 404 | Объект не найден |
| 422 | Недостаточно средств на балансе или превышен лимит выплат |
| 502 | Временная ошибка — повторите запрос позже с тем же order_id (инвойс) или request_id (выплата): дубль не создастся |
| 503 | Курс фиатной валюты временно недоступен |
Чек-лист перед запуском
- API-ключ хранится только на сервере.
- Задан Callback URL (https) и секрет; подпись проверяется на каждом вебхуке.
- Перед выдачей товара статус проверяется через
GET /v1/invoices/{id}. - Обработчик вебхуков идемпотентен (повтор события не выдаёт товар дважды).
- Клиенту показывается точная сумма
amount_to_payи сеть. - Указан адрес выплат и настроены правила выплат.
- Для выплат по API: заданы секрет выплат и IP, адреса в белом списке активны, вебхуки
security.*кто-то читает. - Проведён тестовый платёж на минимальную сумму.