POST /apiv2/bandwidth
Аренда bandwidth в сети TRON и её делегирование на адрес получателя на фиксированный период: 5 минут, а для аккредитованных аккаунтов — 1 час.
⚠️ Уровни доступа.
- Аккредитованные аккаунты могут арендовать любой объём (до 5000) на 5 минут или 1 час в пределах размера пула и максимальных лимитов, с поддержкой нескольких параллельных заказов. Аккредитация предоставляется поддержкой Netts.
- Без аккредитации можно арендовать только 400 единиц на 5 минут, один раз — следующий заказ разрешён только после окончания предыдущей аренды. Запросы на объём, отличный от 400, на 1 час или второй заказ при активном первом будут отклонены.
URL эндпоинта
POST https://netts.io/apiv2/bandwidthЗаголовки запроса
| Заголовок | Обязательный | Описание |
|---|---|---|
| Content-Type | Да | application/json |
| X-API-KEY | Да | Ваш API-ключ из панели управления Netts |
| X-Real-IP | Да | IP-адрес из вашего белого списка |
| X-Idempotency-Key | Нет | Необязательный сгенерированный клиентом ключ (base64) для безопасного повтора запроса без дублирования заказа. Если не передан, сервер сгенерирует его автоматически |
Тело запроса
{
"amount": 1500,
"receiveAddress": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"period": "5m"
}Параметры
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
| amount | integer | Да | Количество единиц Bandwidth для аренды (минимум: 400, максимум: 5000) |
| receiveAddress | string | Да | Адрес TRON, который получит bandwidth (T…, 34 символа, base58) |
| period | string | Да | Длительность аренды: "5m" (5 минут) или "1h" (1 час, только для аккредитованных аккаунтов) |
| trx_send | boolean | Нет | Гарантированная транзакция: если bandwidth недоступна, на адрес вместо этого отправляется TRX, чтобы транзакция всё равно прошла. Работает только при amount = 400 (в остальных случаях игнорируется). По умолчанию false |
| check | boolean | Нет | Если true и у получателя уже есть более 400 bandwidth, заказ не делегируется и средства не списываются (статус enough). По умолчанию false |
| test | boolean | Нет | Тестовый запуск. Если true, имитируется полный цикл выполнения заказа — ответ сообщает результат, который был бы получен, и цену, которая была бы списана — без каких-либо действий в блокчейне и без списания средств. По умолчанию false |
Примеры запросов
Приведённые ниже примеры также формируют и отправляют заголовок
X-Idempotency-Key, чтобы случайный повтор не создал второй заказ. Полные правила см. в разделе Идемпотентность.
cURL
API_KEY="your_api_key"
ADDR="TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AMOUNT=1500
PERIOD="5m"
NONCE=$(( $(date +%s) / 2 )) # stable for retries within a 2s window; or your own order UUID
# X-Idempotency-Key = base64( HMAC-SHA256( API_KEY, "addr:amount:period:nonce" ) )
IDEMP=$(printf '%s' "${ADDR}:${AMOUNT}:${PERIOD}:${NONCE}" \
| openssl dgst -sha256 -hmac "$API_KEY" -binary | base64)
curl -X POST https://netts.io/apiv2/bandwidth \
-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, \"receiveAddress\": \"$ADDR\", \"period\": \"$PERIOD\"}"Python
import time, hmac, hashlib, base64, requests
API_KEY = "your_api_key"
url = "https://netts.io/apiv2/bandwidth"
payload = {
"amount": 1500,
"receiveAddress": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"period": "5m",
}
# X-Idempotency-Key = base64( HMAC-SHA256( API_KEY, "addr:amount:period:nonce" ) )
# 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['receiveAddress']}:{payload['amount']}:{payload['period']}:{nonce}"
idem_key = base64.b64encode(
hmac.new(API_KEY.encode(), message.encode(), hashlib.sha256).digest()
).decode()
headers = {
"Content-Type": "application/json",
"X-API-KEY": API_KEY,
"X-Real-IP": "your_whitelisted_ip",
"X-Idempotency-Key": idem_key,
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
detail = data.get("detail", {})
if response.status_code == 200 and detail.get("status") == "completed":
d = detail["data"]
print(f"Order ID: {d['orderId']}")
print(f"Hashes: {d['hash']}") # array of delegation tx hashes
print(f"Bandwidth: {d['bandwidth']} for {d['period']}")
print(f"Cost: {d['paidTRX']} TRX")
else:
print(f"Code: {detail.get('code')} | {detail.get('msg', detail)}")Полный пример клиента (Python + cURL) включён в пакет сервиса (handler_bandwidth/doc/client_example/).
Ответ
Успешно — bandwidth делегирована (200 OK)
{
"detail": {
"code": 10000,
"status": "completed",
"msg": "Successful",
"data": {
"orderId": "B5M<key14>",
"paidTRX": "<amount charged in TRX>",
"fulfilledBy": "bandwidth",
"hash": ["a1b2c3...", "d4e5f6..."],
"bandwidth": 1500,
"period": "5m"
}
}
}Успешно — вместо bandwidth отправлены TRX (200 OK, только amount=400 + trx_send=true)
Когда в пуле нет bandwidth и включён параметр trx_send, на адрес отправляются TRX, чтобы транзакция всё равно прошла. В этом случае применяется фиксированная оплата независимо от запрошенного периода.
{
"detail": {
"code": 10000,
"status": "completed",
"msg": "Successful (sent TRX, bandwidth unavailable)",
"data": {
"orderId": "B5M<key14>",
"paidTRX": "<amount charged in TRX>",
"fulfilledBy": "trx",
"trxSendHash": ["<txid>"],
"hash": [],
"bandwidth": 400,
"period": "5m"
}
}
}Уже достаточно — средства не списаны (200 OK, только с check=true)
{
"detail": {
"code": 10002,
"status": "enough",
"msg": "enough band for 1 transfer",
"data": { "orderId": "B5M<key14>", "paidTRX": 0, "bandwidth": 400, "period": "5m" }
}
}В обработке — внешний провайдер (202 Accepted)
Возвращается, когда заказ асинхронно передан внешнему поставщику. Опрашивайте status endpoint (ниже), используя orderId, пока он не завершится.
{
"detail": {
"code": 10001,
"status": "processing",
"msg": "Order accepted, processed by an external provider. Poll the status endpoint.",
"data": { "orderId": "B5M<key14>", "bandwidth": 1500, "period": "5m" }
}
}Тестовый запуск (200 OK, только с test=true)
Имитируется весь процесс заказа. testAction сообщает, что было бы выполнено, а wouldCostTRX — сколько было бы списано. Ничего не делегируется, TRX не отправляются, средства не списываются (paidTRX: 0).
{
"detail": {
"code": 10003,
"status": "test",
"msg": "Test run — no on-chain action, no charge",
"data": {
"orderId": "B5M<...>",
"testAction": "would_delegate",
"wouldCostTRX": "<amount that would be charged in TRX>",
"paidTRX": 0,
"bandwidth": 400,
"period": "5m",
"receiverFreeBandwidth": 600
}
}
}Значения testAction: would_delegate (bandwidth была бы делегирована), would_trx_send (нет bandwidth, amount=400 + trx_send → были бы отправлены TRX), enough (у получателя уже достаточно, при check=true) или would_error:<reason> (например, no_bandwidth, not_whitelisted).
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
| detail.code | integer | 10000 делегировано/TRX, 10002 достаточно, 10001 в обработке |
| detail.status | string | completed / enough / processing / failed |
| detail.data.orderId | string | ID заказа, формат B5M… (5м) / B1H… (1ч) — используйте его для status endpoint |
| detail.data.paidTRX | number | Списанная сумма в TRX (0 при enough) |
| detail.data.fulfilledBy | string | bandwidth (делегировано) / trx (отправлены TRX) |
| detail.data.hash | array | Хеши транзакций делегирования (до 10). Всегда массив (пустой для ветки TRX) |
| detail.data.trxSendHash | array | Хеш(и) перевода TRX, присутствует только при fulfilledBy = trx |
| detail.data.bandwidth | integer | Делегированное количество единиц Bandwidth |
| detail.data.period | string | Период аренды (5m / 1h) |
Эндпоинт статуса
GET https://netts.io/apiv2/bandwidth/status/{orderId}Заголовки: X-API-KEY + X-Real-IP (заказ должен принадлежать аутентифицированному пользователю).
| Состояние заказа | HTTP | code | status |
|---|---|---|---|
| Завершён | 200 | 10000 | completed (с hash / trxSendHash) |
| В процессе | 200 | 10001 | processing |
| Уже достаточно | 200 | 10002 | enough |
| Ошибка | 200 | 5003 | failed |
| Не найден / не ваш | 404 | -1 | — |
Эндпоинт отзыва
Добровольный отзыв (анделегирование) bandwidth одного из ваших делегированных заказов до истечения его срока действия. Bandwidth возвращается автоматически, и возвращается хеш транзакции.
POST https://netts.io/apiv2/bandwidth/reclaim/{orderId}Заголовки: X-API-KEY + X-Real-IP (заказ должен принадлежать аутентифицированному пользователю).
| Состояние заказа | HTTP | code | status | Результат |
|---|---|---|---|---|
| Делегирован → отозван сейчас | 200 | 10004 | reclaimed | reclaimHash (хеши транзакций анделегирования) |
| Уже отозван | 200 | 10004 | reclaimed | reclaimHash + сообщение "already reclaimed" |
| Не в состоянии делегирования (нечего отзывать) | 400 | 5005 | failed | — |
| Отзыв ещё не завершён | 503 | 5003 | failed | повторите попытку позже |
| Не найден / не ваш | 404 | -1 | — | — |
curl -X POST https://netts.io/apiv2/bandwidth/reclaim/B5M<...> \
-H "X-API-KEY: your_api_key" -H "X-Real-IP: your_whitelisted_ip"{
"detail": {
"code": 10004,
"status": "reclaimed",
"msg": "Bandwidth reclaimed",
"data": { "orderId": "B5M<...>", "reclaimHash": ["<txid>"] }
}
}import requests
order_id = "B5M..." # the orderId from your rental response
url = f"https://netts.io/apiv2/bandwidth/reclaim/{order_id}"
headers = {"X-API-KEY": "your_api_key", "X-Real-IP": "your_whitelisted_ip"}
resp = requests.post(url, headers=headers)
detail = resp.json()["detail"]
if resp.status_code == 200 and detail["status"] == "reclaimed":
print(f"Reclaimed: {detail['data']['reclaimHash']} ({detail['msg']})")
else:
print(f"Code {detail.get('code')}: {detail.get('msg', detail)}")Стоимость аренды не возвращается при добровольном досрочном отзыве — отзыв лишь возвращает делегированную bandwidth обратно в пул раньше окончания периода.
Ответы с ошибками
Ошибка аутентификации (401)
{ "detail": { "code": -1, "msg": "Invalid API key or IP not in whitelist" } }Недостаточно средств (403)
{ "detail": { "code": 1004, "status": "failed", "msg": "Insufficient funds" } }Ошибка валидации (400)
{ "detail": { "code": 5004, "status": "failed", "msg": "Bandwidth amount out of range (400..5000)" } }Ошибка делегирования / Сервис недоступен (503)
{ "detail": { "code": 5003, "status": "failed", "msg": "Bandwidth delegation failed" } }Справочник кодов ошибок
| Код | Описание | HTTP-статус |
|---|---|---|
10000 | Успешно (делегировано или отправлены TRX) | 200 |
10000 | Успешно (кэшированный ответ) | 208 |
10001 | Принято, обрабатывается внешним провайдером | 202 |
10002 | У получателя уже достаточно bandwidth (средства не списаны) | 200 |
10003 | Тестовый запуск — предварительный просмотр результата и цены, средства не списаны (test=true) | 200 |
10004 | Bandwidth отозвана (добровольное анделегирование) — возвращён reclaimHash | 200 |
- | Дублирующий запрос всё ещё обрабатывается | 409 |
-1 | Недействительный API-ключ / IP не в белом списке | 401 |
1004 | Недостаточный баланс | 403 |
1005 | Нет адреса плательщика для пользователя | 400 |
5004 | Недопустимый объём/период (валидация) | 400 |
5005 | Нечего отзывать (заказ не находится в состоянии делегирования) | 400 |
5007 | Без аккредитации — только одна аренда единовременно; предыдущий заказ всё ещё активен (дождитесь его окончания) | 503 |
5008 | Без аккредитации — разрешены заказы только на 400 единиц на 5 минут; для больших объёмов или 1 часа требуется аккредитация | 503 |
5003 | Ошибка делегирования bandwidth / недоступно | 503 |
5000 | Внутренняя ошибка сервера | 500 |
Ограничения частоты запросов
| Период | Лимит | Описание |
|---|---|---|
| 1 секунда | 50 запросов | Максимум 50 запросов в секунду на один IP |
Превышен лимит запросов (429)
{ "message": "API rate limit exceeded" }Идемпотентность
Отправляйте необязательный заголовок X-Idempotency-Key, чтобы случайный повтор не создал второй заказ — исходный ответ возвращается со статусом HTTP 208. Если вы не передаёте заголовок, сервер автоматически формирует ключ на основе параметров вашего запроса в пределах короткого временного окна.
Как формировать ключ
Ключ представляет собой base64( HMAC-SHA256( secret, message ) ) — 44-символьную строку base64, где:
- secret = ваш API-ключ (
X-API-KEY); - message = поля, объединённые через
:—receiveAddress:amount:period:nonce.
nonce — это любое значение, которое является неизменным при повторных попытках одного и того же логического заказа, но отличается для разных заказов — например, UUID, который вы сохраняете для этого заказа, или грубый временной интервал (timestamp bucket). Генерируйте ключ один раз на заказ и отправляйте ровно то же самое значение при каждой повторной попытке.
import hmac, hashlib, base64, time
def make_idempotency_key(api_key, receive_address, amount, period, nonce=None):
if nonce is None:
nonce = str(int(time.time() // 2)) # 2-second bucket; or your own order UUID
message = f"{receive_address}:{amount}:{period}:{nonce}"
digest = hmac.new(api_key.encode(), message.encode(), hashlib.sha256).digest()
return base64.b64encode(digest).decode() # 44-char base64# затем отправьте его в виде заголовка:
-H "X-Idempotency-Key: <base64_key>"Включение period в сообщение имеет важное значение: аренда на один и тот же адрес на 5 минут и на 1 час является разными заказами и должна порождать разные ключи.
Валидация. Переданный
X-Idempotency-Keyдолжен быть строкой base64 длиной от 16 до 64 символов (набор символовA–Z a–z 0–9 + / = _ -). Некорректный или слишком длинный ключ отклоняется с кодом HTTP 400 (code 5004).
| Код состояния | Значение |
|---|---|
| 200 | Успешно обработано (первый запрос) |
| 208 | Уже успешно обработано — возвращён кэшированный ответ (повторное списание не производится) |
| 409 | Такой же запрос обрабатывается прямо сейчас — подождите, не повторяйте запрос сразу |
Повтор после ошибки. Кэшируются только успешные результаты (
completed/enough). Если предыдущая попытка завершилась ошибкой или по таймауту (средства не были списаны), вы можете безопасно повторить попытку с тем жеX-Idempotency-Key— заказ будет выполнен заново вместо возврата старой ошибки. Пока попытка всё ещё находится в процессе выполнения, вы получите409; подождите и повторите попытку.
Постоплатные аккаунты
Аккаунты с постоплатной системой расчётов используют тот же endpoint, URL, заголовки и тело запроса, что и все остальные. Разница заключается в способе оплаты заказа:
- С вашего депозита ничего не списывается. Каждый выполненный заказ добавляется к сумме задолженности вашего аккаунта в валюте расчётов, согласованной в договоре. Вы оплачиваете её по счёту в соответствии с вашим соглашением.
- У вашего аккаунта есть кредитный лимит. Пока сумма задолженности находится в пределах лимита, заказы принимаются даже при нулевом депозите. Аренда на 5 минут и на 1 час учитывается в рамках одного и того же лимита bandwidth.
- Оплачиваются только фактически оказанные услуги: bandwidth, делегированная на адрес, или TRX, отправленные взамен (
fulfilledBy = trx). Сумма такая же, как и для предоплатных заказов. - Заказ, который был отклонён, не выполнен, тестовый запуск (
test: true) или заказ с ответомenough(check: true), ничего не стоит. - Добровольный досрочный отзыв не уменьшает сумму к оплате, аналогично предоплатным заказам.
- Уровни доступа, объёмы, периоды и все остальные правила этого эндпоинта такие же, как и для предоплатных аккаунтов.
Постоплатная система расчётов подключается Netts для аккаунта по запросу. Каждый ответ сообщает, как оплачивается заказ: значение paymentMode равно postpaid или prepaid.
Проверка цены (test: true)
{
"amount": 1000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
"period": "5m",
"test": true
}{
"detail": {
"code": 10003,
"status": "test",
"msg": "Test run — no on-chain action, no charge",
"data": {
"orderId": "B5M1a2b3c4d5e6f70",
"testAction": "would_delegate",
"wouldCostTRX": 0.7,
"paidTRX": 0,
"bandwidth": 1000,
"period": "5m",
"receiverFreeBandwidth": 600,
"paymentMode": "postpaid"
}
}
}wouldCostTRX — это сумма в TRX, которая была бы добавлена к вашей задолженности. Ничего не делегируется и не тарифицируется.
Успешный заказ
{
"detail": {
"code": 10000,
"status": "completed",
"msg": "Successful, 0.700000 TRX, postpaid",
"data": {
"orderId": "B5M0f9e8d7c6b5a41",
"paidTRX": 0.7,
"fulfilledBy": "bandwidth",
"hash": ["<txid>"],
"bandwidth": 1000,
"period": "5m",
"paymentMode": "postpaid",
"totalTRX": "0.700000"
}
}
}| Поле | Описание |
|---|---|
| paidTRX | Стоимость услуги в TRX. Для постоплатных аккаунтов она не списывается с депозита |
| paymentMode | postpaid |
| totalTRX | Точная сумма, 6 знаков после запятой |
Все остальные поля, включая ветку TRX (fulfilledBy = trx, trxSendHash), такие же, как и для предоплатных заказов.
Исчерпан кредитный лимит (402)
{
"detail": {
"code": 1004,
"msg": "Postpaid credit limit reached.",
"paymentMode": "postpaid",
"reason": "limit_reached"
}
}Заказ не выполняется и оплата не начисляется. Новые заказы снова начнут приниматься после поступления вашего платежа или увеличения лимита.
Коды ошибок постоплаты
| Код | HTTP | Описание |
|---|---|---|
1004 | 402 | Исчерпан кредитный лимит постоплаты |
5032 | 503 | Цена временно недоступна |
5034 | 503 | Биллинг временно недоступен — заказ не был принят |
5036 | 503 | Проверка кредитного лимита временно недоступна — повторите попытку позже |
Для всех приведённых выше ответов ничего не заказывается и средства не начисляются к оплате. Все остальные коды аналогичны предоплатным заказам.
Примечания
- Уровни доступа: аккредитованные аккаунты могут арендовать любой объём в рамках пула/максимальных лимитов с параллельными заказами; без аккредитации — 400 единиц на 5 минут, один раз (следующий заказ только после завершения предыдущей аренды). Для получения аккредитации обратитесь в службу поддержки Netts.
- Минимум: 400 единиц. Максимум: 5000 единиц на заказ (текущая конфигурация).
- Периоды:
5m(300 с) и1h(3600 с, только для аккредитованных аккаунтов). Bandwidth автоматически отзывается по истечении периода. - Без буфера: делегируется ровно запрошенный объём.
- hash является массивом: один заказ может порождать до 10 хешей делегирования — все они возвращаются в ответе.
- Ценообразование: оплата в TRX в зависимости от запрошенного объёма и периода; тарифы могут меняться в зависимости от времени суток. Актуальные цены уточняйте в поддержке.
- Компенсация за мелкие заказы (делегирование): для заказов менее 1000 единиц к цене добавляется фиксированная комиссия 0.372 TRX в качестве компенсации за ончейн-делегирование и возврат. Для заказов от 1000 единиц и выше данная надбавка отсутствует.
- Компенсация за отправку TRX: если заказ выполняется путём отправки TRX (
fulfilledBy = trx), вместо этого добавляется фиксированная комиссия 0.268 TRX (компенсация за ончейн-перевод TRX). - trx_send: только для
amount = 400; если нет доступной bandwidth, на адрес отправляются TRX, чтобы транзакция всё равно прошла. - check: пропускает делегирование (и списание оплаты), если у получателя уже есть более 400 bandwidth.
- Формат ID заказа:
B5M…(5 минут) /B1H…(1 час). - Таймаут ответа: до ~12 секунд при ожидании делегирования; обычно 1–2 секунды.