Docs / Guides / Missing transactions
Why TRON transactions "disappear"
You credit a deposit, the customer is happy — and an hour later the transaction "doesn't exist". Nothing in your code is wrong. You've hit the finality trap.
The problem
Every team that monitors TRON deposits eventually files this bug: "gettransactionbyid returned the transaction yesterday, today it returns null." Or the reverse: a webhook fired for a deposit that later evaporated. Support threads fill with "missing transaction" reports; someone adds a retry loop; the bug keeps coming back.
What's actually happening
A TRON node answers queries from one of two views of the chain:
- Full node view — includes the newest blocks the node has seen. Fast, but these blocks are not final: TRON reaches finality only after 19 of 27 super representatives have confirmed a block (~19 blocks ≈ one minute). Until then a block can be dropped in a chain reorganization, taking "your" transaction with it.
- Solidity node view (
/walletsolidity/*endpoints) — only finalized blocks. Slower by ~a minute, but what it returns can never be reorged away.
The trap: SDK defaults, tutorials, and copy-pasted code overwhelmingly query the full node view. Your poller sees an unconfirmed transaction, credits it, and if that block loses the confirmation race the transaction genuinely ceases to exist. Nothing "went missing" — it was never final in the first place. The same asymmetry works in reverse: query a lagging solidity endpoint too early and a perfectly real transaction looks absent, so your retry logic "fixes" it into a double-credit later.
The fix
One rule: money decisions only from finalized data. Concretely:
- Scan blocks with
/walletsolidity/getblockbynum+/walletsolidity/gettransactioninfobyblocknum— never the full-node equivalents. - Filter for receipt success (
contractRet === 'SUCCESS') — failed transfers are included in blocks too. - For TRC-20 (USDT), parse the
Transferevent logs from receipts rather than decoding calldata — it also catches contract-internal transfers that calldata parsing misses. - Keep a persistent block cursor so a crash never skips a block, and make event writes idempotent so a re-scan never double-credits.
If you'd rather not build and babysit that pipeline: this is exactly what tronhooks does. We scan finalized blocks only, handle receipts, cursors and retries, and send you an HMAC-signed webhook when a deposit is actually confirmed — with an events API to reconcile against.
Confirmed-only deposit webhooks, ~3s after finality. Free tier: 3 addresses.
5-minute quickstart →