Docs menu

Account — API reference

Who am I, what is my balance, where do I send money.

MethodPathSummary
GET/v1/accountAccount information
PATCH/v1/accountEdit the account’s display name
GET/v1/balanceBalances only
GET/v1/deposit-addressesDeposit addresses for this account
GET/v1/ledgerThe account’s ledger statement
GET/v1/account/addressesThe account’s address book
POST/v1/account/addressesSave an address
DELETE/v1/account/addresses/{entryId}Remove an address
GET/v1/account/statsOrder analytics, aggregated server-side

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

Account information

GET /v1/account · getAccount

Auth: API key (HMAC) or bootstrap token.

Identity, balances, deposit addresses, the limits in force and lifetime counters. This is the endpoint a CatFee-compatible facade maps GET /v1/account onto.

Also readable with a bootstrap token (Authorization: Bearer abt_…), so the signup flow can poll for the first confirmed deposit without an API key.

Responses

StatusMeaning
200OK
401Missing, malformed or rejected credentials.
429Too many requests.
500Something broke on our side.

Response fields (Account)

FieldTypeRequiredDescription
idstringyes
brandstringyesThe brand this account belongs to. Accounts are not shared across brands.
networkenum: mainnet, nileyesThe environment this account belongs to. An account, its ledger and its keys do not span environments: a Nile account is a separate account on the api-nile.<brand-domain> host.
owner_addressstring | nullThe address that signed the challenge this account was created with; the root of recovery. null only for legacy accounts created before the challenge model.
labelstring | nullThe same value as display_name, under the name this field has always had. New clients should read display_name; this one is not going away.
display_namestring | nullThe account’s own title, chosen by its owner and editable with PATCH /v1/account. null when it has none, in which case a UI shows the shortened owner_address instead of an internal id.
statusenum: unfunded, active, suspended, closedyes
balance_suninteger (int64)yesAn amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
balance_usdtinteger (int64)USDT balance in the token’s smallest unit (6 decimals).
reserved_suninteger (int64)Held against in-flight orders. Not spendable.
deposit_addressesarray of object (DepositAddress)yes
deposit_addresses[].currencyenum: TRX, USDTyes
deposit_addresses[].addressstringyesBase58Check TRON address (starts with T, 34 characters).
deposit_addresses[].memostring | nullAlways null since 2026-09-26: every account has an address of its own, so no memo is needed and any memo is ignored. Kept so existing clients do not break.
deposit_addresses[].confirmations_requiredintegerBlocks waited before the deposit is credited.
deposit_addresses[].contractstring | nullThe TRC-20 contract accepted at this address (USDT row only; null for TRX).
deposit_addresses[].rate_nownull | objectUSDT row only. The current SunSwap (or fixed) TRX-per-USDT rate BEFORE the spread, cached 60 s. null when no rate is available right now; the deposit is still accepted and the worker prices it at credit time. Indicative: the credit uses the rate the worker reads when it credits, not this one.
deposit_addresses[].rate_now.trx_per_usdtstringyes
deposit_addresses[].rate_now.sourceenum: sunswap_v3, fixed_envyes
deposit_addresses[].rate_now.atstring (date-time)yes
deposit_addresses[].spread_bpsinteger | nullUSDT row only: basis points taken off the rate (5 = 0.05 %).
deposit_addresses[].minstring | nullUSDT row only: smallest credited USDT deposit; smaller ones are held (held_below_min).
deposit_addresses[].maxstring | nullUSDT row only: largest auto-credited USDT deposit; larger ones are held (held_for_review).
limitsobject
limits.max_order_energyinteger
limits.max_batch_receiversinteger
limits.orders_per_secondinteger
totalsobjectLifetime counters. Informational; not a substitute for the ledger.
totals.deposited_suninteger (int64)An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
totals.spent_suninteger (int64)An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
totals.refunded_suninteger (int64)An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
totals.orders_createdinteger
totals.energy_delegatedinteger (int64)
created_atstring (date-time)yes

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

json
{
  "id": "acc_01J9Z4K2M7Q8",
  "brand": "tenergy.me",
  "network": "mainnet",
  "label": "Acme payments",
  "status": "active",
  "balance_sun": 1250400000,
  "balance_usdt": 0,
  "reserved_sun": 0,
  "deposit_addresses": [{"currency":"TRX","address":"TDepositAddressExample1111111111111"}],
  "limits": {"max_order_energy":3000000,"max_batch_receivers":100,"orders_per_second":30},
  "totals": {
    "deposited_sun": 5000000000,
    "spent_sun": 3749600000,
    "refunded_sun": 0,
    "orders_created": 1842,
    "energy_delegated": 119730000
  },
  "created_at": "2026-04-02T09:11:00.000Z"
}

