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

POST /apiv2/order1h

Создание заказа на аренду Energy на 1 час через нескольких поставщиков энергии с автоматическим переключением при сбоях.

URL эндпоинта

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

Заголовки запроса

ЗаголовокОбязательныйОписание
Content-TypeДаapplication/json
X-API-KEYДаВаш API-ключ из панели управления Netts
X-Real-IPДаIP-адрес из вашего белого списка

Тело запроса

json
{
    "amount": 131000,
    "receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}

Параметры запроса

ПараметрТипОбязательныйОписание
amountintegerДаКоличество Energy для аренды (минимум: 61000, максимум: 3000000)
receiveAddressstringДаTRON-адрес, который получит энергию (формат TRC-20)

Выбор поставщика

API автоматически выбирает оптимального поставщика энергии на основе следующих критериев:

  • Экономическая эффективность — всегда находит самую низкую доступную цену
  • Доступность — гарантирует наличие достаточных резервов энергии
  • Надежность — использует поставщиков с высокими показателями успешности
  • Скорость — отдает приоритет наименьшему времени доставки

Примеры

cURL

bash
curl -X POST https://netts.io/apiv2/order1h \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_api_key" \
  -H "X-Real-IP: your_whitelisted_ip" \
  -d '{
    "amount": 131000,
    "receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
  }'

Python

python
import requests

url = "https://netts.io/apiv2/order1h"
headers = {
    "Content-Type": "application/json",
    "X-API-KEY": "your_api_key",
    "X-Real-IP": "your_whitelisted_ip"
}

