Current offer: every account has 1 reset chance(s), valid for 30 days to top its balance back up to 30,000,000 CU in one click. New accounts start with 30,000,000 CU. Learn more →

Transaction traces: debug_traceTransaction and the Data API trace endpoints

Reconstruct execution call trees for a transaction: the JSON-RPC debug_traceTransaction method with its allowed tracers and guards, and the Data API getTransactionTrace and getBlockTraces endpoints with their finality limits.

Two ways to reconstruct a call tree

A transaction trace is the reconstructed call tree of an execution: which contract was called, with which input, how much gas it consumed, and which sub-calls it made. BlockVectra exposes it through two surfaces:

  • JSON-RPC debug_trace* — runs against the chain's node through the JSON-RPC endpoint, so it can trace recent state the node still has.
  • Data API traces — GET /{chain}/transactions/{hash}/trace and GET /{chain}/blocks/{number}/traces return stored, indexed call trees over REST.

Both use the same API key and are metered in CU by method weight (see the weights below). Which one fits depends on whether you need a single transaction or a whole block, how recent the target is, and whether you want to walk a full block without pagination.

Limits that apply to debug_trace*

debug_trace* requests are accepted only for methods and tracers the chain's method policy allows:

  • Allowed tracers: the tracer parameter accepts only the built-in native tracers — callTracer, flatCallTracer, prestateTracer, 4byteTracer, noopTracer, or omitting it to use the default struct logger. Any other value is rejected with JSON-RPC error -32602 tracer not allowed, not forwarded, and not billed.
  • Trace timeout: the timeout parameter must be a valid duration and at most 30s; otherwise the request is rejected with -32602 trace timeout not allowed, not forwarded, and not billed.
  • Node sync guard: while a chain's node is not synced, every method except eth_chainId — including debug_trace* and the hash/height history lookups — returns -32010; the call is not forwarded and not billed.
  • State window: debug_traceCall, debug_traceBlockByNumber, debug_traceTransaction, and debug_traceBlockByHash target a block that must be inside the chain's state window. A target earlier than the window, or one that uses the safe, finalized, or earliest tag, returns -32011. The node's own out-of-window error is not billed. Block and receipt data are not limited by the state window, but they are limited by the node's retained history.
  • Hash pre-resolution: debug_traceTransaction and debug_traceBlockByHash first resolve the hash to a block height, then apply the state window. A hash that is not 0x plus 64 hex digits returns -32000 transaction not found / block not found without querying the node; a well-formed hash the node does not know returns the same -32000, and a failed lookup is -32603 upstream unavailable (retryable). None of these are forwarded or billed.
  • Per-chain method policy: which debug_trace* methods a chain allows is published by the public GET /v1/chains response. Read it at runtime instead of hardcoding a method list; chains are listed on Supported Chains, and the method reference is in the JSON-RPC methods page.

Requesting debug_traceTransaction with callTracer

The specification's example request carries only the transaction hash. The call below adds the tracer parameter to request a call tree; the value comes from the tracer allowlist above, so no response body is invented here.

export BLOCKVECTRA_API_KEY=rgw_your_api_key

# The specification example (reqTraceTx) passes only the transaction hash:
#   {"jsonrpc":"2.0","id":1,"method":"debug_traceTransaction",
#    "params":["0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"]}
# Add "tracer" to request a call tree with one of the allowed native tracers.
curl -s "https://dev-api.blockvectra.network/v1/robinhood_mainnet" \
  -H 'Content-Type: application/json' \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceTransaction",
    "params": [
      "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
      { "tracer": "callTracer" }
    ]
  }'

What the Data API trace endpoints provide

The Data API returns stored call trees for two scopes. Neither is paginated: next_cursor is never present.

  • GET /{chain}/transactions/{hash}/trace — the call frame of one transaction, looked up by transaction hash.
  • GET /{chain}/blocks/{number}/traces — one call tree per transaction in a block, in tx_index order. A real, finalized block with zero transactions returns data: [].

The response envelope is:

  • TxTraceEnvelope: data is a CallFrame directly, plus meta.
  • BlockTracesEnvelope: data is an array of BlockTraceItem, each with txHash and the result CallFrame, plus meta.

