Prof Energy API

REST API for renting TRON energy for USDT (TRC-20) transfers. Base URL: https://api.profenergy.io/v1. All requests and responses are JSON, all times are UTC (ISO 8601). Wallet AML checks are a separate API: apiaml.profenergy.io.

How it works

A USDT (TRC-20) transfer on TRON burns about 65 000 energy (131 000 if the recipient has never held USDT). Without energy the sender pays the fee in TRX. You send us the sender's TRON address and we delegate the energy to it for 1 hour; the address then makes the transfer with no TRX fee. You pay in USDT from the account balance, per address, at the current price.

Authentication

API access is granted per account by an administrator: ask for it in the Telegram bot (💬 Support). Once approved, the 🔑 API section appears in ⚙️ Settings, where you create a key with ➕ New key. The key is shown once, together with the webhook secret. It spends the same USDT balance as the bot; top up in the bot (💰 Top up). Revoked keys and keys of accounts whose access was withdrawn are rejected with 401.

Authorization: Bearer pe_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or
X-Api-Key: pe_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Limits: 60 requests per minute per key and 60 per minute per IP; 20 POST /energy/order per minute; up to 50 addresses per order request; 5 active keys per account. Exceeding a limit returns HTTP 429 rate_limited — wait a minute and retry.

Quick start

  1. Create a key in the bot and top up the USDT balance.
  2. GET /v1/energy/price — see the current price (no key needed).
  3. POST /v1/energy/order with the sender's address and your own client_id — the balance is charged immediately, the order is queued.
  4. Wait for the final status: poll GET /v1/energy/order/{id} every 5 seconds, or pass a callback_url and receive a webhook. delivered — the address has the energy, make the transfer within the hour. failed — the charge is already back on the balance; read error.

Endpoints

GET/v1/energy/price

Current price. No key required. quantity — energy units per address, 65000–5000000, default 65000 (one USDT transfer to an address that already holds USDT; use 131000 for a first-time recipient). The price is indicative: an order is charged at the price current at the moment of the order (the TRX rate is refreshed hourly, the supplier cost is live). valid_for_sec is a caching hint, not a price lock.

curl "https://api.profenergy.io/v1/energy/price?quantity=65000"

{"ok":true,"quantity":65000,"duration":"1h","price_usdt":1.02,"price_trx":3.0,"trx_usd":0.3398,"valid_for_sec":300}

GET/v1/balance

USDT balance of the account. checks is the AML check package and is not used by energy orders.

curl -H "Authorization: Bearer pe_…" https://api.profenergy.io/v1/balance

{"ok":true,"usdt":190.47,"checks":43}

POST/v1/energy/order

Buy energy for one address or a list. Each address is charged and delivered separately, one after another: a single address is usually delivered in 15–40 seconds, a batch of N addresses takes roughly N × 20 seconds in total. The rental lasts 1 hour from delivery.

FieldTypeDescription
addressstringTRON address (T…) of the sender of the upcoming USDT transfer. Use either address or addresses.
addressesstring[]Up to 50 addresses. Duplicates are removed.
quantityintEnergy per address, 65000–5000000. Default 65000.
client_idstringOptional idempotency key (≤64 chars), unique on your side — an invoice or payout id. Repeating a request with the same client_id returns the existing orders with "idempotent":true and charged_usdt 0 — nothing is charged again. Always set it if you retry on network errors.
callback_urlstringOptional https:// URL on a public host; we POST the final status there (see Webhooks).
curl -X POST https://api.profenergy.io/v1/energy/order \
  -H "Authorization: Bearer pe_…" -H "Content-Type: application/json" \
  -d '{"address":"TXYZ…","quantity":65000,"client_id":"inv-1042","callback_url":"https://example.com/hooks/energy"}'

{"ok":true,
 "orders":[{"id":20,"client_id":"inv-1042","address":"TXYZ…","quantity":65000,"duration":"1h","price_usdt":1.02,
            "status":"queued","delegation_hash":null,"energy_now":null,"error":null,
            "created_at":"2026-09-15T11:23:01+00:00","updated_at":"2026-09-15T11:23:01+00:00"}],
 "charged_usdt":1.02,"balance_usdt":189.45}

Batch: pass "addresses":["T…","T…"]. With client_id, each address gets the idempotency key client_id:address. The balance must cover the whole batch up front (402 otherwise). If it still runs out mid-list, the response has "partial":true and not_ordered_from (the first address that was not ordered); orders already created stay. HTTP status is 200 when at least one order was created and 402 when none.

GET/v1/energy/order/{id}

curl -H "Authorization: Bearer pe_…" https://api.profenergy.io/v1/energy/order/20

