Why USDT transfers fail
A payout desk running USDT on TRON meets the same small set of troubles over and over. None of them is exotic, and most are quiet in a way that matters: the transfer looks fine, the money is gone anyway, and the reason is a property of an address that was knowable before anything was signed. Here is the taxonomy, and where each shows up in an API answer rather than in a reconciliation a week later.
No energy on the sender: the burn surprise
This is the failure that does not look like one. An account short of energy is not turned away; the network takes the shortfall out of its TRX at the protocol rate, 210 sun for each unit. The transfer confirms, the recipient gets the full amount, and 13.650000 TRX has left the account with nothing anywhere calling it an error. At one transfer a day that is noise; at several hundred it is one of the larger operational lines on TRON (the arithmetic).
The recipient has never held USDT
The same transfer, twice the appetite. A recipient with no USDT history holds no token account, and the arriving transfer has to open one first — the computation roughly doubles, from about 65,000 units of energy to about 131,000. Budgeted as an ordinary transfer and paid as a double one, the difference comes out of TRX, and in a payout run to new customers most of the batch can be in that state at once. Not randomness: a property of the recipient.
The recipient is frozen
USDT's issuer can freeze any address that holds the token, and a transfer involving a frozen address does not go through. The cost of the attempt stays spent all the same: energy, or burned TRX, buys the try and not the result. In a batch the loss compounds without a signal — nothing marks the frozen address out among hundreds, and a pipeline that retries its failures pays for the same refusal again and again. The guide to the blacklist covers how addresses get there.
The sending wallet was never activated
The one that looks like somebody else's bug and is not. An address never activated on the network does not exist as an account yet, and energy cannot be delegated to a place that does not exist. An order naming such a sender comes back 422 invalid_address with details.reason set to inactive_wallet, along with the index of the position in the batch and the address itself. Retrying will not help; activating the wallet will. That refusal deliberately does not consume your Idempotency-Key — the same key can be replayed once the wallet is alive. An address that is not a TRON address at all answers differently: 400 invalid_address, with no details.reason.
Which failure shows up in which field
Two calls carry all four, and neither reserves or charges anything. POST /v1/estimate scores the recipients: per item a kind, the energy_units behind it, and any warnings — blacklisted for the frozen address, which an order refuses outright; inactive_recipient for the one that has never held USDT, priced as double; contract_recipient for an address that turns out to be a contract, accepted but priced from a dry-run.
{"items":[{"to":"TN3W…","kind":"double","energy_units":131000,
"warnings":["inactive_recipient"], …}], …}
# response trimmed — the real one also carries prices and the zone
The sender is the one thing the estimate never looks at, and that is the second call: GET /v1/address-check answers activated — the fourth failure above — along with holds_usdt, blacklisted and is_contract for a single address.
Screening this way costs nothing but the requests. It is not a rehearsal of the order, though — creating one spends real TRX whichever mode it uses. How the two calls fit into a payout run of five hundred is a post of its own.
What the statuses say when delivery itself fails
The four above are about the transfer. A separate question is the energy, and the order's final status answers it. completed: delivered on every position, charged in full. partially_completed: part of the batch went undelivered through our fault, so you pay for the positions that arrived and the remainder of the reservation comes back, the two summing to what was held. failed: nothing delivered through our fault, reservation released whole. canceled: your own cancellation before procurement began, released whole as well.
The causes behind a failed position are a closed set — purchase_failed, broadcast_failed, transaction_reverted, broadcast_window_missed, window_closed_before_send — and every one releases that position's reservation. What is not a failure is expired: the energy arrived, was held for the whole window, and simply was not used. completed says the energy was delivered, not that your transfer went out; that split is set out in the Refund Policy, and the price you are held to is the one fixed in the order — the pricing page shows what that is now.