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
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
- Create a key in the bot and top up the USDT balance.
GET /v1/energy/price— see the current price (no key needed).POST /v1/energy/orderwith the sender's address and your ownclient_id— the balance is charged immediately, the order isqueued.- Wait for the final status: poll
GET /v1/energy/order/{id}every 5 seconds, or pass acallback_urland receive a webhook.delivered— the address has the energy, make the transfer within the hour.failed— the charge is already back on the balance; readerror.
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.
| Field | Type | Description |
|---|---|---|
address | string | TRON address (T…) of the sender of the upcoming USDT transfer. Use either address or addresses. |
addresses | string[] | Up to 50 addresses. Duplicates are removed. |
quantity | int | Energy per address, 65000–5000000. Default 65000. |
client_id | string | Optional 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_url | string | Optional 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"}}
| Field | Meaning |
|---|---|
status | queued — 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_hash | Hash of the TRON transaction that delegated the energy (a DelegateResourceContract); look it up on tronscan to verify. Set on delivered. |
energy_now | Energy available on the address right after delivery (includes energy it already had). |
error | Reason of a failure, human-readable. The most common one: the address has never had a transaction — see Notes. |
price_usdt | What 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}}
| HTTP | code | Meaning |
|---|---|---|
| 400 | bad_json, bad_address, bad_quantity, too_many_addresses, bad_callback | Invalid request — fix it, do not retry as is |
| 401 | unauthorized | Missing, invalid or revoked key |
| 402 | insufficient_funds | Top up the USDT balance in the bot; need_usdt and balance_usdt are included |
| 404 | not_found | Unknown endpoint or order |
| 413 | body_too_large | Request body over 64 KB |
| 429 | rate_limited | Per-key or per-IP limit exceeded; wait a minute |
| 500 | internal | Order could not be created; nothing was charged — retry with the same client_id |
| 503 | maintenance, unavailable | Service 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.