Skip to content
Translated page. The English version is the source of truth.

POST /apiv2/withdraw ​

Виведення TRX з вашого балансу Netts на будь-яку адресу TRON. Запит миттєво повертає номер замовлення; фактична виплата в мережі здійснюється асинхронно бекендом (протягом ~5 хвилин). Відстежуйте результат за допомогою опитування ендпойнта статусу або налаштувавши webhook.

ℹ️ Як це працює. Створення заявки на виведення одразу резервує суму з вашого балансу (баланс списується в момент прийняття замовлення). Потім фоновий процес відправляє TRX і позначає замовлення як completed або failed. У початковій відповіді немає синхронного результату в мережі — спочатку ви завжди отримуєте підтвердження зі статусом pending.

URL ендпойнта ​

POST https://netts.io/apiv2/withdraw

Заголовки запиту ​

ЗаголовокОбов'язковийОпис
Content-TypeТакapplication/json
X-API-KEYТакВаш API-ключ із панелі керування Netts
X-Real-IPТакIP-адреса з вашого білого списку
X-Idempotency-KeyНіНеобов'язковий згенерований клієнтом ключ (base64) для безпечного повторення без подвійного виведення. Якщо опущено, сервер формує його автоматично. Це значення стає вашим orderId.

Тіло запиту ​