payload = {
    "amount": 131000,
    "receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}

response = requests.post(url, headers=headers, json=payload)
data = response.json()

if response.status_code == 200:
    detail = data.get('detail', {})
    order_data = detail.get('data', {})
    print(f"Order ID: {order_data.get('orderId')}")
    print(f"Transaction Hash: {order_data.get('hash')}")
    print(f"Energy Delivered: {order_data.get('energy')}")
    print(f"Cost: {order_data.get('paidTRX')} TRX")
    print(f"Delegate Address: {order_data.get('delegateAddress')}")
else:
    error_detail = data.get('detail', data)
    print(f"Error Code: {error_detail.get('code', 'N/A')}")
    print(f"Error Message: {error_detail.get('msg', error_detail)}")

Ответ

Успешный ответ (200 OK)

json
{
    "detail": {
        "code": 10000,
        "msg": "Successful, 2.23 TRX deducted",
        "data": {
            "orderId": "1H123456",
            "paidTRX": 2.23,
            "hash": "a1b2c3d4e5f6789...",
            "delegateAddress": "TDelegatePoolAddress...",
            "energy": 131050
        }
    }
}

Поля ответа

ПолеТипОписание
detail.codeintegerВсегда 10000 для успешных заказов
detail.msgstringСообщение об успехе с указанием списанной суммы
detail.data.orderIdstringЕдиный идентификатор заказа (формат: 1H{request_id})
detail.data.paidTRXnumberОбщая стоимость в TRX (включает комиссию за активацию, если адрес не был активирован)
detail.data.hashstring | nullХеш транзакции. Поле присутствует всегда, но может быть пустым — некоторые поставщики возвращают хеш не сразу. Используйте /apiv2/order_check через 1 минуту, чтобы получить хеш
detail.data.delegateAddressstringАдрес пула, делегировавшего энергию
detail.data.energyintegerКоличество Energy + буфер (обычно +50)

Ответы с ошибками

Ошибка аутентификации (401)

json
{
    "detail": "Invalid API key or IP not in whitelist"
}

Недостаточный баланс (403)

json
{
    "code": 1004,
    "msg": "Insufficient funds. Required: 2.23 TRX, Available: 1.50 TRX"
}

Сервис недоступен (503)

json
{
    "code": 5003,
    "msg": "Service temporarily unavailable. All energy providers are currently unavailable."
}

Ошибки поставщиков (503)

json
{
    "code": 5001,
    "msg": "Energy provider temporarily unavailable"
}
json
{
    "code": 5002,
    "msg": "Energy provider temporarily unavailable"
}
json
{
    "code": 5004,
    "msg": "Energy provider requires higher minimum amount"
}

Внутренняя ошибка сервера (500)

json
{
    "code": 5000,
    "msg": "Internal server error occurred"
}

Справочник кодов ошибок

КодОписаниеHTTP-статус
10000Успешно200
10000Успешно (кэшированный ответ)208
-Повторный запрос все еще обрабатывается409
1004Недостаточный баланс403
5000Внутренняя ошибка сервера500
5001Поставщик энергии недоступен503
5002Поставщик энергии недоступен503
5003Сервис энергии недоступен503
5004Не достигнут минимум поставщика энергии503

Ограничения частоты запросов

Для этого эндпоинта действуют следующие ограничения частоты запросов (на один IP-адрес):

ПериодЛимитОписание
1 секунда50 запросовМаксимум 50 запросов в секунду

Заголовки Rate Limit

http
RateLimit-Limit: 50
RateLimit-Remaining: 49
RateLimit-Reset: 1
X-RateLimit-Limit-Second: 50
X-RateLimit-Remaining-Second: 49

Превышение лимита запросов (429)

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

Идемпотентность

API поддерживает идемпотентность для предотвращения повторной обработки заказов. При отправке нескольких одинаковых запросов система гарантирует, что заказ будет обработан только один раз.

Как работает идемпотентность

Уникальность запроса определяется комбинацией следующих параметров:

  • Временная метка запроса (окно в 1 секунду)
  • Количество энергии
  • Адрес получателя
  • API-ключ

Каждому запросу выделяется окно уникальности длительностью 1 секунда. Для защиты системы от злоупотреблений и обеспечения корректной обработки запросы с идентичными параметрами нельзя отправлять чаще одного раза в секунду.

Текущее поведение: Система автоматически защищает клиентов от ошибочных повторных попыток заказа уже запрошенной энергии. Если вы случайно отправите один и тот же запрос дважды, средства не будут списаны повторно.

Передача собственного ключа

Вы можете взять управление идемпотентностью в свои руки, передавая заголовок X-Idempotency-Key. При его наличии только это значение определяет, является ли запрос повторным, а автоматическая комбинация выше не используется. При его отсутствии ничего не меняется — сервер формирует ключ за вас.

ЗаголовокX-Idempotency-Key
ФорматРовно 64 шестнадцатеричных символа в нижнем регистре — дайджест SHA-256
Срок жизни24 часа с момента первого запроса с этим ключом
Область действияВаш аккаунт. Одно и то же значение, отправленное другим аккаунтом, никогда не вернет ваш результат

Ключ любого другого формата — UUID с дефисами, base64, шестнадцатеричные символы в верхнем регистре — отклоняется с кодом 400 до размещения заказа и до списания средств:

json
{
    "detail": "Invalid idempotency key format. Must be 64-character hexadecimal string."
}

Формат отличается от других эндпоинтов. /apiv2/withdraw, /apiv2/bandwidth и оркестратор принимают ключ base64 длиной от 16 до 64 символов. Этот эндпоинт принимает только 64-значный hex-дайджест, поэтому код генерации ключа, скопированный из тех эндпоинтов, вернет здесь 400.

Как сформировать ключ

Сформируйте его на основе вашего API-ключа. Это сделает значение уникальным для вашего аккаунта, воспроизводимым при повторной попытке и невозможным для подбора кем-либо другим:

python
import hashlib
import hmac

def make_idempotency_key(api_key: str, address: str, amount: int, nonce: str) -> str:
    message = f"{address}:{amount}:{nonce}"
    return hmac.new(api_key.encode(), message.encode(), hashlib.sha256).hexdigest()

Значение nonce привязано к заказу, а не к запросу. Задайте его один раз при создании заказа на вашей стороне и передавайте одно и то же значение при каждой отправке этого заказа — как при первой попытке, так и при каждом повторе. Генерация нового значения внутри функции отправки (str(uuid.uuid4()) при каждом вызове) дает каждой попытке свой ключ, поэтому повтор после таймаута будет принят как второй заказ и списан повторно. Самый простой и правильный выбор — идентификатор заказа, который у вас уже есть: он существует до первой попытки и сохраняется при перезапуске вашего процесса.

python
# один раз, когда заказ создается в вашей системе
order = create_order(address="TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE", amount=131000)

# при первой попытке и при каждом повторе — одни и те же три входных параметра, один и тот же ключ
key = make_idempotency_key(API_KEY, order.address, order.amount, order.id)

headers = {
    "Content-Type": "application/json",
    "X-API-KEY": API_KEY,
    "X-Idempotency-Key": key,
}

Ключ живет 24 часа. После этого тот же nonce снова становится свободным и начинает новый заказ.

Не используйте значения, к которым может прийти кто-то еще — 64 нуля, дайджест фиксированного слова. Ключи разделяют единое пространство между аккаунтами. Такая коллизия никогда не раскроет заказ другого аккаунта, но ваш запрос будет отклонен с кодом 409 до истечения срока действия их ключа, что совсем не тот ответ, который вы ожидаете получить во время повторной попытки.

Размещение двух идентичных заказов

Иногда вам действительно нужно создать два одинаковых заказа — одно и то же количество энергии на один и тот же адрес друг за другом. Автоматический ключ не может отличить эту ситуацию от повторной попытки: два запроса идентичны байт в байт, и единственное, что их разделяет, — это момент их поступления.

Без собственного ключа результат зависит от интервала между ними:

Интервал между двумя запросамиЧто происходит
В пределах одного 1-секундного окнаВторой запрос принимается за повтор. Он не выполняется: вы получаете 208 и ответ первого заказа, включая orderId. Средства за него не списываются
С интервалом более секундыДва разных ключа — оба заказа размещаются и оба оплачиваются

Поэтому, если вы полагаетесь на автоматический ключ, выдерживайте паузу более одной секунды между двумя одинаковыми заказами и проверяйте код состояния: 208 означает, что только что отправленный вами заказ не был размещен.

Пауза — это обходное решение, а не исправление. Она разделяет каждый запрос, включая те, которые вы вовсе не собирались повторять: повтор после таймаута, двойной клик, сообщение, повторно доставленное из вашей очереди. Они также приходят позже окна, поэтому размещаются как отдельные заказы и списываются отдельно. Таймаут ответа этого эндпоинта составляет 10 секунд, что заведомо выходит за пределы окна: автоматический ключ не защищает повтор, следующий за таймаутом.

Ваш собственный ключ исключает догадки, поскольку решение переносится на единственную сторону, которой известен правильный ответ:

Что вы делаетеЧто вы отправляетеРезультат
Второй, действительно новый заказНовый nonceНовый ключ — заказ размещается
Повторная попытка заказа, результат которого неизвестенnonce первой попыткиТот же ключ — 208, исходный ответ, никакого повторного списания

Вторая строка — причина существования этого заголовка, и именно здесь реализации чаще всего допускают ошибку: см. примечание в разделе Как сформировать ключ.

Коды состояния HTTP для повторяющихся запросов

Код состоянияНазваниеОписание
200OKЗаказ успешно обработан (первый запрос)
208Already ReportedЗаказ уже был обработан, возвращается кэшированный ответ
409ConflictЗапрос в данный момент обрабатывается, не повторяйте попытку

Повторный запрос — уже обработан (208)

При получении повторного запроса для уже выполненного заказа:

json
{
    "detail": {
        "code": 10000,
        "msg": "Successful, 2.54 TRX deducted",
        "data": {
            "hash": "9e4c20e21e01e4c39b21b670d1ea1fc1e4b0de94d8fbd4c190d5378ba911dfae",
            "energy": 65050,
            "orderId": "1H70bcc7962a",
            "paidTRX": 2.535,
            "delegateAddress": "TNp5gsJhBmZFXgCdgjMgr8pEZ8fHgXUHDq"
        }
    },
    "idempotency": {
        "status": "completed",
        "cached": true,
        "original_created_at": "2025-12-03T10:34:49.104896"
    }
}

Тело ответа идентично исходному успешному ответу, с добавлением объекта idempotency, указывающего на то, что это кэшированный ответ.

Повторный запрос — все еще обрабатывается (409)

Если повторный запрос поступает в то время, когда исходный все еще обрабатывается:

json
{
    "success": false,
    "error": "duplicate_request_processing",
    "message": "This request is currently being processed. Please wait and do not retry.",
    "idempotency_key": "b9e67b2412d33c92...",
    "retry_after_seconds": 3
}

Рекомендация: Подождите указанное количество retry_after_seconds перед проверкой статуса заказа.

Рекомендации

  • Не отправляйте параллельные запросы с одинаковыми параметрами — дождитесь каждого ответа
  • Используйте новый nonce для каждого нового заказа и nonce первой попытки для каждого ее повтора
  • Никогда не пересоздавайте nonce в момент отправки — повтор должен воспроизводить ключ первой попытки, а не создавать новый
  • Обрабатывайте ответы 409 ожиданием, а не немедленной повторной попыткой
  • Проверяйте поле idempotency.cached, чтобы выявлять кэшированные ответы — 208 означает, что только что отправленный вами заказ не был размещен

Примечания

  • Energy доставляется мгновенно после успешного заказа (обычно в течение 0.5–10 секунд)
  • Таймаут ответа API: максимум 10 секунд, обычно ответ занимает до 2 секунд
  • Активация адреса: если адрес получателя не активирован, Netts активирует его по себестоимости
  • Задержка активации: для неактивированных адресов ответ API может занять до 6 секунд из-за процесса активации
  • Заказы обрабатываются 24/7 с автоматическим переключением поставщиков при сбоях
  • Минимальное количество Energy: 61 000 единиц
  • Максимальное количество Energy: 3 000 000 единиц на заказ
  • Буфер Energy: +50 единиц добавляются автоматически для компенсации поставщика (бесплатно)
  • Хеш транзакции: поле присутствует всегда, но может быть пустым, если поставщик возвращает его не сразу. Чтобы получить хеш, вызовите /apiv2/order_check не ранее чем через 1 минуту после размещения заказа
  • Выбор поставщика: автоматический на основе стоимости и доступности
  • Формат ID заказа: 1H{request_id} для единого отслеживания
  • Ценообразование: динамическое в зависимости от времени суток и количества энергии
  • Длительность: фиксированная 1 час (3600 секунд)
  • Ограничение частоты запросов: 50 запросов в секунду на один IP-адрес