TronEnergy

API documentation

Automate TRON energy rental for exchanges, wallets and payment systems.

Create an API key

Overview

The Open API lets exchanges, wallets and payment systems rent TRON energy programmatically: place orders, check their status, estimate prices and receive a callback when an order completes.

ItemValue
Base URLhttps://api.tronhub.net
MethodPOST for every endpoint
Content typeapplication/json
Amount unitsun (1 TRX = 1,000,000 sun)
Energy deliveryOn-chain delegation to receive_address

Orders are paid from your account balance. Create an API key on the API Keys page; the API secret is shown only once when the key is created.

The API is designed for server-to-server calls. Never expose your API secret in a browser or mobile app.

Authentication

Every request must carry three headers:

HeaderDescription
API-KEYYour API key (starts with ak_)
TIMESTAMPCurrent Unix time in seconds. Requests more than 300 seconds away from server time are rejected.
SIGNATURELowercase hex HMAC-SHA256 signature, see below

Signature

signature = hex( HMAC-SHA256( key = api_secret, message = TIMESTAMP + "&" + body ) )
  • body is the exact raw request body you send. Serialize your JSON once, sign that string, and send the same string — do not re-serialize it after signing.
  • If you send an empty body, sign the string {}.
  • Use the API secret string as the HMAC key as-is (do not hex-decode it).
  • The signature must be lowercase hex.

Key settings

  • Permissions — order (create orders), query (query orders), price (estimate price and market data), balance (account balance), or * for all.
  • IP whitelist — optional, comma-separated list of exact IP addresses. If set, requests from other IPs are rejected.
  • Rate limit — optional requests-per-minute limit per key (0 = unlimited).

Example

import hashlib, hmac, json, time
import requests

API_KEY = "ak_your_api_key"
API_SECRET = "your_api_secret"
BASE_URL = "https://api.tronhub.net"

def call(path, payload=None):
    body = json.dumps(payload or {}, separators=(",", ":"))
    timestamp = str(int(time.time()))
    signature = hmac.new(API_SECRET.encode(), f"{timestamp}&{body}".encode(), hashlib.sha256).hexdigest()
    headers = {
        "Content-Type": "application/json",
        "API-KEY": API_KEY,
        "TIMESTAMP": timestamp,
        "SIGNATURE": signature,
    }
    # Send exactly the string that was signed
    return requests.post(BASE_URL + path, data=body, headers=headers, timeout=15).json()

print(call("/api/open/price", {"period": "1H", "energy_amount": 65000}))
import crypto from "node:crypto"

const API_KEY = "ak_your_api_key"
const API_SECRET = "your_api_secret"
const BASE_URL = "https://api.tronhub.net"

async function call(path, payload = {}) {
  const body = JSON.stringify(payload)
  const timestamp = Math.floor(Date.now() / 1000).toString()
  const signature = crypto.createHmac("sha256", API_SECRET).update(`${timestamp}&${body}`).digest("hex")
  const res = await fetch(BASE_URL + path, {
    method: "POST",
    headers: { "Content-Type": "application/json", "API-KEY": API_KEY, "TIMESTAMP": timestamp, "SIGNATURE": signature },
    body,
  })
  return res.json()
}

