Skip to content
TraceFast Docs

API conventions

Open the block explorer →

Every TraceFast API method follows the same rules, whether it is called with an API key or paid for with x402. This page states them once; the method pages only add what is particular to a method.

Requests

RuleValue
Base URLhttps://tracefast.xyz/api/v1 with an API key; https://mpp.tracefast.xyz/api/v1 over x402
Chaina numeric path segment: /chains/1/…. 1 — Ethereum mainnet — is served; any other value answers 404 chain_not_supported
Familiesresolve to turn a name into an address; entities/{address}/… for everything keyed by an address; tokens/{token}/…; blocks/…; transactions/{hash}/…; traces/{hash}/…; contracts/{address}/…; consensus/…; risk/blacklists/{address}/…
Addresses and hashesinput: 0x-prefixed hex, any case. Output: always lowercase. An address is 40 hex characters, a hash 64
Point in time?block=N — the state at the end of block N, on every method that has a past form. Absent: the current state
Ranges?fromBlock=&toBlock= on the feeds
Parameter namescamelCase, one spelling each, no aliases
Unknown or repeated parameter400 bad_request, naming the parameter. A parameter is never accepted and ignored
MethodGET only; anything else answers 405 method_not_allowed
Request lineat most 2048 bytes; longer answers 414 uri_too_long

Responses

A successful call answers 200 application/json with two members:

{
  "data": { "…": "…" },
  "meta": {
    "chain": "ethereum",
    "timestamp": 1789047095512,
    "cached": false,
    "asOfBlock": 25947302,
    "docs": "https://docs.tracefast.xyz/api/block-latest"
  }
}
  • Numbers that can exceed 2^53 — amounts, balances, gas, wei — are JSON strings in decimal. Block heights and counts are JSON integers.
  • Field names are camelCase.
  • Absence is not falsity. A fact that is missing from an answer is not proven — it never means the opposite. Where a method has a place for an absent value, the page says whether it is omitted or null, and what that means.
  • Methods answer with facts. The one exception is resolve, on the Intelligence plan: it returns the name TraceFast shows for an address and how TraceFast presents it (name, nameStanding, impersonates). No other method carries names or labels, and none carries where a name comes from, a taxonomy or tags.

meta

FieldMeaning
chainethereum for chain id 1
timestampwhen this response was produced, Unix milliseconds
cachedtrue when the answer came from the response cache. Cached answers are refreshed within minutes
asOfBlockthe block the answer is valid at. Absent when the method states no block — absence means "not stated", never "latest"
coveragenamed block heights that bound what the method can state — for example the first block a derived fact is computed from, or the last block a lagging fact has reached. Present only on methods whose coverage is bounded; each such method page lists its keys. Read it on every call: the bounds move
docsthe documentation page of the method that answered

meta is stamped per response, so a cached body never carries a stale meta.

Errors

Every refusal is JSON — never plain text:

{
  "error": {
    "code": "block_not_available",
    "message": "block is past the covered history; the highest block that can be answered is 25901228",
    "details": { "reason": "block_not_available", "maxAvailableBlock": 25901228 },
    "requestId": "01a07bc5-0da1-7f3e-9c2a-…"
  }
}
  • code — a stable word from the table below. Branch on it.
  • message — for a human. It may be reworded; never parse it.
  • details — present only when there is something to act on: a reason that refines the code, and the bound that was hit. Absent — never null — when there is nothing to add.
  • requestId — quote it when you contact support. It is also in the X-Request-Id response header.

The key check (401, 403) and the rate limits (429) are described on API keys; over x402, a 402 is the payment challenge — see Paying with x402.

codeHTTPMeaning
bad_request400the request is outside the contract: a malformed address or hash, a parameter out of range, an unknown or repeated parameter. details.reason says which
invalid_cursor400the cursor is not valid for this request. Restart from the first page
not_found404no method at this path, or nothing at the key the path names — a block above the chain head, an unknown transaction
chain_not_supported404the chain id is not served
method_not_allowed405the path exists, the HTTP method does not
uri_too_long414the request line is over 2048 bytes. details.maxUriBytes
block_not_available422the request is well-formed, but block is outside the history covered right now. details.maxAvailableBlock, and minAvailableBlock where there is a floor — see data freshness
portfolio_too_large422the address holds more distinct positions than the method can value. details.maxPositions
token_not_covered422no balance — and so no holder list or count — can be stated for this token. details.token
balance_not_available422no balance of this address and token is recorded at or before block. details.token, details.block
service_unavailable503a transient limit on our side, or the coverage bound of the data could not be read. Retry with backoff
internal_error500our fault. No details, by design

