GET /apiv2/pricing
Универсальный эндпоинт тарифов, возвращающий цены на все сервисы в одном ответе с динамическими временными периодами.
Цена может измениться в процессе выполнения
Цена, возвращаемая этим эндпоинтом, может измениться во время обработки заказа. Поставщик Energy может отклонить запрос на делегирование, и в этом случае Netts автоматически перенаправит заказ следующему доступному поставщику. Netts стремится не только предлагать наиболее конкурентоспособную цену, но и гарантировать надежное предоставление Energy — поэтому заказ может быть выполнен по цене выше заявленной. Это применимо только к заказам объемом от 300 000 единиц Energy и выше.
Рекомендуется
Это рекомендуемый эндпоинт получения тарифов. Он заменяет устаревший эндпоинт /apiv2/prices, поддержка которого будет прекращена.
URL эндпоинта
GET https://netts.io/apiv2/pricingЗаголовки запроса
| Заголовок | Обязательный | Описание | Значения |
|---|---|---|---|
| X-API-KEY | Да | Ваш API-ключ | string |
| X-Real-IP | Да | IP-адрес из белого списка | IP address |
| 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 — opt-in: возвращаются только при явном запросе через ?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 (opt-in — необходимо запрашивать явно)
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 | Время начала периода (ЧЧ:ММ UTC) |
| periods[].end | string | Время окончания периода (ЧЧ:ММ UTC) |
| periods[].is_current | boolean | Активен ли данный период в текущий момент |
| periods[].price | integer | Цена за единицу Energy в SUN |
| periods[].tiers | array|null | Тарифные уровни в зависимости от объема (см. Уровни) |
Динамические периоды
Количество периодов, их временные диапазоны, метки и цены являются динамическими и управляются на стороне сервера. Не хардкодьте идентификаторы периодов или их количество. Всегда выполняйте итерацию по массиву periods.
Сервис: host
pricing_type: flat_rates
| Поле | Тип | Описание |
|---|---|---|
| rates.standard_65k | number | Стандартный тариф для 65k Energy (TRX) |
| rates.standard_131k_initial | number | Стандартный тариф для 131k Energy, начальная активация (TRX) |
| rates.frequent_65k | number | Частый тариф для 65k Energy (TRX) |
| rates.frequent_131k | number | Частый тариф для 131k Energy (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
Opt-in и доступ
Цены на 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"
}
]
}Схема уровней
| Поле | Тип | Описание |
|---|---|---|
| min_energy | integer | Минимальное количество Energy для этого уровня (включительно) |
| max_energy | integer|null | Максимальное количество Energy для этого уровня (включительно). null = без ограничений |
| price | integer | Цена за единицу Energy в SUN для этого уровня |
| label | string | Идентификатор уровня |
Клиентская логика
if tiers != null:
найти уровень, где min_energy <= order_amount <= max_energy
использовать цену этого уровня
else:
использовать фиксированное поле price для любых объемов заказаКомпактные форматы ответа
Используйте заголовок 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"
}
}Другой формат
Ошибки аутентификации используют нативный формат FastAPI detail, а не структуру 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 | App |
-1 | Недействительный API-ключ или IP не в белом списке | 401 | App |
-1 | Пользователь не найден | 404 | App |
4002 | Неизвестный сервис в параметре ?services= | 400 | App |
5000 | Внутренняя ошибка сервера | 500 | App |
5001 | Не удалось получить данные о тарифах | 500 | App |
5002 | Данные о ценах недоступны для компактного формата | 500 | App |
- | Превышен лимит запросов 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 являются opt-in (
?services=bandwidth), используют типtiered_by_amount_and_periodсsurcharges, и к ним не применяется наценка SUB-пользователей