Skip to content
TraceFast Docs

Portfolio of an address

See a portfolio on an entity page →

Everything an address holds, valued in USD: its token balances and its native ETH, each with the balance, the hourly price, the USD value and the share of the total.

GET https://tracefast.xyz/api/v1/chains/1/entities/{address}/portfolio
ParameterInTypeNotes
addresspathstring0x-prefixed, 40 hex characters, any case
blockqueryinteger, optionalthe state at the end of this block, priced at that block's hour. Absent: the current state
limitqueryinteger, optional1..100, default 100

Access — an API key on the Intelligence 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_entity_portfolio 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

  • Token balances and native ETH only. No NFTs, no DeFi positions, no liquidity-pool shares.
  • Token balances are served for the covered tokens — coveredTokenCount says how many that is, and the set grows. A balance in a token outside it is absent from the answer, not zero.
  • A position is listed only when it can be valued — a USD price for the hour and known decimals. Everything else the address holds is counted in hiddenCount and never listed.
  • At a past block, rebasing tokens count too. A token whose balance grows without transfer events — stETH and the like — enters with its balanceOf at the end of block: listed when it can be valued, otherwise in hiddenCount.

Response

200 application/json, here with ?limit=2:

{
  "data": {
    "address": "0xf977814e90da44bfa03b6295a0616a897441acec",
    "window": { "kind": "current", "asOfBlock": 26132399, "nativeFreshness": "head" },
    "priceBasis": "latest_hour",
    "totalUsd": 20436624609.08933,
    "pricedCount": 178,
    "hiddenCount": 956,
    "coveredTokenCount": 393435,
    "positions": [
      {
        "kind": "token",
        "token": "0xdac17f958d2ee523a2206206994597c13d831ec7",
        "symbol": "USDT",
        "decimals": 6,
        "balance": "16000000001124208",
        "priceUsd": 1,
        "priceHour": 1791280800,
        "priceCarried": false,
        "valueUsd": 16000000001.124208,
        "share": 0.7829081517702341,
        "asOfBlock": 26132399
      },
      {
        "kind": "native",
        "symbol": "ETH",
        "decimals": 18,
        "balance": "519397738757924349825671",
        "priceUsd": 2709.57739502,
        "priceHour": 1791280800,
        "priceCarried": false,
        "valueUsd": 1407348371.9629753,
        "share": 0.06886403204456021,
        "asOfBlock": 26130116
      }
    ]
  },
  "meta": {
    "chain": "ethereum",
    "timestamp": 1791284628440,
    "cached": true,
    "asOfBlock": 26132399,
    "docs": "https://docs.tracefast.xyz/api/address-portfolio"
  }
}

With ?block=24500000 the same address answers window.kind: "block", priceBasis: "hour_of_block", a priceHour, and the balances as they stood then.

data

FieldMeaning
window.kindcurrent, or block when you asked for one
window.asOfBlockthe block the answer is true at — the state at the end of it. With block, the requested block. In the current view, the block the token balances are valid at; it moves forward every few hours
window.nativeFreshnesshead in the current view: the native ETH balance is read up to the chain head, so it can be newer than window.asOfBlock. Absent with block, where every position is at the requested block
priceBasislatest_hour for the current view, hour_of_block with block
priceHourwith hour_of_block: the start of the UTC hour every position is priced at, in Unix seconds
totalUsdthe sum over all valued positions, not only the listed ones. Absent — never 0 — when nothing could be valued
pricedCounthow many positions carry a USD value: the size of the set positions is the top of
hiddenCountassets held with a positive balance that could not be valued. Counted, never listed, not part of totalUsd
coveredTokenCounthow many token contracts balances are served for right now
positions[]at most limit rows in descending USD value

pricedCount + hiddenCount is everything the address holds.

A position

FieldMeaning
kindtoken or native
tokenthe contract, lowercase; absent for the native asset
symbolthe ticker as declared by the contract (ETH for the native asset), absent when it declares none. Any contract can declare any symbol — this is not proof of identity
decimalsas declared by the contract
balancea decimal string in the asset's smallest unit — wei for ETH — not divided by decimals
priceUsdUSD per whole unit at priceHour
priceCarriedtrue when no price was observed in that hour and the latest earlier one was used
valueUsdbalance / 10^decimals × priceUsd, a floating-point estimate; the exact figure follows from balance and priceUsd
sharevalueUsd / totalUsd, between 0 and 1
asOfBlockthe block this balance last changed at. For a token in the current view it can be earlier than window.asOfBlock — the balance has not changed since and is valid at window.asOfBlock. For native ETH in the current view it is the block of the address's last balance change, read up to the chain head, so it can be later than window.asOfBlock

An address holding nothing valued answers 200 with an empty list, no totalUsd, and hiddenCount for whatever it does hold. That is an answer, not an error.

Two things not to confuse

hiddenCount is not dust. It is everything held that could not be priced — a token with no hourly price, or with unknown decimals. A large hiddenCount means totalUsd is a lower bound, not the address's worth.

Absent is not zero. A token outside the covered set is simply not in the answer. When you need a definitive statement about one token, ask address token balance — it refuses instead of guessing.

Errors

Every error is JSON: { "error": { "code": "...", "message": "...", "details": { … } } }

StatuscodeWhendetails
400bad_requestmalformed address; block not positive; limit outside 1..100; an unknown query parameterreason: limit_out_of_range, maxLimit: 100
422block_not_availableblock is past the covered historyreason: block_not_available, maxAvailableBlock
500internal_errorour source returned two balances for one token at one block; neither is chosen—
422portfolio_too_largethe address holds more distinct tokens than the method can valuemaxPositions
404chain_not_supporteda chain id other than 1—
402—payment required, or payment rejected — see Paying with x402—

Numbers a client has to act on are in details, never parsed out of message.


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