Docs menu

Errors & rate limits

The envelope

json
{ "error": { "code": 4001, "slug": "insufficient_funds",
             "message": "Required 1300000 SUN, available 420000 SUN",
             "field": null, "retryable": true,
             "details": { "required_sun": 1300000, "available_sun": 420000 } },
  "request_id": "req_01J9Z5P8T3WQ7X" }
FieldContract
codeStable integer. Never renumbered, never reused for a different meaning. New conditions get new numbers.
slugStable lowercase snake_case name for the same condition. One-to-one with code.
messageEnglish, human-readable, may change without notice. Show it to a human, never parse it.
fieldThe offending request field for validation errors, otherwise null.
retryableWhether retrying the identical request could plausibly succeed later.
detailsOptional machine-readable context; shape is specific to the code, documented below where it exists.
request_idAlso in the X-Request-Id response header. Quote it in support requests.

Branch on slug or code, never on the HTTP status alone — several distinct conditions share a status (409 covers both an idempotency conflict and an order that cannot be reclaimed, and they call for opposite reactions). Unknown codes will appear: treat one you do not recognise as its status class (4xx “my fault, do not retry blindly”, 5xx “their fault, retry with backoff”). Do not fail closed on an unrecognised slug.

Ranges: 1000–1099 auth/credentials · 1100–1199 rate limiting and quotas · 2000–2099 request validation · 3000–3099 business state · 4000–4099 money · 5000–5099 supply · 9000–9099 internal.

Codes