Edit the account’s display name

PATCH /v1/account · updateAccount

Auth: Dashboard session cookie + X-CSRF-Token.

The account’s own title, shown wherever the account is named. null clears it and the display falls back to the shortened owner address — never to an internal id.

A dashboard session operation, and the account’s owner: the title is what every member sees and what support reads back in a ticket. It is a setting; nothing about who may reach what changes here.

Request body

JSON (AccountPatch), required.

FieldTypeRequiredDescription
display_namestring | nullThe account’s title. Trimmed; must not be blank and must carry no control characters. null clears it.

Responses

StatusMeaning
200Updated
400Malformed request — bad JSON, unknown field, wrong type.
401Missing, malformed or rejected credentials.
403Authenticated, but this key is not allowed to do it.
422Syntactically valid but semantically impossible.
500Something broke on our side.

Response fields (Account)

FieldTypeRequiredDescription
idstringyes
brandstringyesThe brand this account belongs to. Accounts are not shared across brands.
networkenum: mainnet, nileyesThe environment this account belongs to. An account, its ledger and its keys do not span environments: a Nile account is a separate account on the api-nile.<brand-domain> host.
owner_addressstring | nullThe address that signed the challenge this account was created with; the root of recovery. null only for legacy accounts created before the challenge model.
labelstring | nullThe same value as display_name, under the name this field has always had. New clients should read display_name; this one is not going away.
display_namestring | nullThe account’s own title, chosen by its owner and editable with PATCH /v1/account. null when it has none, in which case a UI shows the shortened owner_address instead of an internal id.
statusenum: unfunded, active, suspended, closedyes
balance_suninteger (int64)yesAn amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
balance_usdtinteger (int64)USDT balance in the token’s smallest unit (6 decimals).
reserved_suninteger (int64)Held against in-flight orders. Not spendable.
deposit_addressesarray of object (DepositAddress)yes
deposit_addresses[].currencyenum: TRX, USDTyes
deposit_addresses[].addressstringyesBase58Check TRON address (starts with T, 34 characters).
deposit_addresses[].memostring | nullAlways null since 2026-09-26: every account has an address of its own, so no memo is needed and any memo is ignored. Kept so existing clients do not break.
deposit_addresses[].confirmations_requiredintegerBlocks waited before the deposit is credited.
deposit_addresses[].contractstring | nullThe TRC-20 contract accepted at this address (USDT row only; null for TRX).
deposit_addresses[].rate_nownull | objectUSDT row only. The current SunSwap (or fixed) TRX-per-USDT rate BEFORE the spread, cached 60 s. null when no rate is available right now; the deposit is still accepted and the worker prices it at credit time. Indicative: the credit uses the rate the worker reads when it credits, not this one.
deposit_addresses[].rate_now.trx_per_usdtstringyes
deposit_addresses[].rate_now.sourceenum: sunswap_v3, fixed_envyes
deposit_addresses[].rate_now.atstring (date-time)yes
deposit_addresses[].spread_bpsinteger | nullUSDT row only: basis points taken off the rate (5 = 0.05 %).
deposit_addresses[].minstring | nullUSDT row only: smallest credited USDT deposit; smaller ones are held (held_below_min).
deposit_addresses[].maxstring | nullUSDT row only: largest auto-credited USDT deposit; larger ones are held (held_for_review).
limitsobject
limits.max_order_energyinteger
limits.max_batch_receiversinteger
limits.orders_per_secondinteger
totalsobjectLifetime counters. Informational; not a substitute for the ledger.
totals.deposited_suninteger (int64)An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
totals.spent_suninteger (int64)An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
totals.refunded_suninteger (int64)An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
totals.orders_createdinteger
totals.energy_delegatedinteger (int64)
created_atstring (date-time)yes

Balances only

GET /v1/balance · getBalance

Auth: API key (HMAC).

A deliberately small response for callers that poll before every order. Cheaper than /account and on the read rate-limit budget.

Responses

StatusMeaning
200OK
401Missing, malformed or rejected credentials.
429Too many requests.
500Something broke on our side.

Response fields (Balance)

FieldTypeRequiredDescription
balance_suninteger (int64)yesAn amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
balance_usdtinteger (int64)
reserved_suninteger (int64)An amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
available_suninteger (int64)yesbalance_sun - reserved_sun. This is what an order can draw on.
as_ofstring (date-time)yes

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

