valscope

Public API

Read-only JSON under /api/v1, served from the same queries as the pages. No key is needed. Every response is cached at the edge for one indexer tick, so numbers can lag the chain by up to thirty seconds.

Conventions

Envelope. Successful responses are { data, meta } where meta carries the epoch, slot and sample time the numbers refer to and the generation time. Errors are { error: { code, message } } with status 400 (bad parameter), 404 (unknown key or dataset not deployed), 429 (rate limit) or 500.

Numbers. Lamports and other 64-bit chain quantities (stake, rewards, fees, balances, slots, credits) are strings; rates, shares and ratios are JSON numbers in the unit the name says (a share of 0.105 is 10.5 %); commissions are integer basis points; times are ISO-8601 UTC.

Caching and limits. Cache-Control: public, s-maxage=30, stale-while-revalidate=120 on every GET; CORS is open for GET. Each address may make 60 requests per minute to uncached paths; a 429 carries Retry-After. Cached repeats do not count.

Attribution. Data is computed from chain data by the valscope indexer (stake accounts and their authorities, reward partition blocks, vote state, gossip). MEV figures come from Jito's Kobe API, prices from Jupiter and CoinGecko. Please link to valscope.app when you publish derived numbers.

GET /api/v1/network

Returns. the home-page aggregates: epoch progress, stake, inflation, supply, last rewarded epoch, epoch length, SOL price, concentration (Nakamoto coefficient, top shares, ASNs, countries), stake by source, client and version shares

{
  "data": {
    "epoch": { "epoch": 1049, "slot": "453517740", "slotIndex": "349740", "slotsInEpoch": "432000", "progress": 0.8096, "sampledAt": "2026-10-05T07:46:12.000Z" },
    "stake": { "activeStake": "442016234000000000", "delinquentStake": "131000000000000", "validators": 686, "delinquent": 15 },
    "rewards": { "epoch": 1048, "totalRewards": "78640007412123", "clusterRewardRate": 0.0001779, "clusterApy": 0.04984, "epochsPerYear": 273.38 },
    "price": { "usd": 120.67, "at": "2026-10-05T09:38:32.421Z", "source": "jupiter" },
    "concentration": { "nakamoto": 18, "superminorityShare": 0.335, "top10Share": 0.241, "top33Share": 0.49, "asns": [ { "asn": 396356, "org": "Latitude.sh", "stake": "46…", "share": 0.105, "validators": 93 } ], "countries": [ … ] },
    "stakeBySource": { "epoch": 1049, "buckets": [ { "key": "pools", "name": "Stake pools", "stake": "51…", "share": 0.116, "accounts": 3120 }, … ] },
    "clients": [ { "client": "agave", "clientMod": "bam", "label": "Agave + BAM", "stake": "159…", "share": 0.36, "validators": 371 }, … ],
    "versions": { "modal": "4.3", "rows": [ { "version": "4.3", "stake": "…", "share": 0.838, "validators": 591 }, … ] }
  },
  "meta": { "epoch": 1049, "slot": 453517740, "sampledAt": "2026-10-05T07:46:12.000Z", "generatedAt": "2026-10-05T07:46:20.113Z" }
}

GET /api/v1/validators

Parameters. sort = stake | commission | credits | apy | skip | name | client | net · dir = asc | desc · client = agave | firedancer | frankendancer · q (name, vote or identity substring) · limit ≤ 200 · offset

Returns. explorer rows from the materialised view (refreshed every tick): stake and rank, commission and pending commission, credits ratio, 30-epoch APY, skip rate, mean vote latency, client, location, last net income

{
  "data": { "total": 687, "limit": 2, "offset": 0, "validators": [
    { "vote": "CcaHc2L…", "identity": "Fd7btg…", "name": "Figment", "activeStake": "17930000000000000", "stakeRank": 1, "stakeShare": 0.0406,
      "commissionBps": 700, "pendingCommissionBps": null, "delinquent": false, "superminority": true, "blsRegistered": true,
      "client": "agave", "clientMod": "jito", "version": "4.3.0", "country": "Germany", "city": "Limburg an der Lahn",
      "credits": "6910000", "clusterMaxCredits": "6912000", "creditsRatio": 0.9997, "apy30": 0.0463, "leaderSlots": 17520, "blocksProduced": 17511, "skipRate": 0.0005,
      "latencyMean": 1.08, "netLast": "1061369832319", "netEpoch": 1048 }
  ] },
  "meta": { … }
}

