GET /apiv2/pricing
Universal pricing endpoint that returns all service prices in a single response with dynamic time periods.
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 |
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"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 |
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.
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