# Chain — API reference

Source: https://tenergy.me/docs/api/chain
Last updated: 2026-09-27

Read-only TRON helpers.

| Method | Path | Summary |
|---|---|---|
| `GET` | `/v1/resources/{address}` | Resource situation of an address |
| `GET` | `/v1/status` | Service status |
| `POST` | `/v1/estimate/transfer` | Energy needed for a TRC-20 transfer |

Generated from [`openapi.yaml`](https://tenergy.me/openapi.yaml) at build time. Base URL `https://api.tenergy.me/v1`, or `https://api-nile.tenergy.me/v1` on Nile ([Environments](https://tenergy.me/docs/environments)). Every request below is signed as in [Authentication](https://tenergy.me/docs/authentication) unless its **Auth** line says otherwise.

## Resource situation of an address

`GET /v1/resources/{address}` · `getAddressResources`

**Auth:** Public — no credentials needed; a request signed with an API key (HMAC) is accepted too.

What the chain currently says about an address: whether it is activated, how much free
energy and bandwidth it has, how much is delegated to it and by whom, and which of those
delegations came from us.

Read from our own node with a short cache (`as_of` tells you how fresh it is). Use it to
decide whether an order is needed at all — the cheapest energy is the energy you do not buy.

**Public.** No credentials are needed; anonymous calls are limited per source IP and get
`our_active_orders: []`. A signed request lists that account's own active orders on the
address and is counted against the key's budget.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `address` | path | string | yes |  |

### Responses

| Status | Meaning |
|---|---|
| `200` | OK |
| `400` | Malformed request — bad JSON, unknown field, wrong type. |
| `401` | Missing, malformed or rejected credentials. |
| `429` | Too many requests. |
| `500` | Something broke on our side. |
| `503` | Temporarily unable to serve. On order creation this is fail-secure: nothing was stored and nothing was charged, so retrying verbatim with the same `client_order_id` is safe. |

#### Response fields (`AddressResources`)

| Field | Type | Required | Description |
|---|---|---|---|
| `address` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `activated` | boolean | yes | False for an address that has never received anything on chain. |
| `balance_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `holds_usdt` | boolean \| null |  | Whether the address holds a non-zero USDT (TRC-20) balance — `balanceOf > 0` on the network's USDT contract. A USDT transfer TO an address that holds none writes a new storage slot and costs about twice the energy (~131k instead of ~65k). `null` when the read failed; the rest of the response is unaffected. |
| `energy` | object | yes |  |
| `energy.limit` | integer |  | Total energy the address may use. |
| `energy.used` | integer |  |  |
| `energy.available` | integer |  | `limit - used`. What a transfer can spend now. |
| `energy.delegated_in` | integer |  | Part of the limit that came from delegations. |
| `bandwidth` | object | yes |  |
| `bandwidth.limit` | integer |  |  |
| `bandwidth.used` | integer |  |  |
| `bandwidth.available` | integer |  |  |
| `bandwidth.delegated_in` | integer |  |  |
| `bandwidth.free_net_limit` | integer |  | The daily free bandwidth allowance, included in `limit`. |
| `our_active_orders` | array of object |  | This account's own currently-active orders delivering to this address. Delegations from other providers or other accounts are counted in `delegated_in` but are not listed — we cannot attribute them. |
| `our_active_orders[].order_id` | string |  |  |
| `our_active_orders[].amount` | integer |  |  |
| `our_active_orders[].resource` | enum: `energy`, `bandwidth`, `activation` |  | `energy` — TRON energy, the resource a TRC-20 transfer consumes. · `bandwidth` — TRON bandwidth (net), consumed by transaction size. · `activation` — one-off account activation; `amount` and `tier` do not apply. |
| `our_active_orders[].expires_at` | string (date-time) |  |  |
| `as_of` | string (date-time) | yes | When this was read from the chain. Cached for a few seconds. |

Example `200` response, from the contract (illustrative values — live numbers come from the API):

```json
{
  "address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
  "activated": true,
  "balance_sun": 4120000,
  "holds_usdt": true,
  "energy": {"limit":131000,"used":0,"available":131000,"delegated_in":131000},
  "bandwidth": {"limit":1600,"used":0,"available":1600,"delegated_in":0,"free_net_limit":600},
  "our_active_orders": [
    {
      "order_id": "ord_01J9Z5P8T3WQ",
      "amount": 65000,
      "resource": "energy",
      "expires_at": "2026-09-11T19:04:07.900Z"
    }
  ],
  "as_of": "2026-09-11T18:40:00.000Z"
}
```

## Service status

`GET /v1/status` · `getStatus`

**Auth:** Public.

Whether TEnergy is working right now, component by component: the database, incoming
payments (how long ago the payment scanner last advanced), energy delivery over the last
hour (orders, failures, median seconds from order to delegation) and energy available to
sell. `status` is the worst component. Delivery is judged only on an hour with at least 3
orders; a quiet hour is not an incident.

**Public.** No credentials are needed. The answer is cached for 10 seconds. It is `503` when
a component is `down`, so a plain HTTP check alerts without reading the body.

### Responses

| Status | Meaning |
|---|---|
| `200` | Operational or degraded |
| `429` | Too many requests. |
| `503` | A component is down; the body has the same shape. |

#### Response fields (`ServiceStatus`)

| Field | Type | Required | Description |
|---|---|---|---|
| `status` | enum: `operational`, `degraded`, `down` | yes |  |
| `network` | enum: `mainnet`, `nile` | yes |  |
| `as_of` | string (date-time) | yes |  |
| `components` | object | yes |  |
| `components.api` | object | yes |  |
| `components.api.status` | enum: `operational`, `degraded`, `down` | yes |  |
| `components.database` | object | yes |  |
| `components.database.status` | enum: `operational`, `degraded`, `down` | yes |  |
| `components.payments` | object | yes |  |
| `components.payments.status` | enum: `operational`, `degraded`, `down` | yes |  |
| `components.payments.scanner_updated_s_ago` | integer \| null | yes | Seconds since the payment scanner last advanced; null before its first block. |
| `components.delivery` | object | yes |  |
| `components.delivery.status` | enum: `operational`, `degraded`, `down` | yes |  |
| `components.delivery.orders_1h` | integer | yes |  |
| `components.delivery.failed_1h` | integer | yes |  |
| `components.delivery.median_delivery_s_1h` | integer \| null | yes |  |
| `components.supply` | object | yes |  |
| `components.supply.status` | enum: `operational`, `degraded`, `down` | yes |  |
| `components.supply.available_energy` | integer | yes | Energy that can be sold right now for 1 hour. |

Example `200` response, from the contract (illustrative values — live numbers come from the API):

```json
{
  "status": "operational",
  "network": "mainnet",
  "as_of": "2026-09-29T10:00:00.000Z",
  "components": {
    "api": {"status":"operational"},
    "database": {"status":"operational"},
    "payments": {"status":"operational","scanner_updated_s_ago":3},
    "delivery": {"status":"operational","orders_1h":42,"failed_1h":0,"median_delivery_s_1h":6},
    "supply": {"status":"operational","available_energy":18500000}
  }
}
```

## Energy needed for a TRC-20 transfer

`POST /v1/estimate/transfer` · `estimateTransferEnergy`

**Auth:** API key (HMAC).

How much energy a TRC-20 transfer from `from_address` to `to_address` will consume, and
what renting that much would cost. Defaults to USDT (`TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t`)
when `contract_address` is omitted.

The number depends on whether the recipient already holds a non-zero balance of that
token — a first-time recipient costs roughly twice as much — which is why both addresses
are required. The estimate is produced by a `triggerConstantContract` simulation against
our node, so it reflects the current contract state, not a table.

Add a safety margin before ordering: the simulation is taken now and the transfer is
broadcast later, and the recipient's balance may change in between. `recommended_amount`
already includes the platform's margin and is the number to order.

### Request body

JSON (`TransferEstimateRequest`), required.

| Field | Type | Required | Description |
|---|---|---|---|
| `from_address` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `to_address` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `contract_address` | string |  | TRC-20 contract. Defaults to USDT `TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t`. |
| `amount` | string \| null |  | Transfer amount in the token's smallest unit, as a decimal string to avoid precision loss on large values. Affects the simulation only marginally; omit if unknown. |
| `tier` | enum: `5m`, `15m`, `1h`, `1d`, `3d`, `30d` |  | Tier to price the rental at. Defaults to `1h`. |

Example request body, from the contract (illustrative values):

```json
{
  "from_address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
  "to_address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

### Responses

| Status | Meaning |
|---|---|
| `200` | OK |
| `400` | Malformed request — bad JSON, unknown field, wrong type. |
| `401` | Missing, malformed or rejected credentials. |
| `429` | Too many requests. |
| `500` | Something broke on our side. |
| `503` | Temporarily unable to serve. On order creation this is fail-secure: nothing was stored and nothing was charged, so retrying verbatim with the same `client_order_id` is safe. |

#### Response fields (`TransferEstimate`)

| Field | Type | Required | Description |
|---|---|---|---|
| `from_address` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `to_address` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `contract_address` | string | yes | Base58Check TRON address (starts with `T`, 34 characters). |
| `recipient_holds_token` | boolean |  | Whether the recipient already has a non-zero balance of this token. A first-time recipient roughly doubles the energy cost, which is the single biggest factor here. |
| `energy_required` | integer | yes | Energy the simulated transfer consumed. |
| `recommended_amount` | integer | yes | What to actually order — `energy_required` plus a safety margin for state drift between this estimate and the broadcast. Order this, not `energy_required`. |
| `bandwidth_required` | integer |  |  |
| `tier` | enum: `5m`, `15m`, `1h`, `1d`, `3d`, `30d` |  | Rental period. The API sells `5m` and `1h`; `1d` exists but is switched off. `15m`, `3d` and `30d` are retired and never sold — they stay in the enum only so old orders parse. Check `available` on each `GET /v1/prices` row; a tier that is not available is rejected with `2003 tier_unavailable`. |
| `price_sun_per_unit` | integer |  |  |
| `energy_amount_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `activate_amount_sun` | integer (int64) |  | Activation fee for `to_address` when it is not yet activated. |
| `total_amount_sun` | integer (int64) |  | An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer. |
| `burn_alternative_sun` | integer (int64) |  | What the same transfer would cost in burned TRX at the current network energy price, for comparison. Computed from the chain parameter (`getEnergyFee`), not from a stored constant. That parameter has been **100 SUN per energy since 2025-08-29**; the example is `130,285 × 100`. Any code or example still using 210 is reading a stale hard-coded constant. |
| `as_of` | string (date-time) | yes |  |

Example `200` response, from the contract (illustrative values — live numbers come from the API):

```json
{
  "from_address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
  "to_address": "TXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "recipient_holds_token": false,
  "energy_required": 130285,
  "recommended_amount": 131000,
  "bandwidth_required": 345,
  "tier": "1h",
  "price_sun_per_unit": 20,
  "energy_amount_sun": 2620000,
  "activate_amount_sun": 1200000,
  "total_amount_sun": 3820000,
  "burn_alternative_sun": 13028500,
  "as_of": "2026-09-11T18:41:00.000Z"
}
```
