Call frames of a transaction, paged
The whole call tree of a transaction, frame by frame in the order it ran, page by page. Each frame carries everything the execution trace carries, plus — always — the first 260 bytes of its calldata and output with their full sizes, and the positions of the event logs it emitted.
Use this method when a tree is larger than the trace's 1 000-frame cap, or when you need every frame's calldata or the logs a frame emitted. For a small tree read in one response, the execution trace is simpler.
GET https://tracefast.xyz/api/v1/chains/1/traces/{hash}/frames
| Parameter | In | Type | Notes |
|---|---|---|---|
hash | path | string | 0x-prefixed, 64 hex characters, any case |
limit | query | integer, optional | frames per page, 1..100, default 50 |
cursor | query | string, optional | nextCursor of the previous page. Valid only for this method and this transaction |
Access — an API key on the Investigation plan or higher (plans), or no key at all: pay per call with x402 at the same path on https://mpp.tracefast.xyz/api/v1, at the price its 402 states. As a tool for AI agents: get_trace_frames on the MCP server. Stable — see stability.
chains/1 is a literal: the method serves Ethereum mainnet data. Other chain
ids answer 404 chain_not_supported. There are no other parameters — an
unknown one is refused rather than ignored.
What it covers, and what it does not
- Up to 20 000 frames. The method walks the tree to that size; when it is
larger, the last page says so with
framesTruncated: true. A clipped tree never claims to be the whole one. orderis the position in the whole tree, not in the page: a page that starts atorder50 continues the one that ended at 49.- A page may hold fewer frames than
limitwhen their calldata is large. It still continues from the last frame served; only an absentnextCursorends the walk. - A trace that is not available yet is refused, never answered empty.
Traces trail the chain by minutes to hours, sometimes longer. A
transaction in a block they have not reached answers
422 block_not_availablewithreason: coverage_gapand the last block traces are available for. That says nothing about the transaction's outcome — ask again later. - Frames and their log positions have a starting block.
meta.coveragenames the first block the frames are computed from (framesFromBlock) and the first block the event attribution is computed from (eventAttributionFromBlock). Both can move to earlier blocks over time.
Response
200 application/json, here with ?limit=1 — the first page of a USDC
transfer through its proxy:
{
"data": {
"hash": "0xc41b41fb1c3eea59ea87b9e90edf476fb202e8daf02f19f469cdf497adbc76e0",
"blockNumber": 25920000,
"txIndex": 3,
"frames": [
{
"order": 0,
"depth": 1,
"callPath": "0000",
"callType": "call",
"from": "0x978e75381d64fb18af7112e42fa76a211a773456",
"to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"valueWei": "0",
"gas": "78392",
"gasUsed": "40652",
"inputSelector": "0xa9059cbb",
"status": "success",
"revertDecodeStatus": "absent",
"codeAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"inputHead": "0xa9059cbb000000000000000000000000f9dec5642e2b51ba67c695144d3360fab966f5a30000000000000000000000000000000000000000000000000000000029ba1944",
"inputSize": 68,
"outputHead": "0x0000000000000000000000000000000000000000000000000000000000000001",
"outputSize": 32,
"logIndexes": []
}
],
"framesTruncated": false,
"nextCursor": "AVsyNTkyMDAwMCwzLDBdr7mkLJEtmSoLlzCQTIJIQw"
},
"meta": {
"chain": "ethereum",
"timestamp": 1789063644283,
"cached": false,
"asOfBlock": 25920000,
"docs": "https://docs.tracefast.xyz/api/trace-frames",
"coverage": {
"eventAttributionFromBlock": 2675000,
"framesFromBlock": 2675000
}
}
}The second page holds frame order: 1 — the proxy's delegatecall into its
implementation — with logIndexes: [0]: the Transfer event was emitted by the
implementation's code, not by the outer call. That page carries no
nextCursor, so the tree has two frames.
data
| Field | Meaning |
|---|---|
hash | the transaction, lowercase |
blockNumber, txIndex | its block and index within the block |
frames[] | this page, in pre-order |
framesTruncated | true on the last page when the tree is larger than 20 000 frames and frames remain unserved |
nextCursor | pass it back as cursor for the next page. Absent on the last page |
A frame
A frame has every field of a frame in the execution trace
— its position (callPath, parentPath), the call, value and gas, what it created
(createdAddress, salt, initCodeHash, selfdestructBeneficiary) and its
outcome (errorKind, errorSelector, revertReason, revertData,
revertDataSize, revertDataTruncated) — with two differences:
| Field | Meaning |
|---|---|
inputHead, outputHead, inputSize, outputSize | always present, not opt-in: the first 260 bytes of the frame's calldata and output, lowercase 0x-hex, and their full lengths in bytes. Compare the size against 260, not against the hex string's length |
logIndexes | the positions, within the transaction's receipt, of the event logs this frame emitted, ascending. Empty when it emitted none. Match them with logIndex on transaction events |
meta.coverage
| Key | Meaning |
|---|---|
framesFromBlock | the first block frames are served from; an older transaction is refused with 422 |
eventAttributionFromBlock | the first block from which logIndexes are computed |
Pagination
Pages are keyset, not offset. Pass nextCursor back as cursor until it is
absent; keep the same hash. A cursor opens only for this method and this
transaction; any other use, or a cursor altered in transit, answers 400 invalid_cursor — restart from the first page. See
pagination.
Errors
| Status | code | When | details |
|---|---|---|---|
| 400 | bad_request | the hash is not 0x plus 64 hex characters | reason: tx_hash_invalid |
| 400 | bad_request | limit is outside 1..100 | reason: limit_out_of_range, limit, maxLimit: 100 |
| 400 | invalid_cursor | the cursor is not valid for this request | reason: invalid_cursor |
| 404 | not_found | no transaction with this hash is known | — |
| 422 | block_not_available | the transaction is below the height frames are served from | reason: block_not_available, minAvailableBlock |
| 422 | block_not_available | the traces have not reached the transaction's block yet; ask again later | reason: coverage_gap, maxAvailableBlock, coverageGapFromBlock — no coverageGapToBlock: the range is open-ended |
| 422 | block_not_available | the hash is unknown while recent blocks are in a coverage gap; ask again later | reason: coverage_gap, coverageGapFromBlock, coverageGapToBlock, maxAvailableBlock |
Malformed input, unknown parameters and the key check's 401/403/429 are the same for every method — see conventions and API keys.
Related pages
- Execution trace of a transaction — the same tree in one response, up to 1 000 frames, calldata opt-in
- Transaction events — the logs that
logIndexespoint at - Storage writes of a transaction — what each frame wrote to contract storage
- Why a transaction reverted — only the failed frames, with error names
- Transactions: Trace — the call tree in the app
Last updated 22 Oct 2026, 08:06 UTC · verified against TraceFast v1.0.261 · Markdown