json
{
  "balance_sun": 1250400000,
  "balance_usdt": 0,
  "reserved_sun": 0,
  "available_sun": 1250400000,
  "as_of": "2026-09-11T18:04:05.123Z"
}

Deposit addresses for this account

GET /v1/deposit-addresses · listDepositAddresses

Auth: API key (HMAC).

The account’s own deposit address: a TRON address that belongs to this account alone, so no memo is needed (memo is always null). Two rows, same address: TRX, and USDT (TRC-20, contract), which the ledger credits as TRX at rate_now minus spread_bps, between min and max USDT. The address is issued on the first read if the account has none yet.

A deposit is credited after the configured number of block confirmations (confirmations_required), and produces a balance.credited webhook.

Support can replace the address (never the customer; at most once per rotation.min_interval_days and rotation.max_per_window times per rotation.window_days). A replaced address is listed under retired and still credits until credited_until (rotation.retired_credit_days after it was retired).

Responses

StatusMeaning
200OK
401Missing, malformed or rejected credentials.
429Too many requests.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
dataarray of object (DepositAddress)yes
data[].currencyenum: TRX, USDTyes
data[].addressstringyesBase58Check TRON address (starts with T, 34 characters).
data[].memostring | nullAlways null since 2026-09-26: every account has an address of its own, so no memo is needed and any memo is ignored. Kept so existing clients do not break.
data[].confirmations_requiredintegerBlocks waited before the deposit is credited.
data[].contractstring | nullThe TRC-20 contract accepted at this address (USDT row only; null for TRX).
data[].rate_nownull | objectUSDT row only. The current SunSwap (or fixed) TRX-per-USDT rate BEFORE the spread, cached 60 s. null when no rate is available right now; the deposit is still accepted and the worker prices it at credit time. Indicative: the credit uses the rate the worker reads when it credits, not this one.
data[].rate_now.trx_per_usdtstringyes
data[].rate_now.sourceenum: sunswap_v3, fixed_envyes
data[].rate_now.atstring (date-time)yes
data[].spread_bpsinteger | nullUSDT row only: basis points taken off the rate (5 = 0.05 %).
data[].minstring | nullUSDT row only: smallest credited USDT deposit; smaller ones are held (held_below_min).
data[].maxstring | nullUSDT row only: largest auto-credited USDT deposit; larger ones are held (held_for_review).
retiredarray of objectAddresses this account used before, newest first.
retired[].addressstringyesBase58Check TRON address (starts with T, 34 characters).
retired[].retired_atstring (date-time)yes
retired[].credited_untilstring (date-time)yesA transfer to this address in a block after this instant is not credited automatically; contact support.
rotationobjectWho may replace the address, and how often.
rotation.byenum: supportyes
rotation.min_interval_daysintegeryes
rotation.max_per_windowintegeryes
rotation.window_daysintegeryes
rotation.retired_credit_daysintegeryes

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

json
{
  "data": [
    {
      "currency": "TRX",
      "address": "TDepositAddressExample1111111111111",
      "memo": null,
      "confirmations_required": 19
    }
  ],
  "retired": [
    {
      "address": "TRetiredAddressExample111111111111",
      "retired_at": "2026-09-20T10:00:00.000Z",
      "credited_until": "2026-10-20T10:00:00.000Z"
    }
  ],
  "rotation": {
    "by": "support",
    "min_interval_days": 7,
    "max_per_window": 3,
    "window_days": 90,
    "retired_credit_days": 30
  }
}

The account’s ledger statement

GET /v1/ledger · listLedger

Auth: Dashboard session cookie + X-CSRF-Token.

Every journal that moved this account’s balance, newest first: deposits, order charges, refunds and the rest. amount_sun / amount_usdt are the net effect on the balance — positive when it went up. kind=deposit is the deposit history of the top-up screen.

A deposit appears here once it is credited, i.e. after confirmations_required block confirmations; a transfer still confirming is not listed yet. sender and block_number are null on deposits credited before 2026-09-25.

Dashboard session only (member role viewer or above). No API-key scope opens it: the ledger shows senders and transaction ids that no key-readable endpoint shows today, and extending balance.read to it is an access decision that has not been taken.

Parameters

NameInTypeRequiredDescription
kindqueryenum: deposit, all
limitqueryinteger
cursorquerystringOpaque cursor from a previous response’s next_cursor.

Responses