GET /api/v1/validators/{vote}

Returns. identity (name, website, keybase, details, icon), the current sample (stake, commission, credits, last vote, client, location, authorities, balances) and the twelve health checks

{ "data": { "vote": "…", "identity": "…", "name": "…", "current": { "activeStake": "…", "commissionBps": 500, "pendingCommissionBps": null, "delinquent": false, "client": "agave", "clientMod": "bam", "voteBalance": "2420000000", "identityBalance": "19510000000", … },
  "health": { "epoch": 1049, "flags": [ { "id": "voting", "label": "Voting", "status": "pass", "detail": "last vote slot 453,517,740" }, … ] } }, "meta": { … } }

GET /api/v1/validators/{vote}/epochs

Parameters. limit ≤ 64

Returns. per-epoch rows, oldest first: stake, commission, credits and ratio, delinquent seconds, version, leader slots and blocks produced, skip rate, mean latency

{ "data": { "vote": "…", "epochs": [ { "epoch": 1049, "activeStake": "…", "commissionBps": 500, "credits": "…", "creditsRatio": 0.9998, "delinquentSeconds": 0, "version": "4.3.0", "leaderSlots": 84, "blocksProduced": 84, "skipRate": 0, "latencyMean": 1.1, "latencyFullShare": 1 } ] } }

GET /api/v1/validators/{vote}/stake

Parameters. epochs ≤ 200 (history window)

Returns. stake by source for the current attribution epoch (pools, labelled authorities, self, unlabelled buckets, with activating and deactivating amounts) and the stacked history

{ "data": { "vote": "…", "current": { "epoch": 1049, "total": "117000000000000", "sources": [ { "kind": "label", "key": "Solana Foundation (SFDP)", "name": "Solana Foundation (SFDP)", "active": "61400000000000", "activating": "390000000000", "deactivating": "0", "accounts": 4 }, … ] },
  "history": { "epochs": [1048, 1049], "dates": ["2026-10-03", "2026-10-04"], "series": [ { "key": "pool:Jito4AP…", "name": "Jito", "values": ["…", "…"] } ], "totals": ["…", "…"] } } }

GET /api/v1/validators/{vote}/rewards

Parameters. limit ≤ 200

Returns. per-epoch rewards, oldest first: effective stake, delegator rewards, commission, reward rate and APY, MEV and priority-fee data from Jito, block fee rewards, production, the method used (blocks | points | inflation_reward)

{ "data": { "vote": "…", "rewards": [ { "epoch": 1048, "effectiveStake": "…", "stakingRewards": "19800000000", "commissionRewards": "1040000000", "commissionBps": 500, "rewardRate": 0.000169, "apy": 0.0472, "mevRewards": "1110000000", "mevCommissionBps": 1000, "mevRate": 0.0000085, "runningJito": true, "runningBam": true, "feeRewards": "0", "leaderSlots": 84, "blocksProduced": 0, "method": "blocks", "clusterRate": 0.000178, "epochsPerYear": 273.4 } ] } }

GET /api/v1/validators/{vote}/finance

Parameters. limit ≤ 200

Returns. per-epoch income and cost lines: inflation commission, block fee rewards (with coverage), MEV and priority-fee commission, vote fees (exact from balance accounting or estimated), VAT, balances at the boundaries, flows, net before hosting, SOL price

{ "data": { "vote": "…", "finance": [ { "epoch": 1048, "inflationCommission": "1040000000", "feeRewards": "0", "feeCoverage": 0, "mevCommission": "111000000", "pfCommission": "0", "voteFees": "2159500000", "voteFeesMethod": "estimate", "flowsCoverage": 1, "landedVotesEst": "431900", "identityEnd": null, "income": "1151000000", "voteCost": "2159500000", "net": "-1008500000", "solPriceUsd": 120.62 } ] } }

GET /api/v1/validators/{vote}/events

Parameters. limit ≤ 200

Returns. change events, newest first: commission_change, block_commission_change, voter_change, withdrawer_change, collector_change, bls_registered, identity_change, version_change, info_change, delinquent_start, delinquent_end, withdrawal

{ "data": { "vote": "…", "events": [ { "id": 812, "kind": "commission_change", "at": "2026-10-04T15:46:32.683Z", "slot": "453300120", "payload": { "from_bps": 500, "to_bps": 450, "effective_epoch": 1050 } } ] } }

