GET /apiv2/pricing
Універсальний ендпоінт ціноутворення, який повертає ціни на всі послуги в одній відповіді з динамічними періодами часу.
Ціна може змінитися під час виконання
Ціна, яку повертає цей ендпоінт, може змінитися під час обробки замовлення. Постачальник енергії може відхилити запит на делегування, і в такому разі Netts автоматично перенаправляє замовлення наступному доступному постачальнику. Netts прагне не лише пропонувати найвигіднішу ціну, але й гарантувати надійне постачання енергії — тому замовлення може бути виконане за вищою ціною, ніж зазначена. Це стосується лише замовлень від 300 000 одиниць енергії та вище.
Рекомендовано
Це рекомендований ендпоінт ціноутворення. Він замінює застарілий ендпоінт /apiv2/prices, підтримку якого буде припинено.
URL ендпоінта
GET https://netts.io/apiv2/pricingЗаголовки запиту
| Заголовок | Обов'язковий | Опис | Значення |
|---|---|---|---|
| X-API-KEY | Так | Ваш API-ключ | string |
| X-Real-IP | Так | IP-адреса з білого списку | IP-адреса |
| X-Format | Ні | Формат відповіді (за замовчуванням: повний JSON) | now, compact, short, short1h, count |
Параметри запиту
| Параметр | Тип | За замовчуванням | Опис |
|---|---|---|---|
| services | string | all | Розділений комами фільтр послуг для включення |
Доступні послуги
| Послуга | Опис |
|---|---|
energy_1h | Ціни на делегування Energy на 1 годину |
energy_5m | Ціни на делегування Energy на 5 хвилин |
host | Тарифи на делегування Energy в Host Mode |
aml | Ціни на AML-перевірку адрес |
bandwidth | Ціни на оренду Bandwidth — за запитом: повертаються лише за явного запиту через ?services=bandwidth (не входять до стандартної відповіді) |
Приклади запитів
cURL — Повна відповідь
curl -X GET https://netts.io/apiv2/pricing \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip"cURL — Фільтрація за послугами
# Тільки ціни на energy 1h
curl -X GET "https://netts.io/apiv2/pricing?services=energy_1h" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip"
# Energy 1h + AML
curl -X GET "https://netts.io/apiv2/pricing?services=energy_1h,aml" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip"
# Тільки ціни на host
curl -X GET "https://netts.io/apiv2/pricing?services=host" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip"
# Ціни на оренду bandwidth (за запитом — має бути запитано явно)
curl -X GET "https://netts.io/apiv2/pricing?services=bandwidth" \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip"Python
import requests
url = "https://netts.io/apiv2/pricing"
headers = {
"X-API-KEY": "your_api_key",
"X-Real-IP": "your_whitelisted_ip"
}
response = requests.get(url, headers=headers)
data = response.json()
if data.get("success"):
print(f"API version: {data['version']}")
print(f"TRX/USD rate: {data['data']['trx_rate_usd']}")
services = data["data"]["services"]
for svc_name, svc_data in services.items():
pricing_type = svc_data.get("pricing_type")
print(f"\n--- {svc_name} ({pricing_type}) ---")
if pricing_type == "periodic":
for period in svc_data["periods"]:
marker = " <-- current" if period["is_current"] else ""
print(f" {period['label']}: {period['price']} {svc_data['unit']}{marker}")
elif pricing_type == "flat_rates":
for rate, price in svc_data["rates"].items():
print(f" {rate}: {price} {svc_data['unit']}")
elif pricing_type == "provider_based":
for name, info in svc_data["providers"].items():
status = "available" if info["available"] else "unavailable"
print(f" {name}: {info['price']} {svc_data['unit']} - {status}")Python — Фільтрація послуг
params = {"services": "energy_1h,aml"}
response = requests.get(url, headers=headers, params=params)Структура відповіді
Поля верхнього рівня
| Поле | Тип | Опис |
|---|---|---|
| success | boolean | true для успішних запитів |
| version | string | Версія API (наприклад, "2.1") |
| timestamp | string | Час сервера в ISO 8601 UTC |
| data | object | Корисне навантаження відповіді |
Поля Data
| Поле | Тип | Опис |
|---|---|---|
| data.trx_rate_usd | number | Поточний курс обміну TRX/USD |
| data.units_meta | object | Машинозчитувана інформація про конвертацію одиниць |
| data.services | object | Карта запитаних послуг із даними про ціноутворення |
Метадані одиниць (Units Meta)
Дозволяє клієнтам програмно конвертувати між одиницями:
{
"units_meta": {
"sun": {"base": "trx", "multiplier": 1000000},
"trx": {"base": "trx", "multiplier": 1},
"usdt": {"base": "usdt", "multiplier": 1}
}
}Щоб конвертувати з SUN у TRX: trx_price = sun_price / units_meta.sun.multiplier
Загальні поля послуг
Кожна послуга містить такі поля:
| Поле | Тип | Опис |
|---|---|---|
| unit | string | Одиниця ціни (sun, trx, usdt) |
| pricing_type | string | Як парсити цю послугу (дивіться нижче) |
| description | string | Зрозумілий для людини опис |
| cache_ttl | integer | Як часто оновлюються ці дані (секунди) |
Типи ціноутворення
Поле pricing_type повідомляє клієнтам, як парсити кожну послугу:
| Тип | Структура | Використовується у |
|---|---|---|
periodic | Масив periods[] із цінами за часовими проміжками | energy_1h, energy_5m |
flat_rates | Об'єкт rates{} з іменованими ключами тарифів | host |
provider_based | Об'єкт providers{} із даними постачальників | aml |
tiered_by_amount_and_period | tiers[] за діапазоном обсягу, кожен із periods[] | bandwidth |
Послуга: energy_1h / energy_5m
pricing_type: periodic
| Поле | Тип | Опис |
|---|---|---|
| current_period | string | Слизняк (slug) поточного активного періоду |
| periods[] | array | Усі періоди ціноутворення (динамічні, завантажуються з БД) |
| periods[].id | string | Унікальний ідентифікатор періоду (slug) |
| periods[].label | string | Зрозуміла для людини назва періоду |
| periods[].start | string | Час початку періоду (HH:MM UTC) |
| periods[].end | string | Час закінчення періоду (HH:MM UTC) |
| periods[].is_current | boolean | Чи є цей період наразі активним |
| periods[].price | integer | Ціна за одиницю енергії в SUN |
| periods[].tiers | array|null | Рівні ціноутворення на основі обсягу (дивіться Рівні) |
Динамічні періоди
Кількість періодів, їхні часові діапазони, мітки та ціни є динамічними й керуються на стороні сервера. Не хардкодьте ідентифікатори або кількість періодів. Завжди виконуйте ітерацію по масиву periods.
Послуга: host
pricing_type: flat_rates
| Поле | Тип | Опис |
|---|---|---|
| rates.standard_65k | number | Стандартний тариф для 65k енергії (TRX) |
| rates.standard_131k_initial | number | Стандартний тариф для 131k енергії, первинна активація (TRX) |
| rates.frequent_65k | number | Частий тариф для 65k енергії (TRX) |
| rates.frequent_131k | number | Частий тариф для 131k енергії (TRX) |
Послуга: aml
pricing_type: provider_based
| Поле | Тип | Опис |
|---|---|---|
| providers | object | Карта постачальників AML (динамічна, може змінюватися) |
| providers[name].price | number | Ціна перевірки в USDT |
| providers[name].price_trx | number | Ціна перевірки, конвертована в TRX за поточним курсом |
| providers[name].available | boolean | Чи має постачальник доступну квоту |
Динамічні постачальники
Постачальники AML завантажуються з бази даних. Можуть з'являтися нові постачальники, або наявні можуть стати недоступними. Завжди виконуйте ітерацію по об'єкту providers.
Послуга: bandwidth
pricing_type: tiered_by_amount_and_period
За запитом і доступ
Ціни на Bandwidth повертаються лише тоді, коли це явно запитано через ?services=bandwidth — вони не входять до стандартної відповіді. Сам ендпоінт оренди Bandwidth доступний за запитом; зверніться до служби підтримки для отримання доступу. Дивіться Оренда Bandwidth.
Ціна оренди Bandwidth залежить від обсягу замовлення (рівень одиниць), періоду оренди (наприклад, 5m / 1h), вікна часу доби (UTC) та дня тижня. Базові ціни вказані в SUN за одиницю; понад базову ціну можуть застосовуватися фіксовані надбавки (у TRX) — усі значення повертаються у відповіді.
Відповідь надає як зручний вигляд (tiers — ціни для поточного вікна/дня), так і повну сітку (windows + schedule — кожне вікно для кожного дня тижня).
Адаптивний формат — не хардкодьте
Сітка ціноутворення повністю базується на даних і може змінитися в будь-який момент: кількість часових вікон, їхні мітки, час їхнього початку/закінчення, набір періодів оренди (нові періоди можуть додаватися або видалятися), рівні обсягу, розбивка за днями тижня та самі ціни. Клієнти повинні ітерувати повернуті масиви (windows, schedule, tiers, periods) і зіставляти за значенням — ніколи не припускайте фіксовану кількість, фіксовані мітки, фіксований час чи фіксовані ідентифікатори періодів. Код, написаний таким чином, продовжить працювати при зміні розкладу.
| Поле | Тип | Опис |
|---|---|---|
| unit | string | sun_per_unit |
| window | string | Мітка поточного вікна часу доби (UTC) |
| current_day_of_week | integer | Поточний день тижня, ISO 1=Пн … 7=Нд (UTC) |
| tiers[] | array | Рівні обсягу для поточного вікна/дня (для зручності; така сама структура, як усередині schedule) |
| windows[] | array | Довідник усіх вікон часу доби (може збільшуватися/зменшуватися/зсуватися) |
| windows[].label | string | Мітка вікна |
| windows[].start / .end | string | Початок/кінець вікна HH:MM UTC (вікно може перетинати північ, тобто start > end) |
| schedule[] | array | Повна сітка — один запис на (день тижня × вікно) |
| schedule[].day_of_week | integer | ISO день тижня 1…7 |
| schedule[].window | string | Мітка вікна (відповідає windows[].label) |
| schedule[].period_start / .period_end | string | HH:MM UTC |
| schedule[].is_current | boolean | true для сегмента, активного прямо зараз |
| schedule[].tiers[] | array | Рівні обсягу для цього сегмента |
| tiers[].amount_min | integer | Нижня межа рівня (включно) |
| tiers[].amount_max | integer|null | Верхня межа рівня (виключно). null = необмежено |
| tiers[].periods[] | array | Ціни за період оренди в межах рівня |
| tiers[].periods[].id | string | Ідентифікатор періоду оренди (наприклад, 5m, 1h) — може змінюватися/доповнюватися |
| tiers[].periods[].rental_seconds | integer | Тривалість періоду в секундах |
| tiers[].periods[].price | integer | Ціна за одиницю Bandwidth у SUN |
| surcharges | object | Фіксовані доплати до ціни клієнта (TRX) — дивіться нижче |
| limits | object | Ліміти замовлення: min_units, max_units |
Надбавки
| Поле | Тип | Опис |
|---|---|---|
| surcharges.small_order_threshold_units | integer | Замовлення з amount нижче цього значення отримують надбавку за мале замовлення |
| surcharges.small_order_surcharge_trx | number | Додається (TRX) для малих замовлень на делегування — компенсація за ончейн-делегування + повернення |
| surcharges.trx_send_surcharge_trx | number | Додається (TRX), коли замовлення виконується шляхом надсилання TRX — компенсація за переказ TRX |
Приклад відповіді
{
"bandwidth": {
"unit": "sun_per_unit",
"pricing_type": "tiered_by_amount_and_period",
"description": "Bandwidth delegation rental",
"cache_ttl": 30,
"window": "<current window label>",
"current_day_of_week": 7,
"tiers": [
{
"amount_min": 400,
"amount_max": 1000,
"periods": [
{"id": "5m", "rental_seconds": 300, "price": "<price_sun>"},
{"id": "1h", "rental_seconds": 3600, "price": "<price_sun>"}
]
},
{"amount_min": 1000, "amount_max": 3000, "periods": ["..."]},
{"amount_min": 3000, "amount_max": null, "periods": ["..."]}
],
"windows": [
{"label": "<window label>", "start": "01:00", "end": "09:00"},
{"label": "<window label>", "start": "14:00", "end": "00:00"}
],
"schedule": [
{
"day_of_week": 1,
"window": "<window label>",
"period_start": "01:00",
"period_end": "09:00",
"is_current": false,
"tiers": [
{"amount_min": 400, "amount_max": 1000, "periods": [
{"id": "5m", "rental_seconds": 300, "price": "<price_sun>"},
{"id": "1h", "rental_seconds": 3600, "price": "<price_sun>"}
]}
]
}
],
"surcharges": {
"small_order_threshold_units": 1000,
"small_order_surcharge_trx": "<trx>",
"trx_send_surcharge_trx": "<trx>"
},
"limits": {"min_units": 400, "max_units": 5000}
}
}schedule містить один запис для кожної комбінації (день тижня × вікно) — ітеруйте його, щоб відобразити повний календар цін. Рівно один запис має is_current: true.
Логіка клієнта (розрахунок ціни замовлення)
Використовуйте tiers для отримання «ціни прямо зараз». Щоб знайти ціну для іншого часу, виберіть відповідний запис schedule за днем тижня + вікном, чий проміжок [period_start, period_end) містить цей час (пам'ятайте, що вікно може перетинати північ, коли start > end), потім використовуйте його tiers.
# ціна для поточного моменту:
for tier in bandwidth.tiers:
if tier.amount_min <= amount < (tier.amount_max or infinity):
for p in tier.periods:
if p.id == requested_period: # зіставляйте за значенням, а не за індексом
base_trx = (p.price / units_meta.sun.multiplier) * amount
if amount < surcharges.small_order_threshold_units:
base_trx += surcharges.small_order_surcharge_trx # замовлення на делегування
# гілка виконання через відправку TRX:
# trx_branch_trx = base_trx_for_smallest_tier_shortest_period + surcharges.trx_send_surcharge_trx
# ціна для довільного дня тижня/часу: та сама логіка, але спочатку виберіть запис schedule[]
# де day_of_week співпадає і час потрапляє в [period_start, period_end).Централізовано та динамічно
Ціни на Bandwidth, вікна, розбивка за днями тижня та надбавки керуються на стороні сервера (БД) і можуть змінюватися. Завжди ітеруйте windows, schedule, tiers та periods із відповіді та зіставляйте за значенням — не хардкодьте кількість, мітки, час чи ідентифікатори періодів. Націнки SUB-користувачів не застосовуються до Bandwidth.
Рівні
Наразі tiers має значення null для всіх періодів. Коли ціноутворення на основі обсягу буде ввімкнено, поле міститиме масив об'єктів рівнів:
{
"tiers": [
{
"min_energy": 0,
"max_energy": 64999,
"price": "<price_sun>",
"label": "standard"
},
{
"min_energy": 65000,
"max_energy": 130999,
"price": "<price_sun>",
"label": "65k"
},
{
"min_energy": 131000,
"max_energy": 131000,
"price": "<price_sun>",
"label": "131k"
},
{
"min_energy": 131001,
"max_energy": null,
"price": "<price_sun>",
"label": "bulk"
}
]
}Схема рівнів (Tiers Schema)
| Поле | Тип | Опис |
|---|---|---|
| min_energy | integer | Мінімальний обсяг енергії для цього рівня (включно) |
| max_energy | integer|null | Максимальний обсяг енергії для цього рівня (включно). null = необмежено |
| price | integer | Ціна за одиницю енергії в SUN для цього рівня |
| label | string | Ідентифікатор рівня |
Логіка клієнта
if tiers != null:
знайти рівень, де min_energy <= order_amount <= max_energy
використати ціну цього рівня
else:
використати фіксоване поле ціни для всіх обсягів замовленьКомпактні формати відповіді
Використовуйте заголовок X-Format, щоб отримувати компактні текстові відповіді. Вони повертають ціну поточного активного періоду з energy_1h.
X-Format: now / compact / short
curl -H "X-API-KEY: your_key" -H "X-Format: now" https://netts.io/apiv2/pricing<Period>: price=<N> sun, 65k=<X.XXX> TRX (<X.XX>$), 131k=<X.XXX> TRX (<X.XX>$), 1m=<X.XXX> TRX (<X.XX>$)X-Format: short1h
Те саме, але без мітки періоду та ціни за одиницю.
curl -H "X-API-KEY: your_key" -H "X-Format: short1h" https://netts.io/apiv2/pricing65k=<X.XXX> TRX (<X.XX>$), 131k=<X.XXX> TRX (<X.XX>$), 1m=<X.XXX> TRX (<X.XX>$)X-Format: count
Ціноутворення для гуртових замовлень на 1, 2, 3, 5, 10, 20 замовлень.
curl -H "X-API-KEY: your_key" -H "X-Format: count" https://netts.io/apiv2/pricing1-<X.XXX> TRX (<X.XX>$), 2-<X.XXX> TRX (<X.XX>$), ...Формула розрахунку
TRX cost = (price_sun / units_meta.sun.multiplier) x energy_amount
USD cost = TRX_cost x trx_rate_usdНацінка для SUB-користувачів
SUB-користувачі автоматично отримують ціни з урахуванням націнки їхнього батьківського облікового запису. API завжди повертає кінцеву ціну для автентифікованого користувача — жодних обчислень на стороні клієнта не потрібно.
Відповіді з помилками
Помилки можуть надходити з двох рівнів із різними форматами. Ваш клієнт повинен обробляти обидва.
Помилки програми (від API)
Помилки рівня програми використовують стандартний формат success/error:
Недійсна послуга (400)
{
"success": false,
"error": {
"code": 4002,
"message": "Unknown services: invalid_service"
}
}Помилка автентифікації (401)
Повертається програмою, коли API-ключ відсутній або IP-адреси немає в білому списку:
{
"detail": {
"code": -1,
"msg": "Invalid API key or IP not in whitelist"
}
}Інший формат
Помилки автентифікації використовують нативний формат detail фреймворку FastAPI, а не структуру success/error. Це пов'язано з тим, що помилка виникає до того, як запит досягає логіки програми.
Користувача не знайдено (404)
{
"detail": {
"code": -1,
"msg": "User not found"
}
}Внутрішня помилка сервера (500)
{
"success": false,
"error": {
"code": 5001,
"message": "Failed to retrieve pricing data"
}
}Помилки шлюзу (від Kong)
Ці помилки повертаються шлюзом API до того, як запит потрапить до програми. Вони використовують власний формат Kong:
Перевищено ліміт запитів (429)
{
"message": "API rate limit exceeded"
}Таймаут шлюзу (504)
{
"message": "An invalid response was received from the upstream server"
}Довідник кодів помилок
| Код | Опис | HTTP-статус | Джерело |
|---|---|---|---|
-1 | API-ключ не надано | 401 | Програма |
-1 | Недійсний API-ключ або IP-адреси немає в білому списку | 401 | Програма |
-1 | Користувача не знайдено | 404 | Програма |
4002 | Невідома послуга в параметрі ?services= | 400 | Програма |
5000 | Внутрішня помилка сервера | 500 | Програма |
5001 | Не вдалося отримати дані ціноутворення | 500 | Програма |
5002 | Дані про ціну недоступні для компактного формату | 500 | Програма |
- | Перевищено ліміт запитів API | 429 | Kong |
Рекомендована обробка помилок на клієнті
response = requests.get(url, headers=headers)
data = response.json()
if response.status_code == 200 and data.get("success"):
# Успіх — обробка даних
services = data["data"]["services"]
elif response.status_code == 429:
# Обмеження запитів Kong — зачекати та повторити
retry_after = response.headers.get("Retry-After", "60")
time.sleep(int(retry_after))
elif "detail" in data:
# Помилка автентифікації/валідації FastAPI
detail = data["detail"]
if isinstance(detail, dict):
print(f"Error {detail.get('code')}: {detail.get('msg')}")
else:
print(f"Error: {detail}")
elif "error" in data:
# Помилка програми
err = data["error"]
print(f"Error {err.get('code')}: {err.get('message')}")
else:
print(f"Unexpected response: {response.status_code}")Міграція з /apiv2/prices
| Аспект | /apiv2/prices (старий) | /apiv2/pricing (новий) |
|---|---|---|
| Періоди | 5 фіксованих | Динамічні з БД |
| Рівні цін | 3 захардкоджені | Єдина ціна + майбутні tiers |
| Варіанти тривалості | Недоступно | energy_5m |
| Ціни на AML | Окремий ендпоінт | Включено через ?services=aml |
| Ціни на Host | Змішані у відповіді | Окрема послуга host |
| Фільтрація послуг | Недоступно | Параметр ?services= |
| Конвертація одиниць | Не задокументовано | units_meta у відповіді |
| Інформація про кеш | Не задокументовано | cache_ttl для кожної послуги |
| Формат відповіді | {"status": "success", ...} | {"success": true, "version": "2.1", "data": {...}} |
Ліміти запитів
Застосовуються ті самі ліміти запитів, що й для /apiv2/prices (налаштовані у шлюзі Kong).
Примітки
- Усі ціни на Energy вказані в SUN — використовуйте
units_metaдля конвертації - Ціни на Host вказані в TRX
- Ціни на AML вказані в USDT з включеною конвертацією в TRX
- Увесь час вказано в UTC
- Використовуйте
cache_ttlдля кожної послуги, щоб знати, як часто оновлюються дані - Використовуйте
pricing_type, щоб визначити, як парсити кожну послугу - Періоди, постачальники, тарифи та всі значення є динамічними — не хардкодьте їх
- Ціноутворення на Bandwidth надається за запитом (
?services=bandwidth), використовуєtiered_by_amount_and_periodізsurchargesта не підлягає націнці для SUB-користувачів