GET /apiv2/pricing
Universal pricing endpoint that returns all service prices in a single response with dynamic time periods.
Price may change during fulfillment
The price returned by this endpoint may change while an order is being processed. An energy provider can decline a delegation request, in which case Netts automatically routes the order to the next available provider. Netts is committed not only to offering the most competitive price, but also to ensuring a reliable energy supply — therefore an order may be fulfilled at a higher price than quoted. This applies only to orders of 300,000 energy units and above.
Recommended
This is the recommended pricing endpoint. It replaces the legacy /apiv2/prices endpoint which will be deprecated.
Endpoint URL
GET https://netts.io/apiv2/pricingRequest Headers
| Header | Required | Description | Values |
|---|---|---|---|
| X-API-KEY | Yes | Your API key | string |
| X-Real-IP | Yes | IP address from whitelist | IP address |
| X-Format | No | Response format (default: full JSON) | now, compact, short, short1h, count |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| services | string | all | Comma-separated filter of services to include |
Available Services
| Service | Description |
|---|---|
energy_1h | 1-hour energy delegation prices |
energy_5m | 5-minute energy delegation prices |
host | Host energy delegation rates |
aml | AML address check prices |
bandwidth | Bandwidth rental prices — opt-in: returned only when explicitly requested via ?services=bandwidth (not part of the default response) |
Example Requests
cURL — Full Response
curl -X GET https://netts.io/apiv2/pricing \
-H "X-API-KEY: your_api_key" \
-H "X-Real-IP: your_whitelisted_ip"cURL — Filter by Services
# Only energy 1h prices
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 prices only
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 rental prices (opt-in — must be requested explicitly)
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 — Filter Services
params = {"services": "energy_1h,aml"}
response = requests.get(url, headers=headers, params=params)Response Structure
Top-Level Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | true for successful requests |
| version | string | API version (e.g. "2.1") |
| timestamp | string | Server time in ISO 8601 UTC |
| data | object | Response payload |
Data Fields
| Field | Type | Description |
|---|---|---|
| data.trx_rate_usd | number | Current TRX/USD exchange rate |
| data.units_meta | object | Machine-readable unit conversion info |
| data.services | object | Map of requested services with pricing data |
Units Meta
Allows clients to programmatically convert between units:
{
"units_meta": {
"sun": {"base": "trx", "multiplier": 1000000},
"trx": {"base": "trx", "multiplier": 1},
"usdt": {"base": "usdt", "multiplier": 1}
}
}To convert from SUN to TRX: trx_price = sun_price / units_meta.sun.multiplier
Service Common Fields
Every service includes these fields:
| Field | Type | Description |
|---|---|---|
| unit | string | Price unit (sun, trx, usdt) |
| pricing_type | string | How to parse this service (see below) |
| description | string | Human-readable description |
| cache_ttl | integer | How often this data refreshes (seconds) |
Pricing Types
The pricing_type field tells clients how to parse each service:
| Type | Structure | Used by |
|---|---|---|
periodic | periods[] array with time-based prices | energy_1h, energy_5m |
flat_rates | rates{} object with named rate keys | host |
provider_based | providers{} object with provider data | aml |
tiered_by_amount_and_period | tiers[] by amount range, each with periods[] | bandwidth |
Service: energy_1h / energy_5m
pricing_type: periodic
| Field | Type | Description |
|---|---|---|
| current_period | string | Slug of the currently active period |
| periods[] | array | All pricing periods (dynamic, loaded from DB) |
| periods[].id | string | Unique period identifier (slug) |
| periods[].label | string | Human-readable period name |
| periods[].start | string | Period start time (HH:MM UTC) |
| periods[].end | string | Period end time (HH:MM UTC) |
| periods[].is_current | boolean | Whether this period is currently active |
| periods[].price | integer | Price per energy unit in SUN |
| periods[].tiers | array|null | Volume-based pricing tiers (see Tiers) |
Dynamic periods
The number of periods, their time ranges, labels, and prices are all dynamic and managed server-side. Do not hardcode period IDs or counts. Always iterate over the periods array.
Service: host
pricing_type: flat_rates
| Field | Type | Description |
|---|---|---|
| rates.standard_65k | number | Standard rate for 65k energy (TRX) |
| rates.standard_131k_initial | number | Standard rate for 131k energy, initial activation (TRX) |
| rates.frequent_65k | number | Frequent rate for 65k energy (TRX) |
| rates.frequent_131k | number | Frequent rate for 131k energy (TRX) |
Service: aml
pricing_type: provider_based
| Field | Type | Description |
|---|---|---|
| providers | object | Map of AML providers (dynamic, may change) |
| providers[name].price | number | Check price in USDT |
| providers[name].price_trx | number | Check price converted to TRX at current rate |
| providers[name].available | boolean | Whether provider has available quota |
Dynamic providers
AML providers are loaded from the database. New providers may appear or existing ones may become unavailable. Always iterate over the providers object.
Service: bandwidth
pricing_type: tiered_by_amount_and_period
Opt-in & access
Bandwidth pricing is returned only when explicitly requested via ?services=bandwidth — it is not part of the default response. The bandwidth rental endpoint itself is available by request; contact support for access. See Bandwidth rental.
Bandwidth rental price depends on the order amount (unit tier), the rental period (e.g. 5m / 1h), the time-of-day window (UTC) and the day of week. Base prices are in SUN per unit; on top of the base, fixed surcharges (in TRX) may apply — all values are returned in the response.
The response provides both a convenience view (tiers — prices for the current window/day) and the full grid (windows + schedule — every window across every weekday).
Adaptive format — do not hardcode
The pricing grid is fully data-driven and may change at any time: the number of time windows, their labels, their start/end times, the set of rental periods (new periods may be added or removed), the amount tiers, the weekday breakdown and the prices themselves. Clients must iterate over the returned arrays (windows, schedule, tiers, periods) and match by value — never assume a fixed count, fixed labels, fixed times or fixed period ids. Code written this way keeps working when the schedule changes.
| Field | Type | Description |
|---|---|---|
| unit | string | sun_per_unit |
| window | string | Current time-of-day window label (UTC) |
| current_day_of_week | integer | Current weekday, ISO 1=Mon … 7=Sun (UTC) |
| tiers[] | array | Amount tiers for the current window/day (convenience; same shape as inside schedule) |
| windows[] | array | Directory of all time-of-day windows (may grow/shrink/shift) |
| windows[].label | string | Window label |
| windows[].start / .end | string | Window start/end HH:MM UTC (a window may cross midnight, i.e. start > end) |
| schedule[] | array | Full grid — one entry per (weekday × window) |
| schedule[].day_of_week | integer | ISO weekday 1…7 |
| schedule[].window | string | Window label (matches a windows[].label) |
| schedule[].period_start / .period_end | string | HH:MM UTC |
| schedule[].is_current | boolean | true for the segment active right now |
| schedule[].tiers[] | array | Amount tiers for this segment |
| tiers[].amount_min | integer | Tier lower bound (inclusive) |
| tiers[].amount_max | integer|null | Tier upper bound (exclusive). null = unlimited |
| tiers[].periods[] | array | Prices per rental period within the tier |
| tiers[].periods[].id | string | Rental period id (e.g. 5m, 1h) — may change/extend |
| tiers[].periods[].rental_seconds | integer | Period length in seconds |
| tiers[].periods[].price | integer | Price per bandwidth unit in SUN |
| surcharges | object | Fixed additions to the client price (TRX) — see below |
| limits | object | Order limits: min_units, max_units |
Surcharges
| Field | Type | Description |
|---|---|---|
| surcharges.small_order_threshold_units | integer | Orders with amount below this value get the small-order surcharge |
| surcharges.small_order_surcharge_trx | number | Added (TRX) for small delegation orders — compensation for on-chain delegation + reclaim |
| surcharges.trx_send_surcharge_trx | number | Added (TRX) when the order is fulfilled by sending TRX — compensation for the TRX transfer |
Example Response
{
"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 contains one entry for every (weekday × window) combination — iterate it to render a full price calendar. Exactly one entry has is_current: true.
Client Logic (compute the order price)
Use tiers for "the price right now". To look up a price for another time, pick the matching schedule entry by weekday + the window whose [period_start, period_end) contains the time (remember a window may cross midnight when start > end), then use its tiers.
# price for the current moment:
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: # match by value, not by index
base_trx = (p.price / units_meta.sun.multiplier) * amount
if amount < surcharges.small_order_threshold_units:
base_trx += surcharges.small_order_surcharge_trx # delegation orders
# TRX-send fulfillment branch instead:
# trx_branch_trx = base_trx_for_smallest_tier_shortest_period + surcharges.trx_send_surcharge_trx
# price for an arbitrary weekday/time: same logic, but first select the schedule[] entry
# where day_of_week matches and the time falls in [period_start, period_end).Centralized & dynamic
Bandwidth prices, windows, weekday breakdown and surcharges are managed server-side (DB) and may change. Always iterate windows, schedule, tiers and periods from the response and match by value — do not hardcode counts, labels, times or period ids. SUB-user markups do not apply to bandwidth.
Tiers
Currently tiers is null for all periods. When volume-based pricing is enabled, the field will contain an array of tier objects:
{
"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
| Field | Type | Description |
|---|---|---|
| min_energy | integer | Minimum energy amount for this tier (inclusive) |
| max_energy | integer|null | Maximum energy amount for this tier (inclusive). null = unlimited |
| price | integer | Price per energy unit in SUN for this tier |
| label | string | Tier identifier |
Client Logic
if tiers != null:
find the tier where min_energy <= order_amount <= max_energy
use that tier's price
else:
use the flat price field for all order amountsCompact Response Formats
Use the X-Format header to get compact text responses. These return the current active period price from 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
Same but without period label and per-unit price.
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
Bulk order pricing for 1, 2, 3, 5, 10, 20 orders.
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>$), ...Calculation Formula
TRX cost = (price_sun / units_meta.sun.multiplier) x energy_amount
USD cost = TRX_cost x trx_rate_usdSUB-User Markup
SUB-users automatically receive prices with their parent's markup applied. The API always returns the final price for the authenticated user — no client-side calculation needed.
Error Responses
Errors may come from two layers with different formats. Your client should handle both.
Application Errors (from API)
Application-level errors use the standard success/error format:
Invalid Service (400)
{
"success": false,
"error": {
"code": 4002,
"message": "Unknown services: invalid_service"
}
}Authentication Error (401)
Returned by the application when API key is missing or IP is not whitelisted:
{
"detail": {
"code": -1,
"msg": "Invalid API key or IP not in whitelist"
}
}Different format
Authentication errors use FastAPI's native detail format, not the success/error structure. This is because the error is raised before the request reaches application logic.
User Not Found (404)
{
"detail": {
"code": -1,
"msg": "User not found"
}
}Internal Server Error (500)
{
"success": false,
"error": {
"code": 5001,
"message": "Failed to retrieve pricing data"
}
}Gateway Errors (from Kong)
These errors are returned by the API gateway before the request reaches the application. They use Kong's own format:
Rate Limit Exceeded (429)
{
"message": "API rate limit exceeded"
}Gateway Timeout (504)
{
"message": "An invalid response was received from the upstream server"
}Error Code Reference
| Code | Description | HTTP Status | Source |
|---|---|---|---|
-1 | API key not provided | 401 | App |
-1 | Invalid API key or IP not in whitelist | 401 | App |
-1 | User not found | 404 | App |
4002 | Unknown service in ?services= parameter | 400 | App |
5000 | Internal server error | 500 | App |
5001 | Failed to retrieve pricing data | 500 | App |
5002 | Price data unavailable for compact format | 500 | App |
- | API rate limit exceeded | 429 | Kong |
Recommended Client Error Handling
response = requests.get(url, headers=headers)
data = response.json()
if response.status_code == 200 and data.get("success"):
# Success — process data
services = data["data"]["services"]
elif response.status_code == 429:
# Kong rate limit — back off and retry
retry_after = response.headers.get("Retry-After", "60")
time.sleep(int(retry_after))
elif "detail" in data:
# FastAPI auth/validation error
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:
# Application error
err = data["error"]
print(f"Error {err.get('code')}: {err.get('message')}")
else:
print(f"Unexpected response: {response.status_code}")Migration from /apiv2/prices
| Aspect | /apiv2/prices (old) | /apiv2/pricing (new) |
|---|---|---|
| Periods | 5 fixed | Dynamic from DB |
| Price tiers | 3 hardcoded | Single price + future tiers |
| Duration variants | Not available | energy_5m |
| AML prices | Separate endpoint | Included via ?services=aml |
| Host prices | Mixed in response | Separate host service |
| Service filtering | Not available | ?services= parameter |
| Unit conversion | Undocumented | units_meta in response |
| Cache info | Undocumented | cache_ttl per service |
| Response format | {"status": "success", ...} | {"success": true, "version": "2.1", "data": {...}} |
Rate Limits
Same rate limits as /apiv2/prices apply (configured in Kong gateway).
Notes
- All energy prices are in SUN — use
units_metafor conversion - Host prices are in TRX
- AML prices are in USDT with TRX conversion included
- All times are in UTC
- Use
cache_ttlper service to know how often data refreshes - Use
pricing_typeto determine how to parse each service - Periods, providers, rates, and all values are dynamic — do not hardcode them
- Bandwidth pricing is opt-in (
?services=bandwidth), usestiered_by_amount_and_periodwithsurcharges, and is not subject to SUB-user markup