Data API

GET /v1/tokens/{mint}/holders

Holder list with supply concentration. Paginated.

Endpoint

GET  https://solindex.infinityblocks.io/v1/tokens/{mint}/holders

Authentication

Send your key in the x-api-key header (or ?api-key=). See Authentication.

Path parameters

ParamDescription
mintBase-58 token mint address.

Query parameters

ParamTypeDefaultAllowed / range
limitint501–500 (page size)
offsetint0Rows to skip
pageint1-based page (alternative to offset)

Request

curl -s "https://solindex.infinityblocks.io/v1/tokens/<MINT>/holders?limit=50" \
  -H "x-api-key: <API_KEY>"
const r = await fetch("https://solindex.infinityblocks.io/v1/tokens/<MINT>/holders?limit=50", {
  headers: { "x-api-key": "<API_KEY>" },
});
const { data } = await r.json();

Response

{ "data": {
  "count": 150, "top1Pct": 51.82,
  "snapshotSlot": 423870739, "snapshotTime": 1780165395000, "lagSeconds": 4,
  "lastChangeTime": 1780165395000,
  "indexHead": { "time": 1784188941000, "slot": 433233827, "lagSeconds": 5 },
  "degraded": false,
  "source": "geyser-firehose-from-birth", "isComplete": true, "coverage": "complete",
  "holders": [ { "wallet": "…", "balance": 30511727.23, "pct": 51.824 }, … ] },
  "page": { "limit": 50, "offset": 0, "total": 150,
    "returned": 50, "hasMore": true, "nextOffset": 50 } }
Paginated by limit + offset (or 1-based page); page.total equals the holder count. count and top1Pct are whole-set aggregates — they don't change as you page. Balances are aggregated by owner wallet. Burn and system sinks (the SPL incinerator and the system/null address) are excluded — they hold supply but aren't real holders, so counting them would skew count and top1Pct (this matches the common holder definition). Holder balances come from a live token-account change stream, so freshness is per-wallet, not one as-of snapshot: snapshotSlot/snapshotTime track the most-recently-updated wallet, and lagSeconds is how stale that is. source reports how the owner set was built — helius-seed+geyser-stream, geyser-firehose-from-birth, geyser-stream, helius-seed, or none. isComplete/coverage say whether the holder set is canonical (complete — fully seeded, or a LaunchLab token tracked live since launch) or a lower-bound (live-firehose-only on a pre-existing token, so small/inactive holders may be undercounted).

Reading freshness correctly. lastChangeTime (alias of snapshotTime) is when this mint’s holder set last changed on-chain — it legitimately ages on quiet tokens and is not index staleness. The index-health signal is indexHead: the live holder stream’s global watermark (time, slot, and its lag vs now). SLA: indexHead.lagSeconds is single-digit seconds in normal operation; degraded: true is returned whenever the stream watermark lags more than 15 minutes — treat responses as stale-risk only then. So: degraded=false + old lastChangeTime = “no balance changes since then”, current and authoritative. snapshotSlot=0 means the freshest row for this mint came from the external full-enumeration seed (seed rows carry no slot); the first live on-chain change writes a real slot. A reconcile sweep additionally re-verifies top holders of any mint whose trades outpace its holder rows (heals stream-disconnect windows within ~10 minutes).

Try it

Run GET /v1/tokens/{mint}/holderslive · GET

Your key is stored only in this browser (localStorage).