/token-score produces a deterministic 0–100 description of a Base token’s current market structure. The response includes every raw input, sub-score, weight, breakpoint, and read time needed to reproduce the result.
The score does not predict returns, compare a token with its peers, or recommend buying, selling, or holding. Its band is only a label for the numerical result.
Input
The endpoint accepts a Base ERC-20 contract address:0x followed by 40 hexadecimal characters. An invalid key is rejected uncharged.
The address is the identity shared by the price, pool, and holder reads. Symbols are not accepted because the same symbol can resolve to different deployments on different chains. Use /token-price for a symbol lookup.
Formula
Each raw input is mapped to a 0–100 sub-score by linear interpolation between the breakpoints returned informula.factors. Values beyond the first or last breakpoint are clamped. The composite is the weighted mean of the available sub-scores, with weights renormalized over the factors that resolved.
The weights are a product judgement, not the result of a backtest. They travel with every response so a consumer can apply different weights to the published sub-scores.
Liquidity and price movement
The liquidity factor sums liquidity only for returned pools whose token address matches the requested contract. The value is a floor, because the pool search returns one page rather than every pool in existence.context.poolsReturned and context.matchedPoolCount show the coverage. The separate context.liquidityUsd field is the price plane’s top-pool value and is not scored.
Price direction is also not scored. priceStability uses the absolute 24-hour move so a rapid rise does not receive a higher score merely for moving upward. The signed move remains available in context.priceChange24hPct.
Missing data and withholding
Every factor remains in the response even when its input is missing:
An absent factor has
present: false, score: null, its nominal weight, and its data plane. A factor from a successful read also carries planeReadAt. No missing factor is replaced with a neutral value.
coverage.weightCoverage is the share of nominal weight that resolved. If it is below 0.5, the endpoint returns:
Bands
Two fields that need context
Holder concentration includes contracts. Top addresses can include liquidity pools, burn addresses, bridges, staking contracts, and treasuries. The factor measures concentration; it does not identify insiders. Turnover is returned without a score.context.turnover24h divides 24-hour volume by pooled liquidity. High turnover can reflect demand or wash trading, and these inputs do not distinguish the two.
Inputs come from public DEX data and Otto’s licensed holder-data provider. The response’s formula block is the authority for the exact calculation used on that read.