{
  "openapi": "3.1.0",
  "info": {
    "title": "TronTransfer API",
    "version": "1.2.1",
    "summary": "Energy-sponsored, non-custodial USDT (TRC-20) transfers on TRON.",
    "description": "Send USDT on TRON mainnet for a flat fee, with no staking or energy rental. The sender (who needs about the fee amount in TRX) signs two transactions (a small flat TRX fee to collectAddress, and their normal USDT transfer() call); TronTransfer confirms the fee, delegates the energy, then broadcasts the USDT transfer. No API key. TronTransfer never receives private keys. Current fee to a recipient that already holds USDT: ~5.48 TRX (~$1.81), as of 2026-10-28. Option for senders short of TRX: pay the network fee in USDT with the /zt/* endpoints (zero-TRX). The sender signs two unbroadcast USDT transfer() txs (the quoted USDT fee to feeAddress, then the payment); TronTransfer supplies the energy and bandwidth, so the sender's TRX balance can be 0. The sender's account must already be activated on TRON and hold at least amount + fee in USDT. The USDT fee is higher than the TRX fee and depends on live prices; always use GET /zt/quote. Option for developers and agents that send often: a prepaid API account. POST /account/keys returns a key (tt_live_…, shown once) and a deposit code; deposit TRX to depositAddress with the code as the transaction memo (a wallet a memo-matched deposit came from is listed on the account and, once confirmed with POST /account/deposit-addresses/confirm, is credited without a memo; never confirm an exchange address); then POST /v1/transfers with Authorization: Bearer <key> and only usdtTx (no fee tx): the fee is charged from the balance, one signature per transfer. Same per-transfer fee as the on-chain flow (higher for recipients that do not yet hold USDT); 15% less after 100 transfers in 30 days, 30% less after 500; a transfer is accepted only when the balance covers the current cold-recipient fee. The charge is returned in full when the transfer never goes out and nothing was bought for it; once energy or bandwidth was bought, or it is broadcast and fails on-chain, only the network cost paid is kept (settled from the chain once the transaction has expired; usdtTx may expire at most 15 minutes from now). Balances never expire; withdrawals on request. Dashboard: https://trontransfer.com/account. Full agent guide: https://trontransfer.com/llms-full.txt",
    "contact": { "name": "TronTransfer", "url": "https://doc.trontransfer.com/", "email": "trontransferusdt@gmail.com" }
  },
  "externalDocs": { "description": "Human-readable API docs with examples", "url": "https://doc.trontransfer.com/" },
  "servers": [{ "url": "https://trontransfer.com", "description": "TRON mainnet" }],
  "paths": {
    "/config": {
      "get": {
        "operationId": "getConfig",
        "summary": "Fee destination, USDT contract and default pricing",
        "description": "Call once (cache briefly). Returns where the TRX fee must be paid and the default (warm) pricing.",
        "responses": {
          "200": {
            "description": "Config",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "collectAddress": { "type": "string", "description": "TRON address the TRX fee tx must pay." },
                "usdtContract": { "type": "string", "description": "USDT TRC-20 contract (TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t)." },
                "trxUsd": { "type": ["number", "null"] },
                "defaultRegion": { "type": "string" },
                "regions": { "type": "array", "items": { "type": "string" } },
                "pricing": { "$ref": "#/components/schemas/Pricing" },
                "pricingByRegion": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/Pricing" } }
              }
            } } }
          }
        }
      }
    },
    "/recipient": {
      "get": {
        "operationId": "getRecipient",
        "summary": "Exact fee for a recipient, plus free safety checks",
        "description": "Use pricing.feeSun as the exact fee. The fee depends on whether the recipient already holds USDT (warm, 65k energy) or not (cold, 131k energy). Do not send if blacklisted is true.",
        "parameters": [
          { "name": "addr", "in": "query", "required": true, "description": "Recipient TRON address (base58, starts with T).", "schema": { "type": "string" } },
          { "name": "from", "in": "query", "required": false, "description": "Optional sender address; enables 'you have paid this address before' signals.", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Recipient info",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "valid": { "type": "boolean" },
                "address": { "type": "string" },
                "activated": { "type": "boolean" },
                "isContract": { "type": "boolean" },
                "isUsdtContract": { "type": "boolean" },
                "blacklisted": { "type": ["boolean", "null"], "description": "On Tether's USDT blacklist. Do not send if true." },
                "hasReceivedUsdt": { "type": "boolean" },
                "hasSentUsdt": { "type": "boolean" },
                "usdtBalance": { "type": "number" },
                "ageDays": { "type": ["number", "null"] },
                "pricing": { "$ref": "#/components/schemas/Pricing" },
                "pricingByRegion": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/Pricing" } }
              }
            } } }
          },
          "400": { "description": "addr missing" }
        }
      }
    },
    "/v1/transfers": {
      "post": {
        "operationId": "createTransfer",
        "summary": "Submit a sponsored USDT transfer (two signed transactions, or one with an API key)",
        "description": "Without an API key: the fully-signed fee tx (TRX transfer of pricing.feeSun to collectAddress) and the fully-signed USDT transfer() tx, both from the same wallet, both with ~300 s expiration. With a prepaid API key (Authorization: Bearer tt_live_…): only usdtTx; the fee is charged from the account's TRX balance before any energy is rented (a feeTx in the body is ignored) and the answer adds prepaid { chargedTrx, balanceTrx, tier }. Do not broadcast the transactions yourself. Judge success by the 'ok' field, never the HTTP status: business failures return HTTP 200 with ok=false. If the response is not JSON (gateway timeout) the transfer may still complete: check GET /receipt with the USDT tx's txID before doing anything else; never rebuild and resend blindly. Prepaid usdtTx may expire at most 15 minutes from now (400 TX_EXPIRATION_TOO_LONG, detail.maxExpirationMs = 900000); sign with ~300 s. Prepaid charge on failures: NODE_UNAVAILABLE = nothing charged, retry; DUPLICATE = this signed tx was already charged, never twice (usdtTxid in the answer; sign a new tx to send again); ENERGY_UNAVAILABLE = refunded at once when nothing was bought for the transfer (refunded true, prepaid.balanceTrx), otherwise settled from the chain once the tx has expired; USDT_BROADCAST_FAILED = the node refused the broadcast, settled from the chain once the tx has expired (full refund when nothing was bought, network cost kept otherwise; usdtTxid in the answer); INTERNAL_ERROR = refunded at once when nothing was bought and the USDT was never handed to a node, otherwise settled from the chain; USDT_NOT_CONFIRMED (status pending) = the USDT was broadcast: if it failed on-chain only the network cost paid is kept, if still pending poll GET /receipt. Settlement: in a block with SUCCESS the charge stands; in a block but failed, the actual network cost is kept and the rest refunded; never landed, full refund when nothing was bought, cost kept otherwise. A reconciler runs at start-up and every 5 minutes and never refunds on a throttled or lagging node's say-so. Every refund is at most once per transfer (a refund row in the ledger).",
        "security": [{}, { "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "required": ["usdtTx"],
            "properties": {
              "feeTx": { "allOf": [{ "$ref": "#/components/schemas/SignedTransaction" }], "description": "Required without an API key: a signed TRX transfer of pricing.feeSun to collectAddress. Optional (ignored) when authenticated with a prepaid API key." },
              "usdtTx": { "$ref": "#/components/schemas/SignedTransaction" },
              "region": { "type": "string", "enum": ["sea", "global"], "default": "sea" }
            }
          } } }
        },
        "responses": {
          "200": {
            "description": "Result. ok=true with usdtTxid on success; ok=false with code/message on a mid-flight failure (with an API key also NODE_UNAVAILABLE, nothing charged, and DUPLICATE, already charged once).",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferResult" } } }
          },
          "400": {
            "description": "Validation failure (INVALID_JSON, TX_MISSING, FEE_NOT_TRX, FEE_WRONG_DESTINATION, FEE_TOO_LOW, FEE_TOO_HIGH, USDT_NOT_A_TRANSFER, WRONG_USDT_CONTRACT, SENDER_MISMATCH, TX_EXPIRED; with an API key also TX_TAMPERED, BAD_SIGNATURE, PERMISSION and TX_EXPIRATION_TOO_LONG, whose detail.maxExpirationMs is 900000). Nothing was broadcast or charged.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferResult" } } }
          },
          "401": {
            "description": "INVALID_API_KEY: the Authorization: Bearer key is not valid (wrong, or rotated). Nothing charged.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } }
          },
          "402": {
            "description": "INSUFFICIENT_BALANCE: the prepaid balance is below the current cold-recipient fee. Nothing charged. detail has balanceTrx, requiredTrx and chargeTrx; depositAddress and depositCode say where to top up.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InsufficientBalance" } } }
          },
          "429": {
            "description": "RATE_LIMITED (API key only): 30 transfers per minute per account, or 60 bad-key attempts per 10 minutes per IP. Nothing charged; wait.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } }
          },
          "503": {
            "description": "PREPAID_UNAVAILABLE: prepaid accounts are switched off right now. Nothing charged; the two-transaction flow without a key still works.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } }
          }
        }
      }
    },
    "/receipt": {
      "get": {
        "operationId": "getReceipt",
        "summary": "Solidified receipt for a USDT transfer",
        "description": "energyFee 0 proves the transfer used sponsored energy. Returns { pending: true } until the transaction solidifies (~60 s).",
        "parameters": [{ "name": "txid", "in": "query", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": {
            "description": "Receipt or pending",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "result": { "type": "string", "examples": ["SUCCESS"] },
                "energyUsed": { "type": "integer" },
                "energyFee": { "type": "number", "description": "TRX burned for energy; 0 when sponsored." },
                "netFee": { "type": "number" },
                "pending": { "type": "boolean" }
              }
            } } }
          }
        }
      }
    },
    "/zt/status": {
      "get": {
        "operationId": "getZeroTrxStatus",
        "summary": "Whether paying the fee in USDT (zero-TRX) is available",
        "description": "Offer the USDT-fee option only when enabled is true. Pass sender to ask for a specific wallet.",
        "parameters": [
          { "name": "sender", "in": "query", "required": false, "description": "Sender TRON address (base58).", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ZtStatus" } } }
          }
        }
      }
    },
    "/zt/quote": {
      "get": {
        "operationId": "getZeroTrxQuote",
        "summary": "USDT fee quote for a zero-TRX send",
        "description": "Returns the fee in USDT and where to pay it. Build the fee transfer for exactly feeUnits to feeAddress. Re-quote if more than ~2 minutes (validS) pass; POST /zt/process re-prices and accepts 95%-300% of a fresh quote. On failure: ok=false with code and message.",
        "parameters": [
          { "name": "sender", "in": "query", "required": true, "description": "Sender TRON address (base58). Must be activated on TRON.", "schema": { "type": "string" } },
          { "name": "recipient", "in": "query", "required": true, "description": "Recipient TRON address (base58).", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Quote, or ok=false with a code",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ZtQuote" } } }
          }
        }
      }
    },
    "/zt/process": {
      "post": {
        "operationId": "processZeroTrxTransfer",
        "summary": "Submit a zero-TRX send (two signed, unbroadcast USDT transfer() txs)",
        "description": "feeTx = USDT transfer(feeAddress, feeUnits) from the quote; payTx = USDT transfer(recipient, amount). Both on the USDT contract TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t, signed by the same sender, call_value 0, no memo, feeLimit 30 TRX, expiration 150 s to 15 min away when received (build with ~5-8 min). Never broadcast them yourself. Answers when both transfers are in a block (typically 15-45 s) or after at most 40 s with status=processing: then poll GET /zt/job. Sending the same pair again is safe (it never spends twice). Read the answer: completed = sent; pay_failed = fee charged, payment not sent; processing = keep polling; a code in the nothing-charged list (DISABLED MISCONFIGURED PAUSED RATE_LIMITED BUSY REFUSED BAD_ADDRESS PRICE_UNAVAILABLE INVALID_JSON TX_MISSING TX_TAMPERED NOT_A_TRANSFER WRONG_TOKEN VALUE_ATTACHED MEMO_NOT_ALLOWED FEE_LIMIT_TOO_LOW ZERO_AMOUNT BAD_SIGNATURE PERMISSION TX_EXPIRING SENDER_MISMATCH FEE_WRONG_DESTINATION PAY_TO_FEE_ADDRESS SAME_TX FEE_TOO_LOW FEE_TOO_HIGH ACCOUNT_INACTIVE INSUFFICIENT_USDT WOULD_FAIL BANDWIDTH_SHORT ENERGY_UNAVAILABLE ENERGY_TIMEOUT FEE_NOT_PAID) = nothing was charged; any other code (e.g. UNCONFIRMED, INTERNAL_ERROR) = uncertain: check both transfers on-chain before retrying.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "required": ["feeTx", "payTx"],
            "properties": {
              "feeTx": { "$ref": "#/components/schemas/SignedTransaction" },
              "payTx": { "$ref": "#/components/schemas/SignedTransaction" }
            }
          } } }
        },
        "responses": {
          "200": {
            "description": "Job answer (always HTTP 200; check ok and status).",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ZtResult" } } }
          }
        }
      }
    },
    "/zt/job": {
      "get": {
        "operationId": "getZeroTrxJob",
        "summary": "Current answer for a zero-TRX send",
        "description": "Same shape as POST /zt/process. Poll every 3-5 s while status is processing; every job ends within ~25 minutes of its transactions being signed. ok=false with code NOT_FOUND if the relay never accepted that pair.",
        "parameters": [
          { "name": "fee", "in": "query", "required": true, "description": "The fee transaction's txID (64 hex characters).", "schema": { "type": "string", "pattern": "^[0-9a-fA-F]{64}$" } }
        ],
        "responses": {
          "200": {
            "description": "Job answer",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ZtResult" } } }
          }
        }
      }
    },
    "/stats": {
      "get": {
        "operationId": "getStats",
        "summary": "Public track record",
        "responses": {
          "200": {
            "description": "Completed transfers, USDT moved, recent (anonymised) sends",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "transfers": { "type": "integer" },
                "usdtMoved": { "type": "number" },
                "firstAt": { "type": ["string", "null"], "format": "date-time" },
                "recent": { "type": "array", "items": { "type": "object", "properties": { "usdt": { "type": "number" }, "created_at": { "type": "string", "format": "date-time" } } } }
              }
            } } }
          }
        }
      }
    },
    "/account/keys": {
      "post": {
        "operationId": "createApiKey",
        "summary": "Create a prepaid API account and its key",
        "description": "No auth. Returns the key once (tt_live_… ; only its hash is stored, so save it server-side and never put it in a URL or a page) together with the account (its depositCode, TT- plus 6 characters) and depositAddress, where TRX deposits go. 5 new keys per hour per IP. Dashboard for humans: https://trontransfer.com/account",
        "requestBody": {
          "required": false,
          "content": { "application/json": { "schema": {
            "type": "object",
            "properties": { "label": { "type": "string", "maxLength": 60, "description": "A name for the account (shown in the dashboard)." } }
          } } }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": { "application/json": { "schema": {
              "type": "object",
              "required": ["ok", "key", "account", "depositAddress"],
              "properties": {
                "ok": { "type": "boolean" },
                "key": { "type": "string", "description": "The API key. Shown only here." },
                "account": { "$ref": "#/components/schemas/Account" },
                "depositAddress": { "type": "string", "description": "TRON address for TRX deposits (the same as collectAddress in /config)." }
              }
            } } }
          },
          "429": { "description": "RATE_LIMITED", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "503": { "description": "PREPAID_UNAVAILABLE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } }
        }
      }
    },
    "/account/pricing": {
      "get": {
        "operationId": "getAccountPricing",
        "summary": "Public prepaid pricing and the deposit address",
        "description": "No auth. The live on-chain fee (what a prepaid transfer is charged before any volume discount), the pricing rules, and depositAddress. charge is null here; GET /account/me returns the account's own charge and minimum balance.",
        "responses": {
          "200": {
            "description": "Pricing",
            "content": { "application/json": { "schema": {
              "allOf": [
                { "type": "object", "properties": { "ok": { "type": "boolean" }, "depositAddress": { "type": "string" } } },
                { "$ref": "#/components/schemas/AccountPrices" }
              ]
            } } }
          },
          "503": { "description": "PREPAID_UNAVAILABLE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } }
        }
      }
    },
    "/account/me": {
      "get": {
        "operationId": "getAccount",
        "summary": "The account: balance, tier, ledger, deposits, transfers and current prices",
        "description": "Bearer. prices.charge.minBalanceTrx is the balance needed before a transfer is accepted (the live cold-recipient fee); estimatedTransfers is how many warm transfers the balance covers now. ledger lists the last 100 movements (deposit, charge, refund, adjust), newest first; a charge or refund's ref is prepaid:<usdt txID>.",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Account view",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "ok": { "type": "boolean" },
                "account": { "$ref": "#/components/schemas/Account" },
                "depositAddress": { "type": "string" },
                "depositAddresses": { "type": "array", "description": "Wallets a memo-matched deposit came from (up to 10). Only a confirmed one (POST /account/deposit-addresses/confirm) credits memo-less deposits.", "items": { "type": "object", "properties": { "address": { "type": "string" }, "added_at": { "type": "string", "format": "date-time" }, "confirmed": { "type": "integer", "enum": [0, 1] } } } },
                "tier": { "$ref": "#/components/schemas/PrepaidTier" },
                "ledger": { "type": "array", "items": { "$ref": "#/components/schemas/LedgerEntry" } },
                "deposits": { "type": "array", "items": { "$ref": "#/components/schemas/Deposit" } },
                "transfers": { "type": "array", "items": { "$ref": "#/components/schemas/AccountTransfer" } },
                "prices": { "$ref": "#/components/schemas/AccountPrices" },
                "estimatedTransfers": { "type": ["integer", "null"], "description": "balance ÷ the current warm charge." }
              }
            } } }
          },
          "401": { "description": "INVALID_API_KEY", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "429": { "description": "RATE_LIMITED", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "503": { "description": "PREPAID_UNAVAILABLE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } }
        }
      }
    },
    "/account/deposit-addresses/confirm": {
      "post": {
        "operationId": "confirmDepositAddress",
        "summary": "Confirm a listed wallet as your own, so its plain TRX transfers to depositAddress are credited without a memo",
        "description": "Bearer. A wallet a memo-matched deposit came from is listed on the account (GET /account/me depositAddresses, up to 10). Until confirmed, a memo-less deposit from it is parked as unmatched. Never confirm an exchange address: an exchange withdrawal comes from a hot wallet shared by many customers. A wallet seen with two different accounts' memo codes is treated as shared, unbound from both and never credited without a memo again.",
        "security": [{ "bearerAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DepositAddressBody" } } } },
        "responses": {
          "200": { "description": "The account's listed wallets", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DepositAddresses" } } } },
          "401": { "description": "INVALID_API_KEY", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "503": { "description": "PREPAID_UNAVAILABLE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } }
        }
      }
    },
    "/account/deposit-addresses/remove": {
      "post": {
        "operationId": "removeDepositAddress",
        "summary": "Drop a wallet from the account's list",
        "security": [{ "bearerAuth": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DepositAddressBody" } } } },
        "responses": {
          "200": { "description": "The account's listed wallets", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DepositAddresses" } } } },
          "401": { "description": "INVALID_API_KEY", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "503": { "description": "PREPAID_UNAVAILABLE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } }
        }
      }
    },
    "/account/check-deposits": {
      "post": {
        "operationId": "checkDeposits",
        "summary": "Look for new confirmed TRX deposits now",
        "description": "Bearer. Deposits are credited automatically about once a minute once their transaction is confirmed; this forces a check. 3 per minute per account. Only TRX transfers to depositAddress with the account's deposit code in the memo, or from a confirmed wallet, are credited; anything else is parked as unmatched for support.",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "What was credited by this check, and the balance",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "ok": { "type": "boolean" },
                "credited": { "type": "array", "items": { "type": "object", "properties": { "txid": { "type": "string" }, "amountTrx": { "type": "number" }, "matchedBy": { "type": "string", "enum": ["memo", "address"] } } } },
                "balanceTrx": { "type": "number" }
              }
            } } }
          },
          "401": { "description": "INVALID_API_KEY", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "429": { "description": "RATE_LIMITED (checked a moment ago)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "503": { "description": "PREPAID_UNAVAILABLE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } }
        }
      }
    },
    "/account/rotate": {
      "post": {
        "operationId": "rotateApiKey",
        "summary": "Replace the API key",
        "description": "Bearer (the current key). Returns a new key; the old one stops working at once. A lost key cannot be rotated: contact support.",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "The new key (shown once)", "content": { "application/json": { "schema": { "type": "object", "required": ["ok", "key"], "properties": { "ok": { "type": "boolean" }, "key": { "type": "string" } } } } } },
          "401": { "description": "INVALID_API_KEY", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } },
          "503": { "description": "PREPAID_UNAVAILABLE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountError" } } } }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "tt_live_… prepaid API key",
        "description": "Optional. A prepaid API account key from POST /account/keys, sent as Authorization: Bearer tt_live_… . On POST /v1/transfers it replaces the fee transaction: the fee is charged from the account's TRX balance. Required on GET /account/me, POST /account/deposit-addresses/confirm, POST /account/deposit-addresses/remove, POST /account/check-deposits and POST /account/rotate."
      }
    },
    "schemas": {
      "Pricing": {
        "type": "object",
        "properties": {
          "region": { "type": "string" },
          "energy": { "type": "integer", "description": "65000 (recipient holds USDT) or 131000 (new USDT address)." },
          "cold": { "type": "boolean" },
          "feeSun": { "type": "integer", "description": "Exact fee in sun (1 TRX = 1,000,000 sun). Pay exactly this in the fee tx." },
          "feeTrx": { "type": "number" },
          "feeUsd": { "type": ["number", "null"] },
          "networkUsd": { "type": ["number", "null"], "description": "What burning TRX yourself would cost." },
          "savePct": { "type": "integer" },
          "profitable": { "type": "boolean", "description": "false = sponsorship paused right now (energy market too expensive); retry later or send normally." }
        }
      },
      "SignedTransaction": {
        "type": "object",
        "description": "A fully-signed TRON transaction object as produced by TronWeb (txID, raw_data, raw_data_hex, signature[]).",
        "required": ["txID", "raw_data", "signature"],
        "properties": {
          "txID": { "type": "string" },
          "raw_data": { "type": "object" },
          "raw_data_hex": { "type": "string" },
          "signature": { "type": "array", "items": { "type": "string" } }
        }
      },
      "TransferResult": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "status": { "type": "string", "examples": ["completed", "pending"] },
          "code": { "type": ["string", "null"], "examples": ["MARKET_UNPROFITABLE", "ENERGY_UNAVAILABLE", "FEE_TOO_LOW", "TX_EXPIRATION_TOO_LONG", "NODE_UNAVAILABLE", "DUPLICATE", "USDT_BROADCAST_FAILED"] },
          "message": { "type": "string" },
          "detail": { "type": "object" },
          "refunded": { "type": "boolean", "description": "With an API key on ENERGY_UNAVAILABLE: true = nothing was bought for the transfer and the charge was returned at once; false = energy was bought, the charge is settled from the chain once the tx has expired." },
          "usdtTxid": { "type": "string" },
          "feeTxid": { "type": "string" },
          "sender": { "type": "string" },
          "recipient": { "type": "string" },
          "amountUsdt": { "type": "number" },
          "feeTrx": { "type": "number", "description": "The TRX fee: the fee tx amount, or the prepaid charge." },
          "energyFeeTrx": { "type": ["number", "null"] },
          "prepaid": { "$ref": "#/components/schemas/PrepaidCharge" }
        }
      },
      "PrepaidTier": {
        "type": "object",
        "description": "Volume tier: the number of charged transfers in the trailing window sets the multiplier (100 or more in 30 days: 0.85; 500 or more: 0.70).",
        "properties": {
          "count": { "type": "integer", "description": "Transfers charged in the window." },
          "windowDays": { "type": "integer" },
          "minCount": { "type": "integer", "description": "The tier's threshold (0 = base price)." },
          "mult": { "type": "number" },
          "discountPct": { "type": "integer" }
        }
      },
      "PrepaidCharge": {
        "type": "object",
        "description": "Present on a /v1/transfers answer for an API-key transfer.",
        "properties": {
          "chargedTrx": { "type": "number", "description": "TRX taken from the balance for this transfer." },
          "balanceTrx": { "type": "number", "description": "The balance after the charge." },
          "tier": { "$ref": "#/components/schemas/PrepaidTier" }
        }
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "keyPrefix": { "type": "string", "description": "The first characters of the key (tt_live_ + 4), to recognise it." },
          "label": { "type": ["string", "null"] },
          "depositCode": { "type": "string", "description": "TT- plus 6 characters. Put it in the memo of a TRX deposit to depositAddress.", "examples": ["TT-7K4MQ2"] },
          "balanceSun": { "type": "integer" },
          "balanceTrx": { "type": "number" },
          "status": { "type": "string", "examples": ["active"] },
          "createdAt": { "type": "string", "format": "date-time" },
          "lastUsedAt": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "AccountPrices": {
        "type": "object",
        "properties": {
          "trxUsd": { "type": ["number", "null"] },
          "onchain": {
            "type": "object",
            "description": "The live on-chain fee (the base of the prepaid charge).",
            "properties": { "warmTrx": { "type": "number" }, "coldTrx": { "type": "number" }, "warmUsd": { "type": ["number", "null"] }, "coldUsd": { "type": ["number", "null"] } }
          },
          "charge": {
            "type": ["object", "null"],
            "description": "What this account is charged now (null on the public /account/pricing).",
            "properties": {
              "warmTrx": { "type": "number", "description": "Charge for a recipient that already holds USDT." },
              "coldTrx": { "type": "number", "description": "Charge for a recipient that never held USDT." },
              "warmUsd": { "type": ["number", "null"] },
              "coldUsd": { "type": ["number", "null"] },
              "minBalanceTrx": { "type": "number", "description": "A transfer is accepted only when the balance is at least this (the live cold fee)." },
              "tier": { "$ref": "#/components/schemas/PrepaidTier" }
            }
          },
          "rules": {
            "type": "object",
            "properties": {
              "priceMult": { "type": "number" },
              "tiers": { "type": "array", "items": { "type": "object", "properties": { "minCount": { "type": "integer" }, "mult": { "type": "number" } } } },
              "tierWindowDays": { "type": "integer" },
              "minBalanceMult": { "type": "number" },
              "failedOnchain": { "type": "string", "enum": ["cost", "full", "none"], "description": "What is kept when the USDT was broadcast and failed on-chain: cost = only the network cost paid." }
            }
          }
        }
      },
      "LedgerEntry": {
        "type": "object",
        "properties": {
          "kind": { "type": "string", "enum": ["deposit", "charge", "refund", "adjust"] },
          "amount_sun": { "type": "integer", "description": "Signed: negative for a charge." },
          "amountTrx": { "type": "number" },
          "balance_after_sun": { "type": "integer" },
          "balanceAfterTrx": { "type": "number" },
          "ref": { "type": ["string", "null"], "description": "The deposit's txid, or prepaid:<usdt txID> for a charge or refund." },
          "note": { "type": ["string", "null"] },
          "at": { "type": "string", "format": "date-time" }
        }
      },
      "Deposit": {
        "type": "object",
        "properties": {
          "txid": { "type": "string" },
          "from_address": { "type": ["string", "null"] },
          "amount_sun": { "type": "integer" },
          "amountTrx": { "type": "number" },
          "matched_by": { "type": ["string", "null"], "description": "memo or address" },
          "block_time": { "type": ["integer", "null"], "description": "Unix ms." },
          "credited_at": { "type": "string", "format": "date-time" }
        }
      },
      "AccountTransfer": {
        "type": "object",
        "properties": {
          "created_at": { "type": "string", "format": "date-time" },
          "recipient": { "type": "string" },
          "usdt_amount": { "type": "number" },
          "fee_sun": { "type": "integer" },
          "chargeTrx": { "type": "number" },
          "status": { "type": "string", "examples": ["completed", "usdt_failed", "energy_failed"] },
          "usdt_txid": { "type": ["string", "null"] },
          "fee_txid": { "type": "string", "description": "prepaid:<usdt txID> (the ledger reference)." }
        }
      },
      "DepositAddressBody": {
        "type": "object",
        "required": ["address"],
        "properties": { "address": { "type": "string", "description": "A TRON address (base58, starts with T)." } }
      },
      "DepositAddresses": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "depositAddresses": { "type": "array", "items": { "type": "object", "properties": { "address": { "type": "string" }, "added_at": { "type": "string", "format": "date-time" }, "confirmed": { "type": "integer", "enum": [0, 1] } } } }
        }
      },
      "AccountError": {
        "type": "object",
        "required": ["ok", "code", "message"],
        "properties": {
          "ok": { "type": "boolean" },
          "code": { "type": "string", "examples": ["INVALID_API_KEY", "RATE_LIMITED", "PREPAID_UNAVAILABLE"] },
          "message": { "type": "string" }
        }
      },
      "InsufficientBalance": {
        "type": "object",
        "description": "HTTP 402 on POST /v1/transfers with an API key. Nothing was charged.",
        "properties": {
          "ok": { "type": "boolean" },
          "code": { "type": "string", "examples": ["INSUFFICIENT_BALANCE"] },
          "message": { "type": "string" },
          "detail": {
            "type": "object",
            "properties": {
              "balanceTrx": { "type": "number" },
              "requiredTrx": { "type": "number", "description": "The balance needed to send (the live cold-recipient fee)." },
              "chargeTrx": { "type": "number", "description": "What this transfer would have been charged." }
            }
          },
          "depositAddress": { "type": "string", "description": "Where to send TRX." },
          "depositCode": { "type": "string", "description": "The memo to put on the deposit." }
        }
      },
      "ZtStatus": {
        "type": "object",
        "required": ["ok", "enabled"],
        "properties": {
          "ok": { "type": "boolean" },
          "enabled": { "type": "boolean", "description": "true = the USDT-fee option can be offered (for this sender, when sender was given)." },
          "paused": { "type": "boolean", "description": "true = temporarily paused; use the TRX-fee flow or retry later." }
        }
      },
      "ZtQuote": {
        "type": "object",
        "required": ["ok"],
        "properties": {
          "ok": { "type": "boolean" },
          "sender": { "type": "string" },
          "recipient": { "type": "string" },
          "feeAddress": { "type": "string", "description": "Where the USDT fee transfer must go (take it from the quote)." },
          "feeUsdt": { "type": "number", "description": "The fee in USDT, for display." },
          "feeUnits": { "type": "string", "description": "The fee in USDT base units (6 decimals). Put exactly this in the fee transfer." },
          "energy": { "type": "integer", "description": "Energy supplied for both transfers." },
          "validS": { "type": "integer", "description": "Seconds the quote stays valid (re-quote after that)." },
          "code": { "type": "string", "description": "On ok=false, e.g. DISABLED, BAD_ADDRESS, PRICE_UNAVAILABLE." },
          "message": { "type": "string" }
        }
      },
      "ZtResult": {
        "type": "object",
        "required": ["ok"],
        "properties": {
          "ok": { "type": "boolean", "description": "true only when status is completed." },
          "status": { "type": "string", "enum": ["completed", "pay_failed", "processing", "failed"], "description": "completed = sent; pay_failed = the fee was charged and the payment was not sent; processing = poll GET /zt/job; failed = see code. Absent when the request was refused before a job existed (then read code)." },
          "code": { "type": "string", "description": "PROCESSING while processing; on failure a code. Only codes in the nothing-charged list (see POST /zt/process) mean nothing was charged; any other code (e.g. UNCONFIRMED, INTERNAL_ERROR) means check both transfers before retrying." },
          "message": { "type": "string" },
          "sender": { "type": "string" },
          "recipient": { "type": "string" },
          "amount": { "type": "string", "description": "Payment amount in USDT base units (6 decimals)." },
          "feeUnits": { "type": "string", "description": "Fee in USDT base units (6 decimals)." },
          "feeTxid": { "type": "string" },
          "payTxid": { "type": "string" },
          "requiredUsdt": { "type": "number", "description": "With FEE_TOO_LOW / FEE_TOO_HIGH: the fee a fresh quote requires." }
        }
      }
    }
  }
}