StatusMeaning
200OK
400Malformed request — bad JSON, unknown field, wrong type.
401Missing, malformed or rejected credentials.
403Authenticated, but this key is not allowed to do it.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
dataarray of object (LedgerEntry)yes
data[].idstringyesThe ledger journal id.
data[].kindenum: deposit, order_charge, order_refund, referral_payout, subscription_fee, subscription_usage, reserve_fee, invoice, withdrawal, adjustmentyes
data[].amount_suninteger (int64)yesNet effect on the TRX balance in SUN; negative for a charge.
data[].amount_usdtinteger (int64)yesNet effect on the USDT balance in the token’s smallest unit.
data[].order_idstring | nullyesThe order a charge or refund belongs to.
data[].depositnull | objectyesSet for kind = deposit, null otherwise.
data[].deposit.txidstring | nullyesThe deposit transaction hash.
data[].deposit.senderstring | nullyesThe address the TRX came from; null on deposits credited before 2026-09-25.
data[].deposit.block_numberinteger | nullyes
data[].deposit.statusenum: credited, pending_rate, held_below_min, held_for_reviewyescredited for every journal. With kind=deposit, USDT deposits the worker saw but did not credit are listed too (first page only): held_below_min, held_for_review or pending_rate, with amount_sun 0 — nothing was credited.
data[].deposit.confirmations_requiredintegeryes
data[].deposit.assetenum: TRX, USDT
data[].deposit.usdt_amountstring | nullUSDT received (decimal string); null for TRX.
data[].deposit.ratestring | nullSUN credited per 1 USDT, after the spread; null for TRX and held rows.
data[].deposit.rate_sourcestring | nullWhere the rate came from (fixed_env, sunswap_v3@<block>, …); null for TRX.
data[].deposit.spread_bpsinteger | null
data[].created_atstring (date-time)yes
next_cursorstring | nullyes

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

json
{
  "data": [
    {
      "id": "jrn_01K5Y8Q2V9M3ZP4T7R1A2B3C4D",
      "kind": "order_charge",
      "amount_sun": -3900000,
      "amount_usdt": 0,
      "order_id": "ord_01K5Y8Q2V9M3ZP4T7R1A2B3C4E",
      "deposit": null,
      "created_at": "2026-09-25T10:12:04.000Z"
    },
    {
      "id": "jrn_01K5Y7A1B2C3D4E5F6G7H8J9K0",
      "kind": "deposit",
      "amount_sun": 50000000,
      "amount_usdt": 0,
      "order_id": null,
      "deposit": {
        "txid": "9f3c1e7a2b4d6f8091a3c5e7f9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7",
        "sender": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
        "block_number": 61000123,
        "status": "credited",
        "confirmations_required": 19
      },
      "created_at": "2026-09-25T09:58:40.000Z"
    }
  ],
  "next_cursor": null
}

The account’s address book

GET /v1/account/addresses · listAddressBook

Auth: Dashboard session cookie + X-CSRF-Token.

Receivers this account saved for reuse, newest first. At most limit (100) entries.

Dashboard session only (member role viewer or above). No API-key scope opens it yet; opening it to balance.read keys is an access decision that has not been taken.

Responses

StatusMeaning
200OK
401Missing, malformed or rejected credentials.
403Authenticated, but this key is not allowed to do it.
500Something broke on our side.

Response fields

FieldTypeRequiredDescription
dataarray of object (AddressBookEntry)yes
data[].idstringyes
data[].labelstringyes
data[].addressstringyesBase58Check TRON address (starts with T, 34 characters).
data[].created_atstring (date-time)yes
data[].updated_atstring (date-time)yes
limitintegeryes
usedintegeryes

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

json
{
  "data": [
    {
      "id": "adr_01K5Y9B7C8D9E0F1G2H3J4K5M6",
      "label": "Payouts hot wallet",
      "address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
      "created_at": "2026-09-25T10:20:00.000Z",
      "updated_at": "2026-09-25T10:20:00.000Z"
    }
  ],
  "limit": 100,
  "used": 1
}

Save an address

POST /v1/account/addresses · saveAddressBookEntry

Auth: Dashboard session cookie + X-CSRF-Token.

Adds address under label. The address is unique per account: saving one that is already in the book replaces its label, answers 200 with the existing entry and uses no slot. A new address on a full book is 3019 address_book_full.

Dashboard session, member role editor or above, with X-CSRF-Token.

Request body

JSON (AddressBookRequest), required.

FieldTypeRequiredDescription
labelstringyesTrimmed; 1–64 characters after trimming.
addressstringyesBase58Check TRON address (starts with T, 34 characters).

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

json
{"label":"Payouts hot wallet","address":"TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE"}

Responses

StatusMeaning
200The address was already saved; its label was replaced.
201Saved as a new entry.
400Malformed request — bad JSON, unknown field, wrong type.
401Missing, malformed or rejected credentials.
403Authenticated, but this key is not allowed to do it.
4093019 address_book_full — details.limit, details.used.
500Something broke on our side.

