POST /apiv2/usdt/analyze
Calculate TRON USDT transfer cost (private endpoint — authenticated).
Returns the exact same TransferAnalysis payload as the public GET variant, but with a much higher rate limit (50 req/sec per Kong node instead of 1/sec) and with request data passed in a JSON body instead of the URL. Use this endpoint for any production integration.
Endpoint URL
POST https://netts.io/apiv2/usdt/analyzeAuthentication
Either of the following two headers is accepted (both supported simultaneously; X-API-KEY is preferred because it matches the rest of the Netts /apiv2/* API surface):
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json. |
X-API-KEY | Preferred | Your Netts API key — exactly the same format used for /apiv2/order1h and other authenticated Netts endpoints. |
Authorization | Accepted as an alternative | Bearer {key} or just {key} (no prefix). Use this if your HTTP client has a built-in bearer/auth flow. |
If both headers are sent, X-API-KEY wins.
IP whitelist: the IP from which the request reaches our edge must be in the whitelist configured for your API key (same mechanism as the other /apiv2/* endpoints). Requests from a non-whitelisted IP return 401 Unauthorized with "Invalid API key or IP not in whitelist".
Reusing your order1h headers
If you already call /apiv2/order1h with X-API-KEY: {key}, you can send the exact same X-API-KEY header to /apiv2/usdt/analyze — the calculator now recognises it as the primary authentication header.
Request body
{
"sender_address": "TFLit1TFohBtT2f8UVCLFVPmZxawxqByYe",
"receiver_address": "TTKR9aQdJWTgXLK9cmzaDitT5VXE497thL"
}Fields
| Field | Type | Required | Constraints |
|---|---|---|---|
sender_address | string | Yes | Valid TRON address — 34 chars, starts with T, valid base58 checksum. |
receiver_address | string | Yes | Valid TRON address; must differ from sender_address. |
TIP
There is no amount field. The calculator returns the cost and resource requirements for a single USDT transfer between the two addresses; if you need the breakdown for a specific USDT amount, multiply the recommended energy by the transfer count on your side — a single TRC-20 USDT transfer consumes the same ~130 k energy regardless of amount.
Request examples
cURL (preferred — X-API-KEY)
curl -X POST "https://netts.io/apiv2/usdt/analyze" \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_API_KEY" \
-d '{
"sender_address": "TFLit1TFohBtT2f8UVCLFVPmZxawxqByYe",
"receiver_address": "TTKR9aQdJWTgXLK9cmzaDitT5VXE497thL"
}'cURL (alternative — Authorization)
curl -X POST "https://netts.io/apiv2/usdt/analyze" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"sender_address": "TFLit1TFohBtT2f8UVCLFVPmZxawxqByYe",
"receiver_address": "TTKR9aQdJWTgXLK9cmzaDitT5VXE497thL"
}'Python
import requests
API_KEY = "YOUR_API_KEY"
payload = {
"sender_address": "TFLit1TFohBtT2f8UVCLFVPmZxawxqByYe",
"receiver_address": "TTKR9aQdJWTgXLK9cmzaDitT5VXE497thL",
}
r = requests.post(
"https://netts.io/apiv2/usdt/analyze",
headers={
"Content-Type": "application/json",
"X-API-KEY": API_KEY, # preferred; same header as /apiv2/order1h
# or, equivalently:
# "Authorization": f"Bearer {API_KEY}",
},
json=payload,
timeout=15,
)
if r.status_code == 200:
data = r.json()["data"]
print("Energy needed:", data["requirements"]["energy_with_buffer"])
print("Total cost: ", data["costs"]["total_cost_trx"], "TRX")
print("Method: ", data["costs"]["recommended_method"])
elif r.status_code == 401:
print("Auth failed:", r.json())
elif r.status_code == 429:
print("Rate-limited — Retry-After:", r.headers.get("Retry-After"))
else:
print("Error:", r.status_code, r.json())Response
Success (200 OK)
Identical envelope to the public endpoint:
{
"status": "success",
"data": { /* TransferAnalysis — see the public-endpoint page */ },
"current_utc_time": "2026-04-23 11:54:13",
"processing_time_ms": 20.14
}The full field-by-field description of data is on the public-endpoint page — see TransferAnalysis, AddressInfo, Requirements and Costs.
Errors
Order of checks
Authentication is validated before body validation. If the Authorization header is missing/invalid or your IP is not whitelisted, you will always see 401 — even if the JSON body is also malformed. Fix auth first, then re-test with a valid key; only then will Pydantic body-validation errors (422) surface.
| HTTP | Body | When |
|---|---|---|
| 401 | {"code": -1, "msg": "API key not provided (expected X-API-KEY or Authorization header)"} | Neither X-API-KEY nor Authorization header present. |
| 401 | {"code": -1, "msg": "Invalid API key or IP not in whitelist"} | Unknown key, or request IP not in your whitelist. |
| 404 | {"code": -1, "msg": "User not found"} | Key valid but user record was not found (rare). |
| 422 | {"detail": [{"loc": ["body","sender_address"], "msg": "Invalid TRON address length", "type": "value_error"}]} | FastAPI/Pydantic body validation failed. Status is 422 Unprocessable Entity, not 400. |
| 422 | {"detail": [{..., "msg": "Sender and receiver cannot be the same address", "type": "value_error"}]} | sender_address == receiver_address. |
| 429 | {"message": "API rate limit exceeded"} | Sustained traffic beyond 50 req/sec on a Kong node. |
| 500 | {"code": -1, "msg": "Internal server error"} | Unexpected server-side failure. |
Rate limit
- 50 requests / second per Kong node (
limit_by = ip, policylocal). minute/hourlimits are not set — only the per-second limit applies.- Every response carries the standard Kong headers:
RateLimit-Limit,RateLimit-Remaining,RateLimit-Reset,X-RateLimit-Limit-Second,X-RateLimit-Remaining-Second, andRetry-Afteron a429.
Example 429 response
HTTP/1.1 429 Too Many Requests
Content-Type: application/json; charset=utf-8
RateLimit-Limit: 50
RateLimit-Remaining: 0
RateLimit-Reset: 1
Retry-After: 1
X-RateLimit-Limit-Second: 50
X-RateLimit-Remaining-Second: 0
{"message":"API rate limit exceeded"}TIP
If you are reaching 50 req/sec with a single API key and need more, contact support — the limit can be raised per key, or a dedicated rate-limit plugin can be attached to your consumer.
Debug headers
Every response also carries identifiers useful when opening a support ticket — please include them verbatim so we can find the request in our logs within seconds:
| Header | Meaning |
|---|---|
X-Request-ID | Application-side request ID (generated by the calculator). |
X-Process-Time | Application processing time in milliseconds (upstream, excluding Kong). |
X-Kong-Request-Id | Kong-side request ID (present in Kong access logs). |
Client-side timeout and retry
The calculator performs live on-chain queries to TRON nodes for each request, so under load or slow upstream nodes a single call can take several seconds. Short client timeouts will fail even on healthy responses — this is the root cause of most cURL error 28 (Connection timed out) reports from integrators.
Recommended settings:
- Timeout ≥ 15 seconds (30 s is safer). The default 10 s used by many HTTP clients is too short.
- On HTTP 429, honour the
Retry-Afterheader (seconds). Add small jitter (e.g. 0–200 ms) before retrying, then use exponential backoff if you still hit the 50 req/sec limit. - On HTTP 5xx or network errors, retry at most 2–3 times with exponential backoff; do not hammer the endpoint.
- Cache the result client-side for 30–60 seconds per
(sender_address, receiver_address)pair — the underlying resource prices and on-chain state rarely change fast enough to warrant more frequent recalculation.
Browser / CORS support
This endpoint is designed for server-to-server integrations and currently does not support direct calls from a browser: the upstream FastAPI app advertises Access-Control-Allow-Methods: GET only, so the preflight OPTIONS for a cross-origin POST will fail in browsers.
If you need to call the calculator from a browser front-end, proxy the request through your own back-end (which holds the API key) instead of exposing the key to the client anyway.
TIP
If your use case legitimately requires browser-side POST with an API key (e.g. a trusted internal dashboard on a known origin), contact support — a CORS plugin can be attached at the Kong level for your route.
Notes
- Response format is intentionally identical to the public endpoint, so the client code that parses the public response continues to work after you migrate to the authenticated variant — only the call itself changes.
- Both
X-API-KEY: {key}(preferred, consistent with/apiv2/order1h) andAuthorization: Bearer {key}/Authorization: {key}are accepted; if both are sent,X-API-KEYwins. - Cloudflare / reverse-proxy interposition does not affect this endpoint the same way it affects the public one, because authenticated traffic is rate-limited per-Kong-node and per-consumer semantics can be enabled on request.