Skip to main content

Errors & conventions

This page is the reference for how the TRONAgg API reports failures and the cross-cutting rules every endpoint follows: the error envelope, the full error-code catalog, idempotency on purchases, the pagination styles, and the units and formats you will see in every response.

The error envelope

Errors use the standard HTTP status code plus a JSON body with a top-level detail. Most endpoints put a structured object in detail: a machine-readable error code, a human-readable message, and — for a few errors — extra context fields.

{
"detail": {
"error": "insufficient_balance",
"current_balance": 1200000,
"required_amount": 3500000
}
}

Branch on detail.error; show detail.message to a human when present.

Honest exceptions

A few responses do not follow the object-with-error shape. Handle them defensively — read detail, and:

  • Plain-string detail. Some responses set detail to a bare string instead of an object. These are:

    • 401 on any API-key endpoint"API key required", "Invalid API key", or "User not found".
    • 429 on any API-key endpoint"Rate limit exceeded", with a Retry-After header. See Rate limits.
    • 404 on GET /order/{id}"Order not found" (also returned when the order exists but is not yours).
    • 400 on POST /webhooks when the URL host is not a public host — e.g. "Webhook URL must use a public host", "Webhook URL must include a host", "Webhook host could not be resolved".
    { "detail": "Order not found" }
  • Object keyed by code, not error. The order-amount-limit errors on POST /buy use code (plus min / max) — see Order amount limits.

  • Request-validation 422. A malformed request body or an out-of-range query parameter (for example resource_amount ≤ 0, or page_size above 100) is rejected by the framework with 422 and a detail array of field errors.

    { "detail": [ { "loc": ["query", "resource_amount"], "msg": "...", "type": "..." } ] }

A robust client therefore checks the type of detail: object → branch on detail.error (falling back to detail.code); string → treat as a human message; array → request-validation error.

Error codes

Programmatic API

error codeHTTPEndpoint(s)Extra fieldsWhen
unsupported_resource400GET /estimate, POST /buyresource_type other than ENERGY.
invalid_duration400GET /estimate, POST /buyduration other than 1h.
invalid_idempotency_key400POST /buyIdempotency-Key longer than 128 characters.
insufficient_balance400POST /buycurrent_balance, required_amountBalance below the order total. No message field on this endpoint.
validation_error400POST /buy, POST /webhooksmessagePurchase rejected on validation, or a rejected webhook URL (e.g. not HTTPS).
invalid_cursor400GET /transactionsmessageThe cursor value could not be parsed.
duplicate_request409POST /buyA request with the same Idempotency-Key is still in flight.
not_found404DELETE /webhooks/{id}, POST /webhooks/{id}/testmessageNo such webhook for this account.
delivery_failed502POST /webhooks/{id}/testmessageThe test delivery did not succeed.
service_unavailable503GET /estimate, POST /buymessageEnergy purchasing is temporarily unavailable.
internal_error500POST /buymessageUnexpected server error (captured for investigation). Retry later.

For the order_amount_below_minimum / order_amount_above_maximum codes on POST /buy, see Order amount limits.

AutoEnergy

The AutoEnergy endpoints (/autoenergy/*) all use the object envelope — {"error": <code>, "message": <text>} — with these codes:

error codeHTTPWhen
plan_not_found400The requested plan does not exist.
insufficient_balance400Balance too low to start or continue the subscription. (Carries message here, unlike POST /buy.)
not_found404No such subscription for this account.
address_busy409The address is currently being processed; retry shortly.
address_exists409An active subscription already covers this address.
not_reactivatable409The subscription cannot be reactivated in its current state.
not_deletable409The subscription cannot be deleted in its current state.
invalid_address422The address is not a valid TRON address.
fulfiller_unavailable502The fulfilment backend could not be reached; retry.
autoenergy_temporarily_unavailable503AutoEnergy is temporarily unavailable; retry later.
internal_error500Unexpected server error (captured for investigation). Retry later.

Rate limits

Each account may make 1,000 requests per minute across all of its API keys. Past that the API answers 429 with a plain-string detail and a Retry-After header holding the number of seconds until the window resets — wait that long and retry. Order placement is idempotent (see below), so a retried POST /buy after a 429 is safe.

HTTP/1.1 429 Too Many Requests
Retry-After: 23

{ "detail": "Rate limit exceeded" }

Need more? Contact support with your expected request rate.

Idempotency

POST /buy is the only money-moving write, so it accepts an Idempotency-Key header to make retries safe:

  • Send any unique string of ≤ 128 characters (a UUID is a good choice). A longer key returns 400 invalid_idempotency_key.
  • The first request with a given key is processed; its response is cached for 24 hours and returned verbatim for any later request that reuses the same key — so a network retry never places a second order.
  • If a duplicate arrives while the first is still being processed, it returns 409 duplicate_request. Wait and retry; you will then get the cached original response.
  • Keys are scoped per account. Reusing a key across two genuinely different purchases returns the first purchase's response, not a new order.

The header is optional but strongly recommended for any automated buyer.

Pagination

Three list endpoints exist, and — for historical reasons — each paginates differently. Read each on its own terms.

EndpointRequest paramsResponse fieldsStyle
GET /orderspage (≥ 1), page_size (1–100)orders, total, page, page_sizePage-numbered, with a full total count.
GET /transactionslimit (1–100), cursortransactions, has_more, next_cursorCursor-based. Pass the previous next_cursor back as cursor to get the next page; stop when has_more is false.
GET /depositslimit (1–100), offset (≥ 0)deposits, has_moreLimit/offset. Advance offset by limit each page; stop when has_more is false.

All three return newest-first. There is no total on /transactions or /deposits — use has_more to decide whether to fetch another page.

The receiver_address filter on GET /orders

The optional receiver_address query parameter is a substring match, applied to both the receiver and the buyer address of each order (case-insensitive). A partial value matches any order whose receiver or buyer address contains it; a full 34-character address behaves as an exact match.

Units & formats

  • SUN. All amounts in *_sun fields are integers denominated in SUN, the smallest TRX unit: 1 TRX = 1,000,000 SUN.
  • Decimal amounts are strings. Human-facing TRX amounts (total_price_trx, amount_trx, balance_trx, …) are serialized as JSON strings, not numbers, to preserve exact precision. Parse them with a decimal type, never a float.
  • Order statuses are upper-case. An order's status is one of PENDING, PROCESSING, AWAITING_PAYMENT, COMPLETED, or FAILED. COMPLETED and FAILED are terminal.
  • TRON addresses. Addresses are base58 strings that start with T and are 34 characters long.
  • Timestamps. Time fields (created_at, completed_at, …) are ISO-8601 in UTC.

Order amount limits

Every order has a minimum and maximum resource amount. Read the current bounds from GET /estimate, which returns min_amount and max_amount alongside the price.

POST /buy enforces the same bounds. An out-of-range amount returns 400 with a structured detail that — unlike the other purchase errors — is keyed by code (not error) and carries min / max:

{
"detail": {
"code": "order_amount_below_minimum",
"message": "Order amount 500 is below the minimum (1000). Increase the amount or contact support.",
"min": 1000,
"max": 5000000
}
}

The two codes are order_amount_below_minimum and order_amount_above_maximum. Check GET /estimate first to avoid the round-trip.

Next steps

  • Authentication — the X-API-Key header and the 401 responses above.
  • Buy energy — the purchase endpoint that most of these errors come from.
  • Webhook events — the push alternative to polling for order status.