Response fields (AddressBookEntry)

FieldTypeRequiredDescription
idstringyes
labelstringyes
addressstringyesBase58Check TRON address (starts with T, 34 characters).
created_atstring (date-time)yes
updated_atstring (date-time)yes

Remove an address

DELETE /v1/account/addresses/{entryId} · deleteAddressBookEntry

Auth: Dashboard session cookie + X-CSRF-Token.

Frees the slot immediately. An id of another account answers 404, like an id that does not exist. Dashboard session, member role editor, with X-CSRF-Token.

Parameters

NameInTypeRequiredDescription
entryIdpathstringyes

Responses

StatusMeaning
204Removed. No body.
401Missing, malformed or rejected credentials.
403Authenticated, but this key is not allowed to do it.
404No such object, or it belongs to another account. The two are not distinguished.
500Something broke on our side.

Order analytics, aggregated server-side

GET /v1/account/stats · getAccountStats

Auth: API key (HMAC) or dashboard session cookie + X-CSRF-Token.

What the Analytics screen draws, computed next to the data rather than by summing orders in the page. Covers orders created in [from, to):

fieldwhat is counted
ordersevery order, whatever its status
energydelivered energy of energy orders that reached the chain (delegated … reclaimed): delivered_amount, else amount; failed and refunded orders add none
spent_suntotal_amount_sun − refunded_amount_sun of every order, activation included
avg_price_sun_per_65kthe unit price those energy orders were sold at, weighted by delivered energy, × 65,000, rounded to a whole SUN; null without energy

Days and hours are UTC shifted by utc_offset_minutes, so the page can ask for its visitor’s calendar. series has one row per day of the range, zeros included. weekday_hour[d][h] counts orders on ISO weekday d + 1 (Monday first) at hour h.

Retention: 13 months. A from older than that is clamped to the retention start; clamped is true and requested_from echoes what was asked. Defaults: to = now, from = to − 30 days. to must be after from (2001 otherwise).

API key scope orders.read (the aggregates are sums over the orders that scope already lists), or a dashboard session with member role viewer.

Parameters

NameInTypeRequiredDescription
fromquerystring (date-time)
toquerystring (date-time)
bucketqueryenum: day
utc_offset_minutesqueryinteger

Responses

StatusMeaning
200OK
400Malformed request — bad JSON, unknown field, wrong type.
401Missing, malformed or rejected credentials.
403Authenticated, but this key is not allowed to do it.
429Too many requests.
500Something broke on our side.

Response fields (AccountStats)

FieldTypeRequiredDescription
fromstring (date-time)yesThe start actually used
tostring (date-time)yes
requested_fromstring (date-time)yes
clampedbooleanyesTrue when from was older than the retention window and was moved forward.
retention_monthsintegeryes
bucketenum: dayyes
utc_offset_minutesintegeryes
totalsobjectyes
totals.ordersintegeryes
totals.energyintegeryes
totals.spent_suninteger (int64)yesAn amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
totals.avg_price_sun_per_65kinteger | nullyes
seriesarray of objectyes
series[].datestring (date)yes
series[].ordersintegeryes
series[].energyintegeryes
series[].spent_suninteger (int64)yesAn amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.
weekday_hourarray of array of integeryesSeven rows (Monday first) of 24 hourly order counts.
top_receiversarray of objectyes
top_receivers[].receiverstringyesBase58Check TRON address (starts with T, 34 characters).
top_receivers[].ordersintegeryes
top_receivers[].energyintegeryes
top_receivers[].spent_suninteger (int64)yesAn amount in SUN (1 TRX = 1 000 000 SUN). Always an integer.

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

json
{
  "from": "2026-09-23T00:00:00.000Z",
  "to": "2026-09-25T00:00:00.000Z",
  "requested_from": "2026-09-23T00:00:00.000Z",
  "clamped": false,
  "retention_months": 13,
  "bucket": "day",
  "utc_offset_minutes": 0,
  "totals": {"orders":3,"energy":196000,"spent_sun":11760000,"avg_price_sun_per_65k":3900000},
  "series": [
    {"date":"2026-09-23","orders":1,"energy":65000,"spent_sun":3900000},
    {"date":"2026-09-24","orders":2,"energy":131000,"spent_sun":7860000}
  ],
  "weekday_hour": [[0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0]],
  "top_receivers": [
    {
      "receiver": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
      "orders": 2,
      "energy": 131000,
      "spent_sun": 7860000
    }
  ]
}

    ↑ ↓ to move · Enter to open · Esc to close