GET /api/v1/pools

Parameters. sort = tvl | validators | median | mean | price | apy | name · dir · limit ≤ 200 · offset

Returns. the pool catalog with the latest epoch figures: TVL, token supply and price, validator count, median and mean per validator, top-1 share, the epoch reward rate (apyR, null until the epoch has ended) and its 30-epoch mean (rate30), headline fee, open-delegation flag

{ "data": { "total": 1848, "limit": 1, "offset": 0, "pools": [ { "address": "Jito4AP…", "program": "SPoo1K…", "kind": "spl", "name": "Jito", "symbol": "JitoSOL", "mint": "J1toso…", "openDelegation": true, "epoch": 1049, "tvl": "10329410000000000", "tokenSupply": "…", "price": 1.2143, "validatorCount": 413, "medianStake": "32200000000000", "meanStake": "…", "top1Share": 0.031, "apyR": null, "rate30": 0.000166, "fee": { "key": "epoch_fee", "label": "Epoch fee", "fraction": 0.04 } } ] } }

GET /api/v1/pools/{address}

Parameters. limit ≤ 200 · offset (validators page; a multiple of limit)

Returns. one pool: authorities, every fee, the epoch history, a page of validators with pool stake, the validator's total stake, commission and APY, and the delegation changes per epoch. validators.source is "list" (the pool's validator-list account, read for pools above 1 000 SOL) or "mirror" (stake accounts under the pool's withdraw authority, summed per validator; transient = activating + deactivating)

{ "data": { "address": "…", "name": "…", "authorities": { "manager": "…", "staker": "…", "withdrawAuthority": "…", "reserveStake": "…", "validatorList": "…" }, "fees": [ { "key": "epoch_fee", "label": "Epoch fee", "fraction": 0.04, "raw": "4/100" } ],
  "latest": { "epoch": 1049, "tvl": "…", "price": 1.2143, "validatorCount": 413, "top1Share": 0.031, "top10Share": 0.21, "rate30": 0.000166 }, "history": [ … ],
  "validators": { "epoch": 1049, "total": 413, "source": "list", "limit": 50, "offset": 0, "rows": [ { "vote": "…", "name": "…", "active": "…", "transient": "0", "status": 0, "validatorStake": "…", "commissionBps": 500, "apy30": 0.0478 } ] },
  "delegationChanges": [ { "epoch": 1049, "date": "2026-10-04", "added": "…", "removed": "…", "validatorsAdded": 2, "validatorsRemoved": 1, "validators": 413 } ] } }

GET /api/v1/epochs

Parameters. limit ≤ 200

Returns. epochs seen by the indexer, newest first, with slot range, dates and their source, inflation, total stake and the rewards summary (sysvar totals, partitions, measured slot time, epochs per year, cluster reward rate and APY)

{ "data": { "epochs": [ { "epoch": 1048, "firstSlot": "452736000", "lastSlot": "453167999", "slotsInEpoch": "432000", "startedAt": "2026-10-03T05:41:12.000Z", "endedAt": "2026-10-04T13:45:40.000Z", "timeSource": "block", "complete": true, "inflationRate": 0.0362, "totalStake": "…",
  "rewards": { "totalRewards": "78640007412123", "votingRewards": "20870970000000", "stakingRewards": "57769040000000", "partitions": 444, "epochsPerYear": 273.38, "secondsPerSlot": 0.2672, "clusterRewardRate": 0.000178, "clusterApy": 0.0498, "method": "blocks" } } ] } }

GET /api/v1/prices/latest

Returns. the newest stored SOL/USD price and its source (Jupiter live every five minutes; CoinGecko hourly history)

{ "data": { "symbol": "SOL", "usd": 120.67, "at": "2026-10-05T09:38:32.421Z", "source": "jupiter" }, "meta": { … } }

GET /api/v1/search

Parameters. q (required) · limit ≤ 25

Returns. validators by name, vote or identity and pools by name, symbol, address or mint, ten each by default

{ "data": { "validators": [ { "vote": "…", "identity": "…", "name": "Figment", "activeStake": "…", "delinquent": false } ], "pools": [ { "address": "…", "name": "Jito", "symbol": "JitoSOL", "tvl": "…" } ] } }

Something missing? The pages are built from the same query layer; open a page and the data you see is what the API returns.