console.log(await call("/api/open/balance"))
func call(path string, payload any) (*http.Response, error) {
	body, _ := json.Marshal(payload)
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	mac := hmac.New(sha256.New, []byte(apiSecret))
	mac.Write([]byte(timestamp + "&" + string(body)))
	signature := hex.EncodeToString(mac.Sum(nil))

	req, _ := http.NewRequest(http.MethodPost, baseURL+path, bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("API-KEY", apiKey)
	req.Header.Set("TIMESTAMP", timestamp)
	req.Header.Set("SIGNATURE", signature)
	return http.DefaultClient.Do(req)
}

Responses & errors

All responses share the same envelope. Check the code field, not the HTTP status: API errors are returned with HTTP 200.

{
  "code": 200,
  "message": "success",
  "data": {}
}

data is present only on success. On error, message describes the problem.

Error messages are returned in Chinese by default. Send the optional header X-Locale: en to receive them in English:

X-Locale: en

The X-Locale header is not part of the signature.

codeMeaningTypical causes
200Success—
400Invalid parametersMissing or invalid fields, malformed JSON
401Authentication failedMissing headers, expired timestamp, unknown or disabled key, invalid signature
403ForbiddenKey lacks the permission, or IP not in the whitelist
429Too many requestsPer-key rate limit exceeded
500Business errorInsufficient balance, order not found, unsupported period, order failed

A global per-IP limit also applies. When it is exceeded the API responds with HTTP 429 and code: 429. Retry with backoff.

Create order

POST /api/open/order/create · permission order

Deducts the order amount from your balance and delegates energy to receive_address.

FieldTypeRequiredDescription
energy_amountintYesAmount of energy. Must be within the limits returned by market data.
periodstringYesRental period: 1H, 1D, 3D or 30D (case-sensitive).
receive_addressstringYesActivated TRON address that receives the energy.
callback_urlstringNoURL notified when the order completes or fails. Must be a publicly reachable http/https URL; private, loopback and internal addresses are rejected. See callbacks.
out_trade_nostringNoYour own order reference, unique per account. Recommended: it makes retries safe (see below).
{
  "energy_amount": 65000,
  "period": "1H",
  "receive_address": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF",
  "callback_url": "https://example.com/tron-energy/callback",
  "out_trade_no": "ORDER-10001"
}

The amount charged equals total_price from estimate price, including the small-order fee for orders below small_amount.

Retries and out_trade_no. If a create request times out, retry it with the same out_trade_no:

  • Same out_trade_no with the same energy_amount, period and receive_address: the existing order is returned and you are not charged again.
  • Same out_trade_no with different parameters: the request is rejected.
  • While the first request is still being processed, a retry is rejected with a message asking you to query the order later.

Without out_trade_no, a retried request always creates a new order.

Response data:

FieldTypeDescription
order_nostringOrder number
energy_amountintEnergy amount
periodstringRental period
receive_addressstringReceiving address
amountintAmount charged (sun)
statusintOrder status, normally 1 (processing). See status codes.
out_trade_nostringYour order reference
created_atstringCreation time (RFC 3339)
{
  "code": 200,
  "message": "success",
  "data": {
    "order_no": "E20260928103000a1b2c3d4",
    "energy_amount": 65000,
    "period": "1H",
    "receive_address": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF",
    "amount": 1885000,
    "status": 1,
    "out_trade_no": "ORDER-10001",
    "created_at": "2026-09-28T10:30:00+08:00"
  }
}

If the order cannot be placed, the response has code: 500, the charge is refunded to your balance, and no callback is sent.

Query order

POST /api/open/order/query · permission query

Provide order_no or out_trade_no. If both are sent, order_no is used.

FieldTypeRequiredDescription
order_nostringOne ofOrder number
out_trade_nostringOne ofYour order reference

Response data:

FieldTypeDescription
order_nostringOrder number
energy_amountintEnergy amount
periodstringRental period
receive_addressstringReceiving address
statusintOrder status
amountintAmount charged (sun)
refund_amountintAmount refunded (sun)
out_trade_nostringYour order reference
api_namestringName of the API key used for this request
detailsarray | nullDelegation records, newest first; null if there are none yet
created_atstringCreation time (RFC 3339)
updated_atstringLast update time (RFC 3339)

Each item in details:

FieldTypeDescription
txidstringDelegation transaction hash (empty until delegated)
energy_amountintEnergy amount
amountintCost (sun)
statusint0 waiting for result, 1 success, 2 failed, 3 refunded
created_atstringSubmission time (RFC 3339)

Estimate price

POST /api/open/price · permission price

FieldTypeRequiredDescription
periodstringYes1H, 1D, 3D or 30D
energy_amountintYesAmount of energy

Response data:

FieldTypeDescription
periodstringRental period
energy_amountintEnergy amount
priceintUnit price: sun per energy for 1H, sun per energy per day for day periods
daysintBilling multiplier: 1 for 1H, otherwise the number of days
total_priceintprice × energy_amount × days plus the small-order fee (sun). This is the amount charged when the order is created.
additionintSmall-order fee (sun); 0 when energy_amount is at or above small_amount

Market data

POST /api/open/market · permission price · no request body required

Response data:

FieldTypeDescription
tiered_pricingarray[{ "period": "1H", "price": 29 }, ...]. 1H is sun per energy; 1D/3D/30D are sun per energy per day (a 3-day order costs price × energy × 3)
minimum_order_energyintMinimum energy per order
maximum_order_energyintMaximum energy per order
small_amountintOrders below this amount include a small-order fee
small_additionnumberSmall-order fee (TRX)
usdt_energy_need_oldintEnergy for one USDT transfer to an address that holds USDT
usdt_energy_need_newintEnergy for one USDT transfer to an address that has never held USDT
burn_rateintCost of burning TRX instead of using energy (sun per energy)

Account balance

POST /api/open/balance · permission balance · no request body required

{ "code": 200, "message": "success", "data": { "balance": 150000000 } }

balance is in sun (150,000,000 sun = 150 TRX).

Callbacks

When an order reaches a final state — completed (2) or failed (3) — we send a POST request with a JSON body to its callback_url.

{
  "order_no": "E20260928103000a1b2c3d4",
  "out_trade_no": "ORDER-10001",
  "energy_amount": 65000,
  "period": "1H",
  "receive_address": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF",
  "status": 2,
  "amount": 1885000,
  "refund_amount": 0
}

Verifying a callback

Callbacks carry API-KEY, TIMESTAMP and SIGNATURE headers, signed the same way as your requests. Verify against the raw request body before parsing it:

expected = hmac.new(API_SECRET.encode(), f"{timestamp}&{raw_body}".encode(), hashlib.sha256).hexdigest()
valid = hmac.compare_digest(expected, signature)

The callback is signed with the secret of the key that placed the order, or your most recently created enabled key if that key has been disabled. If you have no enabled key, the callback is sent without signature headers — treat it as unverified and confirm with query order.

Delivery

  • Respond with HTTP 200 to acknowledge. Any other status (including 201 or 204) counts as a failure.
  • Each attempt times out after 10 seconds. A callback is attempted up to 3 times in total, a few seconds apart.
  • Callbacks may be delivered more than once or not at all. Make your handler idempotent and use query order to reconcile orders that have not been confirmed.

Order status codes

statusMeaning
0Pending — created, not yet submitted
1Processing — submitted, waiting for delegation
2Completed — energy delegated
3Failed — the charge has been refunded to your balance (refund_amount)
4Refunded (reserved)