Transactions API
What one transaction did
A single transaction by its hash: whether it succeeded, why it reverted, who sent it, what it moved, and which tokens changed hands.
/api/external/transaction-analysis/transaction/{chain}/{hash}What it returns
One transaction, addressed by its hash. Answers whether it succeeded or failed, why it failed when a human-readable reason exists, who sent it and to whom, and every token transfer that happened inside it. Served on BNB, BASE, ETH, RHC, SOL and STABLE; ARC returns 400. ON SOL, to AND nativeValueRaw ARE ALWAYS NULL, and that is structural, not a gap: a Solana transaction has no single recipient and carries no value of its own — native SOL moves as ordinary instructions inside it, any number of them, so there is no one figure to publish. tokenSymbol and tokenType are null there too. AMOUNTS ARE RAW BASE UNITS, as strings, paired with the token decimals — never pre-divided, because a uint256 does not fit in a JSON number and an assumed decimals count publishes a plausible figure that is wrong by a power of ten. ON BNB, BASE AND STABLE, WRAPPING OR UNWRAPPING THE NATIVE COIN IS NOT A TOKEN TRANSFER: those contracts announce a deposit or a withdrawal, not a transfer, so a swap that routes through the wrapped native coin has one fewer row there than the same swap on ETH or RHC. Nothing is invented to close the gap, and truncated stays false for it — a flag that fired on every wrapper interaction would stop meaning anything. A hash that is well-formed but unknown returns 404, never an empty transfer list: "we have no such transaction" and "this transaction moved no tokens" are different answers and this resource keeps them apart. PER-ADDRESS BALANCE CHANGES ARE NOT PUBLISHED. They are available upstream but only at a median 14 seconds against a 15-second timeout, so asking for them would make roughly one request in six take 47 seconds; the field is absent rather than always null, because a null would claim it was checked. Distinct from the token-keyed transfer feed, which answers about one token across its whole history rather than about one transaction.
Chains
- Solana SOL
- BNB Chain BNB
- Ethereum ETH
- Stable STABLE
- Base BASE
- Robinhood Chain RHC
Request
Send your key in the x-dex-data-key header. Replace each <placeholder> with a real value.
curl -H "x-dex-data-key: $DEXDATA_API_KEY" \ "https://api.dexdata.io/api/external/transaction-analysis/transaction/SOL/<hash>"
| Parameter | Description |
|---|---|
chainpath · string · required | BNB, BASE, ETH, RHC, SOL and STABLE. ARC is the one chain that returns 400, and the reason is revertReason: nothing that answers on ARC can say WHY a transaction reverted, and the field would be permanently null rather than occasionally null. The six are not all answered the same way, which is why a few fields are structurally null on SOL and a few behave differently on BNB, BASE and STABLE — each says so in its own description. CELO, ARB, OP and SCROLL return 400 here. |
hashpath · string · required | The transaction: a 0x-prefixed 64-hex-character hash on every chain except SOL; the transaction's first signature, base58, on SOL. |
Response fields
A JSON response. Every field is always present; null means the value could not be established, never zero.
| Field | Type | Description |
|---|---|---|
status | string | null | Whether the transaction succeeded. null is a real state, not a placeholder, and it has two causes: a transaction whose outcome the source has not finished deciding, and a PENDING transaction — one the chain has accepted and not yet mined, which has no outcome to report at all and comes back with at, block and revertReason null and truncated true. Never inferred from the failure text, which is free-form prose and can carry an indexing placeholder rather than an outcome. |
revertReason | string | null | Why a failed transaction reverted, in human-readable form — "insufficient output amount", or a short contract code such as "AR34". null whenever no readable reason exists, which includes the common case of a revert carrying only a 4-byte error selector with no ABI to resolve it. ON ETH AND RHC that selector is often resolved into a NAMED custom error such as "SlippageExceeded(uint256 amountLD, uint256 minAmountLD)"; on BNB, BASE and STABLE it is not, so the same transaction reads null there. null here NEVER means the transaction succeeded — read status for that; a failed transaction with a null reason is ordinary, and on those three chains it is the common case. |
from | string | null | The sending address. |
to | string | null | The receiving address. null is a REAL value for a contract creation, which has no recipient, as well as for an unknown one. ALWAYS null on SOL, where a transaction is a list of instructions with no single callee — there it means "this chain has no such thing", not a contract creation. |
nativeValueRaw | string | null | Native coin moved by the transaction itself, in RAW base units, as a decimal string. A string because the value can exceed what a JSON number holds exactly, and raw because no decimals count is published for the native coin. "0" is a real measurement and is different from null. READ THIS ALONGSIDE tokenTransfers: a plain native transfer has an empty tokenTransfers array and a non-zero value here, so an empty array on its own does not mean nothing moved. ALWAYS null on SOL: nothing is attached to the transaction there, so a plain SOL payment answers an empty tokenTransfers AND a null here — the empty array is true, and the null says the native leg is not published on that chain rather than that nothing happened. |
at | integer | null | Unix SECONDS the transaction was mined at, or null. |
block | integer | null | The block it was mined in, or null. |
tokenTransfers | object[] | Every token movement inside this transaction, in the order the source reports them. Always an array, possibly empty; never null. An empty array means no TOKEN moved — check nativeValueRaw before reading it as "nothing happened" — and read truncated before reading it as the complete list. ON BNB, BASE AND STABLE these are the transfers the transaction ANNOUNCED: wrapping or unwrapping the native coin announces no transfer, so it is absent here on those three chains and present on ETH and RHC. It is not counted as truncation and no row is synthesised for it, because a synthesised row cannot be told apart from a real one by a caller. |
tokenTransfers[].from | string | null | The sending address. The zero address on a MINT — a real, observed event, not a placeholder. |
tokenTransfers[].to | string | null | The receiving address. The zero address on a BURN. |
tokenTransfers[].amountRaw | string | null | The amount in RAW base units, as a decimal string. Divide by 10^decimals to get a human figure, and do not divide at all when decimals is null. |
tokenTransfers[].decimals | integer | null | The token's decimals. null when the source did not report one — in which case amountRaw cannot be safely scaled — and ALWAYS null on an ERC-721 or ERC-1155 row, which counts items rather than fractions of one. A real 0 is possible and is not the same as null. |
tokenTransfers[].tokenAddress | string | null | The token contract address. |
tokenTransfers[].tokenSymbol | string | null | The token symbol. Always null on SOL, where resolving one would be a separate lookup per token rather than part of this answer. On BNB, BASE and STABLE it is read from the token contract itself, so it is null for a contract that does not answer, and for every token past the first 25 distinct ones in a single transaction — a cap on cost, not a statement about the token. The transfer row is published either way. |
tokenTransfers[].tokenType | string | null | The token standard, e.g. ERC-20, ERC-721, ERC-1155. Always null on SOL: that chain draws no such line at the token level, so any value here would answer a different question than the one this field asks. |
truncated | boolean | Whether tokenTransfers is known to be INCOMPLETE. false means the list is whole; true means more transfers happened than are published here. Both are measurements, which is why this is a boolean rather than nullable. On ETH and RHC it is true when a transaction carried more transfers than the primary read returns and the follow-up that completes the list did not come back. On BNB, BASE and STABLE there is no second page to fall behind, and it is true in two other cases: a PENDING transaction, whose transfer list does not exist yet and must not be published as an empty one, and a transfer event in a shape this resource does not read — rare, and flagged rather than dropped. Always false on SOL, where the whole list comes out of the one read and there is nothing to paginate behind. |
Start building with DexData today
Sign in, create a key and make your first call in a minute. Free credits every month, and you only pay for calls that succeed.
Get a free API key