json
{
    "amount": 15,
    "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

Параметри ​

ПараметрТипОбов'язковийОпис
amountnumberТакВалова (gross) сума в TRX (мінімум 3). Комісія відраховується від цієї суми — отримувач одержує amount − fee (net).
addressstringТакЦільова адреса TRON (T…, 34 символи, base58).
sub_and_robot_outbooleanНіРежим виплати для роботів/субакаунтів: застосовує комісію 2 TRX замість 1 TRX. За замовчуванням false.

Комісія. Фіксована комісія утримується від валової суми amount: 1 TRX за звичайних умов або 2 TRX, коли sub_and_robot_out = true. Замовлення відхиляється, якщо amount − fee ≤ 0.

Приклади запитів ​

Наведені нижче приклади також формують і відправляють X-Idempotency-Key, щоб випадковий повтор не створив друге виведення. Повні правила дивіться у розділі Ідемпотентність.

cURL ​

bash
API_KEY="your_api_key"
ADDR="TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AMOUNT=15
NONCE=$(( $(date +%s) / 2 ))   # stable for retries within a 2s window; or your own order UUID

# X-Idempotency-Key = base64url( HMAC-SHA256( API_KEY, "addr:amount:nonce" ) )
IDEMP=$(printf '%s' "${ADDR}:${AMOUNT}:${NONCE}" \
  | openssl dgst -sha256 -hmac "$API_KEY" -binary | basenc --base64url | tr -d '=')

curl -X POST https://netts.io/apiv2/withdraw \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: $API_KEY" \
  -H "X-Real-IP: your_whitelisted_ip" \
  -H "X-Idempotency-Key: $IDEMP" \
  -d "{\"amount\": $AMOUNT, \"address\": \"$ADDR\"}"

Python ​

python
import time, hmac, hashlib, base64, requests

API_KEY = "your_api_key"
url = "https://netts.io/apiv2/withdraw"
payload = {"amount": 15, "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}

# X-Idempotency-Key = base64url( HMAC-SHA256( API_KEY, "addr:amount:nonce" ) ), padding stripped.
# Generate ONCE per order and resend the same value on every retry.
nonce = str(int(time.time() // 2))   # 2s bucket; or your own order UUID
message = f"{payload['address']}:{payload['amount']}:{nonce}"
idem_key = base64.urlsafe_b64encode(
    hmac.new(API_KEY.encode(), message.encode(), hashlib.sha256).digest()
).decode().rstrip("=")

headers = {
    "Content-Type": "application/json",
    "X-API-KEY": API_KEY,
    "X-Real-IP": "your_whitelisted_ip",
    "X-Idempotency-Key": idem_key,
}

resp = requests.post(url, headers=headers, json=payload)
detail = resp.json().get("detail", {})

if resp.status_code == 202 and detail.get("status") == "pending":
    d = detail["data"]
    print(f"Order ID: {d['orderId']}")            # use it for the status endpoint / webhook
    print(f"Net to recipient: {d['net']} TRX (fee {d['fee']})")
else:
    print(f"Code {detail.get('code')}: {detail.get('msg', detail)}")

Відповідь ​

Прийнято — виведення додано в чергу (202 Accepted) ​

Сума зарезервована з вашого балансу, а виплату заплановано. Опитуйте ендпойнт статусу (або чекайте на webhook), доки статус не зміниться на completed / failed.

json
{
    "detail": {
        "code": 10000,
        "status": "pending",
        "msg": "Withdrawal request accepted, processing within 5 minutes.",
        "data": {
            "orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
            "amount": 15.0,
            "fee": 1.0,
            "net": 14.0,
            "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
    }
}

Поля відповіді ​

ПолеТипОпис
detail.codeinteger10000 прийнято
detail.statusstringpending
detail.data.orderIdstringНомер замовлення — URL-безпечний рядок із 43 символів. Використовуйте його для ендпойнта статусу; він також ідентифікує замовлення у корисних навантаженнях webhook.
detail.data.amountnumberЗапитана валова сума (TRX)
detail.data.feenumberУтримана комісія (1 або 2 TRX)
detail.data.netnumberСума, яку отримує одержувач (amount − fee)
detail.data.addressstringЦільова адреса

Ендпойнт статусу ​

GET https://netts.io/apiv2/withdraw/status/{orderId}

Заголовки: X-API-KEY + X-Real-IP (замовлення має належати автентифікованому користувачеві). orderId є URL-безпечним — передавайте його як є, без додаткового URL-кодування.

Стан замовленняHTTPcodestatus
Завершено (TRX відправлено)20010000completed (з processed_at)
У черзі / відправляється20010001pending
Помилка2005003failed (з error_message)
Не знайдено / не ваше404-1—
json
{
    "detail": {
        "code": 10000,
        "status": "completed",
        "data": {
            "orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
            "amount": 15.0, "fee": 1.0, "net": 14.0,
            "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "processed_at": "2026-01-01 00:00:00+00:00"
        }
    }
}

Акаунти субкористувачів ​

Виведення коштів для субкористувачів працює абсолютно так само, як і для звичайних користувачів — лише з власним API-ключем субкористувача. Субкористувач викликає той самий ендпойнт POST /apiv2/withdraw, автентифікований власним ключем; кошти списуються з власного балансу цього субкористувача та надсилаються на будь-яку address, вказану в запиті. Той самий мінімум, та сама комісія (1 TRX), той самий процес. Окремого ендпойнта для субкористувачів немає — кожен акаунт, батьківський або субакаунт, завжди виводить лише власний баланс за допомогою власного ключа.

Webhook-сповіщення ​

Замість опитування налаштуйте webhook один раз, і Netts надсилатиме підписане POST-сповіщення щоразу, коли кожне з ваших виведень переходить у кінцевий стан (completed / failed). Webhook зберігається для кожного користувача окремо та застосовується до виведень цього акаунта. Якщо webhook не налаштовано, просто опитуйте ендпойнт статусу.

Налаштування / перегляд / видалення ​

POST   https://netts.io/apiv2/withdraw/webhook      # create or update
GET    https://netts.io/apiv2/withdraw/webhook      # view current config (secret is never returned)
DELETE https://netts.io/apiv2/withdraw/webhook      # unsubscribe

Заголовки: X-API-KEY + X-Real-IP.

json
// POST body
{
    "callback_url": "https://your-server.example/netts/withdraw-hook",
    "secret": "your_shared_secret_min_8_chars",
    "enabled": true
}
ПараметрТипОбов'язковийОпис
callback_urlstringТакhttp(s) URL (≤ 2048 символів), що приймає POST
secretstringТакСпільний секретний ключ (8…256 символів), що використовується для підпису кожного корисного навантаження
enabledbooleanНіУвімкнення/вимкнення доставки без видалення конфігурації. За замовчуванням true

GET повертає { callback_url, enabled, secret_set, updated_at } — сам секретний ключ ніколи не повертається у відповіді.

Корисне навантаження доставки ​

Netts надсилає POST на вашу адресу callback_url із заголовком X-Netts-Signature: base64( HMAC-SHA256( secret, raw_body ) ) та таким тілом JSON:

json
{
    "orderId": "EXAMPLEorderId0000000000000000000000000000Aa",
    "status": "completed",
    "amount": 15.0,
    "fee": 1.0,
    "net": 14.0,
    "address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "processed_at": "2026-01-01 00:00:00+00:00",
    "error_message": null
}
  • status має значення completed або failed (у разі failed заповнюється поле error_message).

Перевірка підпису ​

Підпис обчислюється на основі канонічного JSON тіла запиту: ключі відсортовані, пробіли відсутні (separators=(",", ":")). Обчисліть його так само і порівняйте.

python
import hmac, hashlib, base64, json

def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = base64.b64encode(
        hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
    ).decode()
    return hmac.compare_digest(expected, signature_header)

# Flask example: verify against the EXACT bytes received, then parse.
# if verify(request.get_data(), request.headers["X-Netts-Signature"], SECRET): ...

Завжди перевіряйте підпис за вихідними отриманими байтами. Якщо ви повторно серіалізуєте розібраний JSON, відтворіть канонічну форму: json.dumps(payload, ensure_ascii=False, separators=(",",":"), sort_keys=True).

Гарантії доставки ​

  • Відповідайте кодом HTTP 2xx для підтвердження. Будь-яка інша відповідь (або тайм-аут) вважається невдалою спробою.
  • До 3 спроб на замовлення у межах 21-хвилинного вікна з моменту створення замовлення (інтервал повторних спроб ≈ 5 хвилин). Після цього спроби доставки припиняються — використовуйте ендпойнт статусу.
  • Доставки дедуплікуються: кожне замовлення успішно доставляється не більше одного разу.
  • Зробіть ваш обробник ідемпотентним за полем orderId.

Відповіді з помилками ​

Помилка автентифікації (401) ​

json
{ "detail": { "code": -1, "msg": "Invalid API key or IP not in whitelist" } }

Недостатньо коштів на балансі (403) ​

json
{ "detail": { "code": 1004, "status": "failed", "msg": "Insufficient balance: 2.0 < 15 TRX" } }

Існує незавершене виведення (409) ​

Ви можете мати лише одне активне виведення одночасно на власному балансі. Зачекайте, поки поточне не буде оброблено.

json
{ "detail": { "code": 4090, "status": "failed", "msg": "You have a pending withdrawal. Wait until it is processed." } }

Помилка валідації (400) ​

json
{ "detail": { "code": 5004, "status": "failed", "msg": "Minimum withdrawal is 3 TRX" } }

Довідник кодів помилок ​

КодОписСтатус HTTP
10000Прийнято (виведення в черзі) / Завершено (ендпойнт статусу)202 / 200
10001В очікуванні — у черзі або відправляється (ендпойнт статусу)200
208Дубль уже прийнятого запиту — кешована відповідь208
-Той самий запит ще обробляється (поки що не повторюйте)409
4090У вас уже є активне виведення в обробці409
-1Недійсний API-ключ / IP не з білого списку, або замовлення не знайдено401 / 404
1004Недостатній баланс403
5004Помилка валідації (сума < 3, комісія ≥ суми, некоректна адреса, неправильний ключ ідемпотентності)400
5003Виведення не вдалося / сервіс недоступний200 (статус) / 503
5000Внутрішня помилка сервера500

Обмеження швидкості (Rate Limits) ​

Обмежується для кожного API-ключа (заголовок X-API-KEY):

ПеріодЛіміт
1 секунда5 запитів
1 хвилина150 запитів

Перевищено ліміт запитів (429) ​

json
{ "message": "API rate limit exceeded" }

Ідемпотентність ​

Надсилайте необов'язковий заголовок X-Idempotency-Key, щоб випадковий повтор не створив друге виведення — початкова відповідь повертається з кодом HTTP 208. Якщо ви не передаєте заголовок, сервер генерує ключ автоматично на основі параметрів вашого запиту протягом короткого проміжку часу. Цей ключ також є вашим orderId.

Як сформувати ключ ​

Ключ — це base64url( HMAC-SHA256( secret, message ) ) із видаленим заповненням = — URL-безпечний рядок із 43 символів, де:

  • secret = ваш API-ключ (X-API-KEY);
  • message = поля, об'єднані символом : — address:amount:nonce.

nonce — це будь-яке значення, яке є стабільним під час повторних спроб того самого логічного замовлення, але різним для різних замовлень — наприклад, UUID, який ви зберігаєте для цього замовлення, або приблизний часовий інтервал. Генеруйте ключ один раз для кожного замовлення та надсилайте точно те саме значення під час кожної повторної спроби.

python
import hmac, hashlib, base64, time

def make_idempotency_key(api_key, address, amount, nonce=None):
    if nonce is None:
        nonce = str(int(time.time() // 2))   # 2-second bucket; or your own order UUID
    message = f"{address}:{amount}:{nonce}"
    digest = hmac.new(api_key.encode(), message.encode(), hashlib.sha256).digest()
    return base64.urlsafe_b64encode(digest).decode().rstrip("=")  # 43-char URL-safe

Валідація. Наданий X-Idempotency-Key повинен містити від 16 до 64 символів із набору A–Z a–z 0–9 + / = _ -. Некоректний або занадто довгий ключ відхиляється з кодом HTTP 400 (code 5004).

Код статусуЗначення
202Прийнято (перший запит)
208Уже прийнято — повернуто кешовану відповідь (без повторного виведення)
409Той самий запит наразі обробляється — зачекайте, не повторюйте запит зараз

Повторення після помилки. Кешуються лише прийняті результати. Якщо попередня спроба завершилася помилкою (наприклад, недостатньо коштів, помилка валідації), ви можете безпечно повторити запит із тим самим ключем — спроба буде виконана знову замість повернення старої помилки. Доки спроба все ще виконується, ви отримуватимете 409; зачекайте та повторіть спробу.

Примітки ​

  • Асинхронна виплата. Відповідь завжди є підтвердженням зі статусом pending; TRX відправляються фоновим процесом бекенда, зазвичай протягом ~5 хвилин. Для отримання результату використовуйте ендпойнт статусу або webhook.
  • Баланс резервується миттєво, коли замовлення прийнято (а не тоді, коли TRX остаточно відправлено).
  • Мінімум: 3 TRX. Комісія: 1 TRX (або 2 TRX з параметром sub_and_robot_out), утримується від валової суми amount; отримувач отримує net = amount − fee.
  • Одне активне виведення за раз на власному балансі (code 4090).
  • Субкористувачі виводять кошти так само, як і звичайні користувачі — той самий ендпойнт POST /apiv2/withdraw, ті самі правила, але автентифікація відбувається за допомогою власного API-ключа субкористувача. Субкористувач виводить власний баланс на будь-яку вказану address. Окремого ендпойнта для субкористувачів немає.
  • orderId — це URL-безпечний рядок із 43 символів; передавайте його як є в URL перевірки статусу (кодування не потрібне).
  • Webhooks: прив'язані до користувача, підписані за допомогою X-Netts-Signature; до 3 спроб протягом 21-хвилинного вікна. Налаштовуються через POST /apiv2/withdraw/webhook.