A 422 is not a failed request: it states what the API can and cannot answer. It is never replaced by a zero, an empty list or a truncated answer.

details.reason

reasonUnder codeCarries, or means
address_invalidbad_requestthe address is not 0x + 40 hex characters
tx_hash_invalidbad_requestthe transaction hash is not 0x + 64 hex characters
topic0_invalidbad_requestthe event signature hash is not 0x + 64 hex characters
attribute_id_invalidbad_requestthe attribute or relation id is not a short identifier of letters, digits and :_.-
block_not_positivebad_requestblock
block_number_invalidbad_requestnumber — the block in the path is not a non-negative integer
block_requiredbad_requestthe method answers about one block and block was not passed
block_not_supportedbad_requestblock — the method has no past-block form
block_window_invertedbad_requestfromBlock, toBlock — the lower bound is above the upper
limit_out_of_rangebad_requestlimit, maxLimit
query_missing, query_too_short, query_too_long, query_invalidbad_requestq is missing, shorter than 2 or longer than 100 characters, or carries control characters
query_is_hashbad_requestq is a 32-byte hash — a transaction or a block, not a name or an address
unknown_parameterbad_requestthe message names the parameter and the accepted ones
duplicate_parameterbad_requestparameter
direction_invalidbad_requestdirection is outside the method's vocabulary
status_invalidbad_requeststatus is outside 1 / 0
period_invalidbad_requestperiod is outside the method's windows — each method page lists its own
event_type_invalidbad_requesteventType is outside the token-transfer event vocabulary
include_calldata_invalidbad_requestincludeCalldata is outside true / false
validator_index_invalidbad_requestindex in the path or validatorIndex in the query is not a non-negative integer
group_by_invalidbad_requestgroupBy is outside validator / address
block_window_too_widebad_requestspan, maxSpan, fromBlock, toBlock — the block window is wider than the method admits; narrow it
issuer_contract_invalidbad_requestissuerContract is not 0x + 40 hex characters
action_invalidbad_requestaction is outside add / remove / enforce
peer_count_over_limitbad_requestpeerCount, maxPeerCount — the past-block ranking cannot be computed for an address with this many counterparties
row_count_over_limitbad_requestrowCount, maxRowCount
window_row_count_over_limitbad_requestthe feed window is too wide for this address; narrow fromBlock / toBlock
filter_needs_block_windowbad_requestfilters, rowCount, maxUnboundedRowCount, spanBlocks, maxSpanBlocks — too many rows to filter without a block window; pass fromBlock / toBlock
invalid_cursorinvalid_cursor—
uri_too_longuri_too_longmaxUriBytes
block_not_availableblock_not_availablemaxAvailableBlock, minAvailableBlock when there is a floor
coverage_gapblock_not_availablecoverageGapFromBlock, maxAvailableBlock, and coverageGapToBlock unless the gap is open-ended — see below
portfolio_too_largeportfolio_too_largemaxPositions
token_not_coveredtoken_not_coveredtoken
no_history_rowbalance_not_availabletoken, block

Numbers a client acts on are in details, built from the same values as the sentence in message.

Data freshness

Most TraceFast methods answer up to the head of the chain. Some data is built behind the head, and the methods that serve it refuse rather than answer empty: an empty list would mean "nothing happened in this block", and that is a statement we do not have.

The refusal is HTTP 422 with error.code block_not_available:

