POST /apiv2/bandwidth
Аренда TRON Bandwidth и делегирование его на адрес получателя на фиксированный период (5 минут или 1 час).
⚠️ Уровни доступа.
- Аккредитованные аккаунты арендуют любой объем (до 5000) в пределах размера пула и максимальных лимитов, с поддержкой нескольких параллельных заказов. Аккредитация предоставляется поддержкой Netts.
- Без аккредитации можно арендовать 400 единиц один раз — следующий заказ разрешен только после завершения предыдущей аренды. Запросы на объем, отличный от 400, или второй заказ при активном первом отклоняются.
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 )) # стабилен для повторных попыток в окне 2 с; или ваш собственный 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" ) )
# Сгенерируйте ОДИН РАЗ на заказ и отправляйте то же самое значение при каждом повторе.
nonce = str(int(time.time() // 2)) # корзина 2 с; или ваш собственный 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"ID заказа: {d['orderId']}")
print(f"Хеши: {d['hash']}") # массив хешей транзакций делегирования
print(f"Bandwidth: {d['bandwidth']} на {d['period']}")
print(f"Стоимость: {d['paidTRX']} TRX")
else:
print(f"Код: {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"
}
}
}Успех — отправлен TRX вместо Bandwidth (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)
Возвращается, когда заказ асинхронно передается внешнему провайдеру. Опрашивайте эндпоинт статуса (ниже), используя 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… (5m) / B1H… (1h) — используйте его для эндпоинта статуса |
| 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 | — |
Эндпоинт отзыва
Добровольный отзыв (undelegate) Bandwidth по одному из ваших делегированных заказов до истечения его периода. Bandwidth отзывается автоматически, и возвращается хеш транзакции.
POST https://netts.io/apiv2/bandwidth/reclaim/{orderId}Заголовки: X-API-KEY + X-Real-IP (заказ должен принадлежать аутентифицированному пользователю).
| Состояние заказа | HTTP | code | status | Результат |
|---|---|---|---|---|
| Делегирован → отозван сейчас | 200 | 10004 | reclaimed | reclaimHash (хеши транзакций undelegate) |
| Уже отозван | 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..." # orderId из вашего ответа на запрос аренды
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"Отозвано: {detail['data']['reclaimHash']} ({detail['msg']})")
else:
print(f"Код {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 отозван (добровольный undelegate) — возвращен reclaimHash | 200 |
- | Дублирующий запрос все еще обрабатывается | 409 |
-1 | Неверный API-ключ / IP не в белом списке | 401 |
1004 | Недостаточный баланс | 403 |
1005 | Нет адреса плательщика для пользователя | 400 |
5004 | Недопустимое количество/период (валидация) | 400 |
5005 | Нечего отзывать (заказ не в состоянии делегирования) | 400 |
5007 | Без аккредитации — только одна аренда одновременно; предыдущий заказ все еще активен (дождитесь окончания) | 503 |
5008 | Без аккредитации — разрешены заказы только на 400 единиц; для больших объемов требуется аккредитация | 503 |
5003 | Ошибка делегирования Bandwidth / сервис недоступен | 503 |
5000 | Внутренняя ошибка сервера | 500 |
Лимиты запросов (Rate Limits)
| Период | Лимит | Описание |
|---|---|---|
| 1 секунда | 50 запросов | Максимум 50 запросов в секунду на IP |
Превышен лимит запросов (429)
{ "message": "API rate limit exceeded" }Идемпотентность
Передавайте опциональный заголовок X-Idempotency-Key, чтобы случайный повтор не создал второй заказ — исходный ответ возвращается с HTTP 208. Если вы не передаете заголовок, сервер автоматически генерирует ключ на основе параметров запроса в пределах короткого временного окна.
Как сформировать ключ
Ключ представляет собой base64( HMAC-SHA256( secret, message ) ) — строку base64 длиной 44 символа, где:
- secret = ваш API-ключ (
X-API-KEY); - message = поля, объединенные через
:—receiveAddress:amount:period:nonce.
nonce — это любое значение, которое не меняется при повторных попытках одного и того же логического заказа, но различается между разными заказами — например, UUID, который вы сохраняете для этого заказа, или округленный таймстемп. Сгенерируйте ключ один раз на заказ и отправляйте точно такое же значение при каждой повторной попытке.
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 секунды; или ваш собственный UUID заказа
message = f"{receive_address}:{amount}:{period}:{nonce}"
digest = hmac.new(api_key.encode(), message.encode(), hashlib.sha256).digest()
return base64.b64encode(digest).decode() # base64 из 44 символов# затем передайте его в качестве заголовка:
-H "X-Idempotency-Key: <base64_key>"Включение period в сообщение крайне важно: аренда на один и тот же адрес на 5m и на 1h — это разные заказы, и они должны давать разные ключи.
Валидация. Передаваемый
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; подождите и повторите.
Примечания
- Уровни доступа: аккредитованные аккаунты арендуют любой объем в пределах лимитов пула/максимума с параллельными заказами; без аккредитации — 400 единиц один раз (следующий заказ только после завершения предыдущей аренды). Свяжитесь с поддержкой 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 секунды.