POST /apiv2/order1h
Створіть замовлення на 1-годинну оренду Energy через кількох постачальників Energy з автоматичним перемиканням при збоях.
URL ендпоінта
POST https://netts.io/apiv2/order1hЗаголовки запиту
| Заголовок | Обов'язковий | Опис |
|---|---|---|
| Content-Type | Так | application/json |
| X-API-KEY | Так | Ваш API-ключ із панелі керування Netts |
| X-Real-IP | Так | IP-адреса з вашого білого списку |
Тіло запиту
{
"amount": 131000,
"receiveAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"
}Параметри
| Параметр | Тип | Обов'язковий | Опис |
|---|---|---|---|
| amount | integer | Так | Кількість Energy для оренди (мінімум: 61000, максимум: 3000000) |
| receiveAddress | string | Так | TRON-адреса, яка отримає Energy (формат TRC-20) |
Вибір постачальника
API автоматично обирає оптимального постачальника Energy на основі:
- Економічної ефективності — завжди знаходить найнижчу доступну ціну
- Доступності — гарантує достатні резерви Energy
- Надійності — використовує постачальників із високим показником успішності
- Швидкості — надає пріоритет найшвидшому часу доставки
Приклади запитів
cURL
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
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)
{
"detail": {
"code": 10000,
"msg": "Successful, 2.23 TRX deducted",
"data": {
"orderId": "1H123456",
"paidTRX": 2.23,
"hash": "a1b2c3d4e5f6789...",
"delegateAddress": "TDelegatePoolAddress...",
"energy": 131050
}
}
}Поля відповіді
| Поле | Тип | Опис |
|---|---|---|
| detail.code | integer | Завжди 10000 для успішних замовлень |
| detail.msg | string | Повідомлення про успіх зі списаною сумою |
| detail.data.orderId | string | Уніфікований ID замовлення (формат: 1H{request_id}) |
| detail.data.paidTRX | number | Загальна вартість у TRX (включає комісію за активацію, якщо адреса не була активована) |
| detail.data.hash | string | null | Хеш транзакції. Поле завжди присутнє, але може бути порожнім — деякі постачальники не повертають хеш миттєво. Скористайтеся /apiv2/order_check через 1 хвилину, щоб отримати хеш |
| detail.data.delegateAddress | string | Адреса пулу, яка делегувала Energy |
| detail.data.energy | integer | Кількість Energy + буфер (зазвичай +50) |
Відповіді з помилками
Помилка автентифікації (401)
{
"detail": "Invalid API key or IP not in whitelist"
}Недостатній баланс (403)
{
"code": 1004,
"msg": "Insufficient funds. Required: 2.23 TRX, Available: 1.50 TRX"
}Сервіс недоступний (503)
{
"code": 5003,
"msg": "Service temporarily unavailable. All energy providers are currently unavailable."
}Помилки постачальника (503)
{
"code": 5001,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5002,
"msg": "Energy provider temporarily unavailable"
}{
"code": 5004,
"msg": "Energy provider requires higher minimum amount"
}Внутрішня помилка сервера (500)
{
"code": 5000,
"msg": "Internal server error occurred"
}Довідник кодів помилок
| Код | Опис | HTTP-статус |
|---|---|---|
10000 | Успіх | 200 |
10000 | Успіх (кешована відповідь) | 208 |
- | Дублікат запиту все ще обробляється | 409 |
1004 | Недостатній баланс | 403 |
5000 | Внутрішня помилка сервера | 500 |
5001 | Постачальник Energy недоступний | 503 |
5002 | Постачальник Energy недоступний | 503 |
5003 | Сервіс Energy недоступний | 503 |
5004 | Не досягнуто мінімуму постачальника Energy | 503 |
Ліміти запитів
До цього ендпоінту застосовуються такі обмеження швидкості (на IP-адресу):
| Період | Ліміт | Опис |
|---|---|---|
| 1 секунда | 50 запитів | Максимум 50 запитів на секунду |
Заголовки обмеження швидкості
RateLimit-Limit: 50
RateLimit-Remaining: 49
RateLimit-Reset: 1
X-RateLimit-Limit-Second: 50
X-RateLimit-Remaining-Second: 49Перевищено ліміт швидкості (429)
{
"message": "API rate limit exceeded"
}Ідемпотентність
API підтримує ідемпотентність для запобігання дублюванню обробки замовлень. Коли ви надсилаєте кілька однакових запитів, система гарантує, що замовлення буде оброблено лише один раз.
Як працює ідемпотентність
Унікальність запиту визначається комбінацією таких даних:
- Мітка часу запиту (вікно в 1 секунду)
- Кількість Energy
- Адреса отримувача
- API-ключ
Кожному запиту надається 1-секундне вікно унікальності. Щоб захистити систему від зловживань та забезпечити належну обробку, запити з ідентичними параметрами не можна надсилати частіше ніж один раз на секунду.
Поточна поведінка: система автоматично захищає клієнтів від помилкових повторних спроб для вже замовленої Energy. Якщо ви випадково надішлете один і той самий запит двічі, з вас не буде списано кошти повторно.
Передача власного ключа
Ви можете взяти контроль над ідемпотентністю у свої руки, надіславши заголовок X-Idempotency-Key. Коли він присутній, лише це значення визначає, чи є запит повторним, а автоматична комбінація, наведена вище, не використовується. Коли він відсутній, нічого не змінюється — сервер формує ключ за вас.
| Заголовок | X-Idempotency-Key |
| Формат | Рівно 64 шістнадцяткових символи в нижньому регістрі — хеш SHA-256 |
| Час життя | 24 години з моменту першого запиту з цим ключем |
| Область дії | Ваш акаунт. Те саме значення, надіслане іншим акаунтом, ніколи не поверне ваш результат |
Ключ будь-якого іншого формату — UUID з дефісами, base64, шістнадцяткові символи у верхньому регістрі — відхиляється з кодом 400 до розміщення замовлення та до списання будь-яких коштів:
{
"detail": "Invalid idempotency key format. Must be 64-character hexadecimal string."
}Формат відрізняється від інших ендпоінтів.
/apiv2/withdraw,/apiv2/bandwidthта оркестратор приймають ключ base64 довжиною 16–64 символи. Цей ендпоінт приймає лише 64-символьний шістнадцятковий хеш, тому код генерації ключів, скопійований з тих ендпоінтів, тут поверне 400.
Як сформувати ключ
Згенеруйте його на основі вашого API-ключа. Це робить значення унікальним для вашого акаунта, відтворюваним під час повторної спроби, і не дозволяє будь-кому іншому отримати таке саме значення:
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())під час кожного виклику) надає кожній спробі різний ключ, тому повторна спроба після таймауту буде прийнята як друге замовлення і тарифікована знову. Найпростіший правильний вибір — це ID замовлення, який у вас уже є: він існує до першої спроби та зберігається після перезапуску вашого процесу.
# один раз, коли замовлення з'являється у вашій системі
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, доки не мине термін дії їхнього ключа, що зовсім не є бажаною відповіддю посеред повторної спроби.
Розміщення двох однакових замовлень
Іноді вам дійсно потрібно розмістити одне й те саме замовлення двічі — однакову кількість Energy на одну й ту саму адресу, одне за одним. Автоматичний ключ не може відрізнити це від повторної спроби: ці два запити побайтово ідентичні, і єдине, що їх розділяє — це момент їх надходження.
Без власного ключа результат залежить від інтервалу між ними:
| Інтервал між двома запитами | Що відбувається |
|---|---|
| У межах того самого 1-секундного вікна | Другий запит вважається повтором. Він не виконується: ви отримуєте 208 і відповідь першого замовлення, включно з orderId. Кошти за нього не списуються |
| З інтервалом понад одну секунду | Два різні ключі — обидва замовлення розміщуються і за обидва списуються кошти |
Тому, якщо ви покладаєтеся на автоматичний ключ, робіть паузу понад одну секунду між двома однаковими замовленнями та перевіряйте статус-код: 208 означає, що щойно надіслане замовлення не було розміщене.
Пауза — це тимчасовий обхідний шлях, а не вирішення проблеми. Вона розділяє кожен запит, включно з тими, які ви взагалі не планували повторювати — повторна спроба після таймауту, подвійний клік, повідомлення, повторно доставлене вашою чергою. Вони також надходять пізніше за вікно унікальності, тому розміщуються як окремі замовлення й оплачуються окремо. Таймаут відповіді цього ендпоінту становить 10 секунд, що вже виходить далеко за межі вікна: автоматичний ключ не захищає повторну спробу, яка виникає після таймауту.
Власний ключ позбавляє від здогадок, оскільки рішення переноситься на єдину сторону, яка знає правильну відповідь:
| Що ви робите | Що ви надсилаєте | Результат |
|---|---|---|
| Друге, дійсно нове замовлення | Новий nonce | Новий ключ — замовлення розміщується |
| Повторна спроба замовлення, результат якого вам невідомий | nonce першої спроби | Той самий ключ — 208, початкова відповідь, повторного списання немає |
Другий рядок — це саме та причина, чому існує цей заголовок, і це місце, де в реалізаціях зазвичай припускаються помилок: дивіться примітку в розділі Як сформувати ключ.
HTTP-статус-коди для дублікатів запитів
| Статус-код | Назва | Опис |
|---|---|---|
| 200 | OK | Замовлення успішно оброблено (перший запит) |
| 208 | Already Reported | Замовлення вже було оброблено, повертається кешована відповідь |
| 409 | Conflict | Запит наразі обробляється, не повторюйте спробу |
Дублікат запиту — вже оброблено (208)
Коли надходить дублікат запиту для вже виконаного замовлення:
{
"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)
Коли дублікат запиту надходить у той час, як оригінальний запит усе ще обробляється:
{
"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}для уніфікованого відстеження - Ціноутворення: динамічне, залежно від часу доби та кількості Energy
- Тривалість: фіксована — 1 година (3600 секунд)
- Обмеження швидкості: 50 запитів на секунду на одну IP-адресу