CodeSlugHTTPWhenRetry
1001missing_credentials401One or more of X-API-KEY, X-API-TIMESTAMP, X-API-SIGN absent. A malformed header value (bad base64, wrong length) is 1002, not 1001; 1001 means the header was not sent at all.No — fix the client.
1002invalid_signature401X-API-SIGN does not match the canonical string the server computed.No. Re-read the canonical string definition; usual causes are re-encoding the query, signing a pretty-printed body while sending a compact one, or a trailing newline.
1003signature_timestamp_skew401X-API-TIMESTAMP more than 5 s from server time, either direction. details.server_time carries our clock.Yes, once, after fixing the clock. Run NTP; do not widen the retry loop.
1004ip_not_allowed401Source address not on this key’s allowlist. details.source_ip echoes what we saw.No. Add it in the dashboard; behind NAT or an egress pool, allowlist the whole block.
1005insufficient_scope403Key valid but lacks the scope this endpoint needs. details.required_scope names it in the one platform permission vocabulary (area.action, e.g. orders.create), documented in openapi.yaml.No — a key’s scopes are chosen explicitly by the account owner, so widening one is a deliberate act, never an automatic retry.
1006key_revoked401The key was deleted or expired.No.
1007key_inactive401The key exists but is switched off.No.
1008account_suspended403The account may read but not order.No. Contact support.
1009replayed_signature401This exact signature was already used; signatures are single-use within the skew window.No — generate a fresh timestamp and signature per attempt, including per retry.
1010challenge_invalid401The signup/login challenge could not be accepted: unknown nonce, expired nonce, nonce already used, or a signature that does not recover the address. One code for all four on purpose — a caller who has not proved control of an address learns nothing about which addresses have accounts. details.reason is "invalid" and carries no detail.Yes, once, after a fresh POST /v1/accounts/challenge.
1011bootstrap_token_expired401The 15-minute bootstrap token from POST /v1/accounts/challenge/verify expired or was used on an operation it does not open (only account creation, the signup deposit address, GET /v1/account and the first key).Yes — re-run the challenge and verify.
1012key_environment_mismatch401The key’s environment marker does not match the network this host serves: an ak_live_… key sent to the test host, or an ak_test_… key sent to the live one. details.key_environment and details.host_environment name both. Answered before the key is looked up, so it says nothing about whether the key exists.No — use the key issued for this host.
1013session_expired401No dashboard session cookie, or the session behind it expired or was signed out.No — sign in again by signing a fresh challenge.
1014csrf_token_invalid403A cookie-authenticated write arrived without an X-CSRF-Token header matching the session’s CSRF cookie.No — read the CSRF cookie and send it on every write.
1016login_code_invalid400The e-mail sign-in code does not match. details.attempts_left is how many guesses this code has left (5 in all).Yes, with the right code; at zero, request a new code.
1017login_code_expired400No live code for this e-mail: never sent, older than 10 minutes, replaced by a newer one, already used, or out of attempts.Yes — request a new code.
1018identity_taken409The e-mail (or other identity) being linked already signs in to another member of this account. One of another account moves here when that account is empty, else 1023.No — write to support.
1019last_identity409Unlinking this sign-in method would leave the account with no way in.No — link another method first.
1020step_up_required403The signed-in person has 2-step on (GET /v1/session/step-up) and this action — withdrawal, API key creation, linking or unlinking a sign-in method, changing the 2-step channel — needs a confirmation. details.step_up_id, details.channel (email, telegram or wallet), details.expires_at (5 minutes), details.message (what is being approved; for wallet, the exact text to sign). For email a code naming the action has just been mailed (details.address: to which of the person’s addresses); for telegram our bot has just sent it.Yes — approve with POST /v1/step-up/{id}/approve, then repeat the identical request with X-Step-Up: <step_up_id>.
1021step_up_invalid403The approval cannot be used: unknown, not approved yet, expired, already used, made for another action or another payload (amount, address), or a wallet signature that does not recover a wallet linked to this person.No — drop X-Step-Up and repeat the request for a fresh confirmation.
1022step_up_channel_unavailable409The 2-step channel cannot be chosen: email needs a verified e-mail sign-in method, wallet a linked wallet, telegram a linked Telegram account and the bot configured on this deployment. details.reason: delivery_failed: Telegram did not take the code (retry shortly).No — link the method first.
1023identity_in_use_account_not_empty409The sign-in method being linked belongs to another account that holds something: details.reason is balance, reserved, orders, withdrawals, api_keys, webhooks, node_keys, members, subscriptions or oauth_grants. A method of an EMPTY account is moved instead and that account is closed.No — write to support.
1024oauth_token_invalid401The OAuth access token (Authorization: Bearer oat_…) is unknown, expired or revoked; its connected agent was revoked or expired; it was issued for another resource; or the person who connected the agent is no longer a member. Sent with WWW-Authenticate: Bearer error="invalid_token".No — refresh the token, or connect the agent again.
1025telegram_bot_not_started409Our bot could not write to the person in Telegram (a step-up code, or the notice that Telegram confirmation is on): Start never pressed in the bot, or the bot blocked. details.bot_username names the bot; nothing changed.Yes — open the bot in Telegram, press Start, then repeat.
1027last_owner409The signed-in person tried to leave an account they are the last owner of (dashboard only). Nothing changed.No — appoint another owner first, then leave.
1028mail_unavailable503An e-mail code was asked for (POST /v1/session/email/start, POST /v1/session/identities/email/start) but this deployment cannot deliver mail right now: no mail provider is configured, or the provider refused the message. No code was issued.Yes, later — or sign in another way.
1029captcha_failed403An e-mail sign-in code was asked for (POST /v1/session/email/start) without a passed bot check: captcha_token is missing, used, expired or from another site. Only when GET /v1/session/methods names email_captcha. No code was issued.Yes, after passing the check again.
1030admin_confirmation_required428Admin panel only: this action needs a signature by the admin’s confirmation key. details.confirm_id and details.message carry the challenge and the exact text to sign (docs/product/admin-auth.md §6). Nothing was changed.Yes — sign details.message and repeat the same request with X-Admin-Confirm-Id and X-Admin-Confirm-Signature.
1031admin_confirmation_invalid403Admin panel only: the confirmation is unknown, already used, expired, issued for another action, or not signed by the confirmation key. Nothing was changed.Yes, with a new confirmation.
1032admin_session_invalid401Admin panel only: the admin session is unknown, ended, frozen, or the request’s browser-key signature, time or nonce did not check out.Sign in to the admin panel again.
1100rate_limited429Per-key or per-IP request budget exceeded. Retry-After says how long; details.scope is key or ip, or step_up when an unused confirmation code went to the same place under 15 s ago (details.retry_after; a used code never holds the next one back).Yes — honour Retry-After, then exponential backoff with jitter. Never a tight loop.
1101concurrency_limited429Too many of this account’s orders or batches in flight at once.Yes, after the in-flight ones settle. Lower your parallelism rather than retrying harder.
1102quota_exceeded429A daily or monthly cap on the account was reached. details.resets_at.Yes, after resets_at. Retrying before that cannot help.
2000malformed_json400Body is not valid JSON, or the content type is not application/json.No.
2001validation_failed400A field is missing, of the wrong type, or out of range. field names it; details.constraint describes the rule. Also returned when scopes is omitted from an API key creation — the API does not invent a default permission set.No.
2002empty_patch422A PATCH with no changeable field in the body.No.
2003tier_unavailable422Tier syntactically valid but not currently sellable for this resource. details.available_tiers lists what is. Also any energy term not on sale (currently everything except 1h) on POST /v1/orders, batches, quotes and estimates; GET /v1/prices shows such a row with available: false.No.
2004quote_mismatch422quote_id sent alongside explicit order fields that contradict the quote.No.
2005idempotency_key_required400A batch created with neither client_batch_id nor an Idempotency-Key header.No.
2006duplicate_receiver400The same address appears twice in one batch. Merge the amounts instead.No.
2007invalid_address400Not a valid Base58Check TRON address (bad checksum, wrong length, hex form instead of Base58).No.
2008amount_out_of_range400Below the tier’s minimum or above its maximum. details.min_amount / details.max_amount.No.
2009batch_too_large400More than 100 receivers, or the total across receivers exceeds the per-batch ceiling.No.
2010invalid_webhook_url400Not HTTPS, resolves to a private/loopback/link-local address, carries credentials, or exceeds 2048 characters.No.
2011unsupported_contract422The contract in a transfer estimate is not a TRC-20 token we can simulate.No.
3001order_not_found404No such order, or it belongs to another account. The two are deliberately not distinguished.No.
3002order_not_cancellable409A batch cancel (POST /v1/batches/{id}/cancel) arrived after that receiver had been picked up. There is no single-order cancel in v1 — POST /v1/orders charges synchronously, so an order never waits unpaid in a queue and this code cannot arise outside a batch.No — inspect the order; it is probably already delivered.
3003receiver_is_ours422The receiver is one of the platform’s own addresses.No.
3004receiver_not_activated422Receiver not activated and activate: false was sent. Nothing was charged.Yes, with activate: true, or after activating the address yourself.
3005quote_expired409The quote’s expires_at has passed.Yes — take a fresh quote first.
3006price_above_limit409Live total exceeds max_price_sun. details.quoted_total_sun is what it would have cost. Nothing was charged.Yes, later — the price moves with the pricing period. Or raise the cap.
3007nothing_to_reclaim409The order never resulted in an active delegation, or it is already expired and returned.No.
3008reclaim_unavailable409This order cannot be returned early.No.
3009order_in_terminal_state409A state change was requested on an order that is already finished.No.
3010idempotency_conflict409The same client_order_id / client_batch_id / Idempotency-Key reused with a different body. details.original_id points at the first request’s object.No — a caller-side bug. Either retry verbatim or pick a new key.
3011subscription_exists409This address already has a subscription for this resource. details.subscription_id.No — patch the existing one.
3012subscription_not_active409An operation needing a live subscription hit a cancelled one.No.
3013webhook_limit_reached409Two endpoints already registered.No — delete or patch one.
3014webhook_role_taken409The requested role is occupied.No — PATCH the other endpoint to swap roles.
3015request_in_progress409An identical request with this idempotency key is still executing. Retry-After suggests when to look again.Do not retry the create. Wait, then read the object by its client id. A retry risks nothing but wastes a slot.
3016account_unfunded409Unused since 2026-09-26 — no route returns it. It was POST /v1/api-keys on an account with no confirmed deposit; an unfunded account may now create keys and is refused at POST /v1/orders with 4001 instead. Kept so the number is never reused.—
3017api_key_limit_reached409The account already holds the maximum number of active API keys. A product limit, not an access right. details.limit and details.used.No — revoke a key you no longer use; the slot is free immediately.
3018deposit_rotation_limited429Operator surface only: POST /v1/admin/accounts/{id}/deposit-address/rotate inside the rotation limits (default 1 per 7 days, 3 per 90 days). details.retry_after (seconds), details.next_allowed_at; Retry-After header.Yes — after retry_after.
3019address_book_full409POST /v1/account/addresses with a new address on an account whose address book already holds 100 entries. A product limit, not an access right. details.limit and details.used. Re-saving an address already in the book only relabels it and never hits this.No — delete an entry you no longer use; the slot is free immediately.
3020subscription_rule_invalid422POST / PATCH /v1/subscriptions with a reserve, low and high that break the rule: 131,000 ≤ reserve ≤ 5,240,000, each a multiple of 1,000, low ≥ 65,000, low < high ≤ reserve, high − low ≥ 65,000 (Basic’s low = high = reserve = 131,000 is the one exception). details.violations names each broken rule.No — fix the numbers or pick a preset.
3021subscriptions_unavailable409Subscriptions are not available yet: POST /v1/subscriptions, and a PATCH that changes the rule, preset or refill parameters. Reading, pausing, resuming and cancelling existing subscriptions keep working. GET /v1/subscriptions/plans → available says which state is in force.Yes, later — once available is true.
3022withdrawals_unavailable409Withdrawals are not available.No.
3023withdrawal_in_progress409A withdrawal is already on its way; one at a time.After it completes.
3024withdrawal_destination_not_allowed422A withdrawal goes only back to a wallet that topped the account up, and at most what it paid in. details.available_sun is what that wallet can take.No.
3025node_key_daily_limit_reached409The node key has spent its daily_limit_sun for this UTC day; the proxy buys no more energy with it and refuses the broadcast. details: daily_limit_sun, spent_today_sun, price_sun.After 00:00 UTC, or with a higher limit on a new key.
3026api_key_spend_limit_reached409The API key has spent its daily (UTC day) or monthly (UTC month) limit on orders. details: period (day/month), limit_sun, spent_sun, price_sun.After the period turns, or after the limit is raised (PATCH /v1/api-keys/{id}).
3027promo_not_found404POST /v1/account/promo with a code that does not exist. Codes are upper-case letters, digits and -.No — check the code.
3028promo_unavailable409The code exists but cannot be used now. details.reason: inactive, not_started (with details.starts_at), ended, used_up.not_started: yes, from starts_at; otherwise no.
3029oauth_request_not_found404No live agent authorization request with this id: unknown, already approved or denied, or older than ten minutes.No — start the connection from the agent again.
3030oauth_grant_not_found404No live connected agent with this id on this account: unknown, revoked or expired.No.
3031spend_limit_reached403The connected agent has spent its daily (UTC day) or monthly (UTC month) limit. details: period (day or month), limit_sun, spent_sun, price_sun, resets_at. Not an OAuth error: connecting again does not raise it.No — after resets_at, or after the person raises the limit in the dashboard.
3032agent_key_limit_exceeded403An AI agent tried to create or edit an API key with a spend limit above its own, or without a limit while it has one. Also a key an agent created (or a key that key created): it is held to the same agent’s limits, and once that agent’s access is revoked or expired it cannot create or widen spending keys at all. details: grant_id, grant_daily_limit_sun, grant_monthly_limit_sun; or grant_id, grant_revoked: true.No — omit the limits to get the agent’s own, or ask the account owner to set other limits in the dashboard.
3033refills_unavailable409POST /v1/refills while no refill venue is enabled on this deployment.No — refills are not available yet.
3034refill_not_found404No such refill, or it belongs to another account; the two are not distinguished.No.
3035no_base_resource422POST /v1/refills for a receiver with no energy (or bandwidth) limit of its own or delegated to it: a refill restores used resource only.No — the receiver needs a stake or a delegation first.
3036nothing_to_refill422POST /v1/refills for a receiver that has used nothing now, or less than the smallest refill. (Asking for more than it has used is 2008 amount_out_of_range with details.restorable_max.) details.restorable_max (0 = nothing used), details.used, details.min_amount.Yes — once the receiver has spent at least min_amount.
3037promo_not_redeemed404GET /v1/promo/redemptions/{address} for an address that has not redeemed the promo token.No.
3038promo_not_eligible403The promo token redeem for an address we never dropped the token on (a token received from another holder does not count).No.
3039promo_already_redeemed409The address already claimed its grant, by signature or by forwarding the token. details.method, details.redeemed_at.No — one grant per address.
3040promo_redeem_unavailable409The promo is not open now: details.state is not_started, ended, cap_reached_today (with details.resets_at) or off (no promo on this network). Nothing is recorded.Yes — after resets_at, or once the promo is open.
4001insufficient_funds402Balance below the order total plus activation. details.required_sun, details.available_sun.Yes — deposit, then retry with the same client_order_id. That is exactly what the idempotency key is for.
4002balance_reserved402Nominal balance sufficient but too much is held against in-flight orders.Yes, once the in-flight orders settle.
4003currency_not_supported422The brand does not accept this currency for this operation.No.
4004ledger_conflict409Two concurrent charges raced on the same balance and one lost. Nothing was charged.Yes, immediately, same idempotency key. Serialise charges per account if you see this often.
5001insufficient_supply503Not enough energy is available for this amount right now. Nothing was charged.Yes, with backoff — supply returns as rentals expire. For a short tier, falling back to a longer tier often succeeds immediately.
5002delegation_failed503The delegation transaction was built but the chain rejected it or it never confirmed. Any charge is reversed; the order ends failed with refunded_amount_sun set.Yes — a fresh client_order_id, since the old order is terminal.
5003chain_unavailable503Our TRON node is not answering, so we cannot verify or deliver.Yes, with backoff.
5004provider_unavailable503Supply did not answer in time. Nothing was charged.Yes, with backoff.
5005receiver_capacity_exceeded422The receiver cannot accept this much more delegated resource (TRON limits delegations per address). details.max_additional.No, not as sent — reduce the amount or wait for existing delegations to expire.
5006supply_paused503Sales administratively paused for this resource or tier. details.resource, details.tier.Yes, later, but not soon — GET /v1/prices will not list a paused tier.
5007capacity_unavailable503Not enough capacity under your contract’s supply policy. The charge is credited back and the order ends failed. details.supply_policy, details.contract_id.Yes, with backoff — own capacity returns as rentals expire.
9000internal_error500An unhandled failure. The order’s state is unknown from the response alone.Yes — with the same client_order_id, the only way to learn whether the first attempt took effect. Never retry a create without one.
9001timeout504The operation exceeded the gateway’s window; outcome unknown.Yes, same client_order_id.
9002not_implemented501The endpoint is described in the contract but not served yet.No.