Both trace endpoints return the standard Ethereum callTracer format. This is an exception to the Data API's money-safety encoding: elsewhere, a value that can exceed 2^53 is serialized as a decimal string; on these two endpoints, value, gas, and gasUsed are 0x-prefixed hex quantities, not decimal strings. Every CallFrame carries type, from, gas, gasUsed, and input; type is one of CALL, DELEGATECALL, STATICCALL, CREATE, CREATE2, or SELFDESTRUCT. to is absent for a CREATE/CREATE2 frame's target, and value is absent for a STATICCALL frame. Optional members are output (absent when the call returned no data), error (absent on success), revertReason (present only for an Error(string) revert), and calls (nested sub-calls in call order). Additional members of the frame are preserved.

To make the shape concrete, here is the CallFrame field skeleton — annotated, not a captured response. The locked specification has no response example for either trace endpoint, so no concrete values are shown:

{
  "type": "CALL | DELEGATECALL | STATICCALL | CREATE | CREATE2 | SELFDESTRUCT",
  "from": "0x…",                      // 20-byte address
  "to": "0x…",                        // absent for a CREATE/CREATE2 target
  "value": "0x…",                     // 0x-prefixed hex quantity; absent for STATICCALL
  "gas": "0x…",                       // 0x-prefixed hex quantity
  "gasUsed": "0x…",                   // 0x-prefixed hex quantity
  "input": "0x…",
  "output": "0x…",                    // absent when the call returned no data
  "error": "…",                       // absent on success
  "revertReason": "…",                // absent unless the call reverted with Error(string)
  "calls": []                         // nested sub-calls in call order; absent for a leaf frame
}

Parameters

  • {chain} (path parameter, required): chain identifier, the chain value of an entry in GET /chains. Matching is exact and case-sensitive; aliases and numeric chain IDs are not accepted.
  • {hash} (path parameter, required for the transaction trace): 32-byte transaction hash, 0x prefix optional, either digit case.
  • {number} (path parameter, required for the block traces): non-negative block height.

Coverage and finality

  • Both endpoints belong to the traces capability. A chain without it returns 422 no_coverage. Chains that provide this dataset are subject to the Supported Chains page and the dataset directory.
  • Trace data can start later than the rest of a chain's indexed history. A block before the chain's first traced block, inside a recorded gap, or one whose transactions were indexed but never traced and that is already too far behind the indexed head returns 422 no_coverage; GET /chains reports the boundary as coverage.traces_from_block, and a trace request before it, or inside a range that could not be traced, returns 422 no_coverage.
  • The transaction trace resolves the hash to a block, then checks the block against finalized_block: a resolved block above it returns 409 finality_exceeded. Hash lookups have no watermark to check "not indexed yet" against, so a just-submitted transaction whose indexing has not caught up also returns 404 not_found; retry briefly before treating it as permanent.
  • The block traces endpoint takes a block number. A {number} above as_of_block returns 409 not_indexed_yet with indexed_through; a {number} at or below as_of_block but above finalized_block returns 409 finality_exceeded.
  • A recent block with transactions but no trace data yet returns 503 unavailable with a Retry-After header. Once it is further behind the indexed head than the chain's trace window, it is 422 no_coverage instead.

Requesting a trace from the Data API

export BLOCKVECTRA_API_KEY=rgw_your_api_key

# One transaction's call frame.
curl -s "https://dev-api.blockvectra.network/v1/data/robinhood_mainnet/transactions/0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd/trace" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

# One call tree per transaction in a finalized block.
curl -s "https://dev-api.blockvectra.network/v1/data/robinhood_mainnet/blocks/1/traces" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

Which one to use

Typical taskBetter fitWhy
Reconstruct a single transaction right after it landsdebug_traceTransactionIt runs against the node's current state, so it is not limited to blocks at or below finalized_block; availability follows the chain's method policy.
Read a single transaction's stored call treeGET /{chain}/transactions/{hash}/traceReturns the transaction's CallFrame directly over REST; the resolved block must be at or below finalized_block.
Read every call tree in one block in one requestGET /{chain}/blocks/{number}/tracesReturns the whole block unpaginated, in tx_index order; the block must be at or below finalized_block.
Trace state the node still has but the dataset has not stored yetdebug_trace*The Data API serves stored data only up to finalized_block; the node can answer for more recent blocks.

CU per call

Every method is billed by its CU weight. The weights below are read from the platform plans API at build time:

CU weight per call

MethodCU per call
debug_trace*100
data.transaction_trace200
data.block_traces200

Weights are read from the platform plans API at build time.

Rejected requests are not billed. For the full billing rules, see What is not billed: error codes and billing rules.

Next steps

On this page