{"ok":true,"order":{"id":20,"client_id":"inv-1042","address":"TXYZ…","quantity":65000,"duration":"1h","price_usdt":1.02,
 "status":"delivered","delegation_hash":"1fbef2d83f95…","energy_now":64999,"error":null,
 "created_at":"2026-09-15T11:23:01+00:00","updated_at":"2026-09-15T11:23:19+00:00"}}
FieldMeaning
statusqueued — accepted and charged, delivery in progress. delivered — final, energy is on the address. failed — final, the charge has been refunded to the balance; see error.
delegation_hashHash of the TRON transaction that delegated the energy (a DelegateResourceContract); look it up on tronscan to verify. Set on delivered.
energy_nowEnergy available on the address right after delivery (includes energy it already had).
errorReason of a failure, human-readable. The most common one: the address has never had a transaction — see Notes.
price_usdtWhat this address was charged.

An order does not stay queued for long: the delivery is either confirmed or refunded, usually within a minute; in rare supplier delays the re-check runs every 2 minutes. Poll every 5 seconds, or use a webhook.

GET/v1/energy/orders?limit=50

Last orders of the account, newest first (max 100). Same order objects as above.

Webhooks

If callback_url was given, we POST a JSON body when the order reaches a final status (delivered or failed). The URL must be https:// on a public host (private and loopback addresses are rejected with bad_callback). Timeout is 8 seconds; on a non-2xx answer we retry once after 2 seconds, then give up — GET /v1/energy/order/{id} stays the source of truth. The X-Signature header is HMAC-SHA256(raw body, callback_secret) in lowercase hex; the secret is shown together with the key in the bot. Requests come with User-Agent: ProfEnergy-Webhook/1.0.

POST https://example.com/hooks/energy
X-Event: energy.order
X-Signature: 2791824917…

{"event":"energy.order","order":{"id":20,"client_id":"inv-1042","address":"TXYZ…","quantity":65000,"price_usdt":1.02,
 "status":"delivered","delegation_hash":"1fbef2d83f95…","energy_now":64999,"error":null,"updated_at":"2026-09-15T11:23:19+00:00"}}

Verify the signature over the raw request body before parsing it:

# Python
import hmac, hashlib
ok = hmac.compare_digest(hmac.new(SECRET.encode(), raw_body, hashlib.sha256).hexdigest(), request.headers["X-Signature"])

# PHP
$ok = hash_equals(hash_hmac('sha256', file_get_contents('php://input'), $secret), $_SERVER['HTTP_X_SIGNATURE'] ?? '');

Answer 200 quickly and do the work asynchronously; a webhook may arrive twice if your first answer was not 2xx — use order.id to de-duplicate.

Full example

import requests, time

API = "https://api.profenergy.io/v1"
H = {"Authorization": "Bearer pe_…"}

price = requests.get(f"{API}/energy/price", params={"quantity": 65000}).json()["price_usdt"]

r = requests.post(f"{API}/energy/order", headers=H, json={
    "address": "TXYZ…",          # the wallet that will send USDT
    "quantity": 65000,
    "client_id": "payout-1042",  # your unique id: safe to retry
}).json()
if not r["ok"]:
    raise SystemExit(r["error"])  # e.g. insufficient_funds → top up in the bot
order_id = r["orders"][0]["id"]

while True:
    o = requests.get(f"{API}/energy/order/{order_id}", headers=H).json()["order"]
    if o["status"] != "queued":
        break
    time.sleep(5)

if o["status"] == "delivered":
    print("energy on address:", o["energy_now"], "tx:", o["delegation_hash"])  # now send the USDT
else:
    print("failed, refunded:", o["error"])

Errors

Every error is JSON with ok:false and an error.code to branch on; error.message is for logs.

{"ok":false,"error":{"code":"insufficient_funds","message":"Need 1.02 USDT for 1 address(es), balance is 0.20 USDT","need_usdt":1.02,"balance_usdt":0.2}}
HTTPcodeMeaning
400bad_json, bad_address, bad_quantity, too_many_addresses, bad_callbackInvalid request — fix it, do not retry as is
401unauthorizedMissing, invalid or revoked key
402insufficient_fundsTop up the USDT balance in the bot; need_usdt and balance_usdt are included
404not_foundUnknown endpoint or order
413body_too_largeRequest body over 64 KB
429rate_limitedPer-key or per-IP limit exceeded; wait a minute
500internalOrder could not be created; nothing was charged — retry with the same client_id
503maintenance, unavailableService paused / temporary outage — nothing was charged, retry later

Notes

Energy can only be delegated to an activated address — one that has had at least one transaction on TRON. A brand-new wallet must first receive any TRX or USDT; otherwise the order fails and is refunded. Sending USDT to a recipient that has never held USDT needs 131000 energy. Energy not used within the hour is not refunded.

Support: the Telegram bot, section 💬 Support.