Validation codes (2000–2099) are all retryable: false and carry field where a single field is at fault; fix the request, retrying it unchanged fails identically.

The supply guarantee: a 503 from order creation never costs you money: either nothing was charged (5001, 5004), or the order ends failed and the charge is credited back (5007). Retrying with the same client_order_id is safe. Where a charge happened and delivery then failed (5002), the order exists, is terminal, and the money is credited back: read it and start a new order rather than retrying the old id.

Retry policy

Retry on 429, 5xx, and on 4001/4002/4004 after fixing the cause. Do not retry any 400, 401, 403, 404, or a 409 other than 4004 — those need a changed request. Always send client_order_id on order creation so every retry is free of double-purchase risk. Exponential backoff starting at 250 ms with full jitter, delay capped at 30 s, give up after roughly 60 s of wall-clock time rather than a fixed attempt count — then read the order by its client id to find out what happened. Honour Retry-After whenever present; it overrides your own schedule.

HTTP status map

200 success, also an idempotent replay of a create and a reclaim that had already happened · 201 a new object was created · 202 accepted for asynchronous processing (batches, and a reclaim whose hash had not landed yet — nothing delivered) · 204 success with no body (deletes, cancels) · 400 malformed or invalid request · 401 credentials missing, wrong, stale or from a disallowed IP · 402 not enough money · 403 authenticated but not permitted · 404 no such object for this account · 409 conflicts with current state, including idempotency conflicts · 422 well-formed but semantically impossible · 429 rate or quota limit · 500 unhandled internal failure · 501 contract-defined but not deployed · 503 temporarily unable to serve, fail-secure on creates · 504 upstream timeout, outcome unknown.

Rate limits

Per API key, and additionally per source IP. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds). Exceeding a limit returns HTTP 429 with 1100 rate_limited and a Retry-After header.

Default budgets (per key, per second). The dashboard shows the budgets in force for your key; higher limits on request:

GroupLimit
Order creation (POST /v1/orders, POST /v1/batches)30 rps
Reads (GET on orders, quotes, prices, resources)50 rps
Account, API keys, webhooks management5 rps

Next steps

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