{
  "error": {
    "code": "block_not_available",
    "message": "block is past the covered history; the highest block that can be answered is 26091091",
    "details": { "reason": "block_not_available", "maxAvailableBlock": 26091091 },
    "requestId": "01a0f2e7-0e5e-7eb0-ab47-53e3b52bffde"
  }
}
  • details.maxAvailableBlock — the highest block the method can answer right now. Ask again at that block, or repeat the request later.
  • maxAvailableBlock is in every 422 but one. On the methods keyed by a transaction hash — trace, call frames, why it reverted, storage writes — the data may not have reached the transaction at a moment when its own bound cannot be read either. The refusal is then reason: coverage_gap with no bound, and the only move is to retry later. Code that takes maxAvailableBlock and asks again must check that it is present. On methods keyed by a block number the same situation answers 503 instead.
  • details.reason coverage_gap — a different case: the block exists, but it sits in a range that is temporarily unavailable. The bounds of the range are in coverageGapFromBlock and coverageGapToBlock. It never means "no such block" — retry later; see coverage gaps.
  • HTTP 503 service_unavailable — the coverage bound could not be read. Retry with backoff.
  • HTTP 404 not_found — the block is above the head of the chain: it does not exist yet.

What trails the head, as it stood on 2026-09-30. This is an example on a date, not a guarantee — the values move, so go by the response, not by this list:

MethodReach on 2026-09-30
One block, block transactions, block withdrawals, block addressesthe head, no lag
Validator withdrawalsbehind the head by minutes; the same withdrawals reach block withdrawals first
Block authorizations, why it revertedbuilt behind the head: usually minutes to tens of minutes, at times an hour or more. The 422 names the highest block you can ask about

An empty list on HTTP 200 always means "we looked, and there is nothing" — never "we have not looked yet".

Coverage gaps

A range of blocks can be temporarily unreadable here even though it exists on chain — a coverage gap. Any method may then answer 422 block_not_available with reason: coverage_gap and the bounds of the gap in details. The verdict comes before the read: a method keyed by a block never answers an empty page for a block inside the gap.

The same refusal covers keys whose block is not known in advance:

  • A transaction hash — absence cannot be confirmed while a gap is open.
  • An address or a token contract with no recorded history — its first activity, or its first transfer, could sit inside the gap, so the API answers coverage_gap rather than 404 not_found. The message names the key it is about; details is the same.
  • Execution traces and the classification of failures become available minutes to hours after the transaction, sometimes later. A transaction whose trace or failure classification is not available yet is refused with the maxAvailableBlock that data has reached; coverageGapFromBlock is the next block, and coverageGapToBlock is absent because the range is open-ended. The refusal says nothing about the transaction's outcome.

Read it as "ask again later", never as "this does not exist". Requests at or below maxAvailableBlock outside the gap are unaffected, and the refusal disappears on its own when the gap closes. Retrying within seconds is pointless; within hours it is not. Where a method's reach is bounded, its meta.coverage names the bounds on every answer.

Pagination

Feeds page by keyset, never by offset — ?page= and ?offset= are refused by name.

  • limit — rows per page, 1 up to the method's cap; the cap and the default are on each method page.
  • nextCursor — in data while there are more rows; absent on the last page.
  • cursor — pass nextCursor back unchanged, with the same filters. A cursor is sealed to its method, chain, direction and filters: altered, or reused under different ones, it answers 400 invalid_cursor. A cursor can also expire. The recovery is the same in every case — restart from the first page.
  • A page holds at most limit rows and may hold fewer while nextCursor is still present: a page of large rows — an event log's data is bounded only by gas — is cut by size, never by cutting a value. A single row larger than that is served whole.
  • total is stated only where it is cheap to know.

Stability

Every public method is stable since 2026-10-01. A method added later may start in beta; its page says so.

StabilityPromiseRetirement
Betathe shape may still change, with noticeno notice window
Stablefrozen; a breaking change becomes a new methodat least 90 days between the announcement and the sunset

A retired method is marked deprecated in the OpenAPI document and announces itself on every response with Deprecation, Sunset and Link headers — the last pointing to its documentation and its successor. Nothing is deprecated today.

Headers

HeaderOnValue
Content-Typeevery responseapplication/json
Cache-Controlsuccessprivate, max-age= the seconds the cached answer has left
Cache-Controlrefusalno-store
X-Request-Idevery responsethe request's id
X-Content-Type-Optionsevery responsenosniff

The OpenAPI document at https://tracefast.xyz/api/v1/openapi.json needs no key and answers conditional requests: its ETag is its info.version, so an unchanged document costs a 304.


Last updated 22 Oct 2026, 08:06 UTC · verified against TraceFast v1.0.261 · Markdown