---
title: "Holder set and concentration for a Robinhood Chain token (PRO+)"
method: GET
path: "/rhc/tokens/{address}/holders"
tags: ["Robinhood Chain"]
---

# Holder set and concentration for a Robinhood Chain token (PRO+)

`GET /rhc/tokens/{address}/holders`

## Request

- Base URL: `https://madeonsol.com/api/v1`
- URL: `https://madeonsol.com/api/v1/rhc/tokens/{address}/holders`
- Auth: HTTP bearer

Holder balances and concentration metrics. **Not trade-derived** — balances are folded from ERC-20 `Transfer` logs, which our node retains in full, so they are exact rather than estimated. The Solana counterpart is `GET /tokens/{mint}/holders` — a live on-chain census via mint-scoped getProgramAccounts (shipped 2026-08-16).

**Every token carries a reconciliation.** `verified` is true only when the reconstructed `sum(balance)` equals on-chain `totalSupply()` at a pinned block. A token that fails, or has not been swept yet, returns `verified: false` with a stated `unverified_reason` — never as though it were exact.

**Concentration excludes pools and burn addresses.** The largest holder of a token is normally its own liquidity pool, so counting it would make `top1_share` meaningless; pools and burns are reported separately as `pool_held_pct` / `burned_pct` and excluded from the circulating denominator. Balances are raw uint256 and are returned as **strings** to preserve precision. Holder addresses may be ERC-4337 smart accounts, so `holder_count` is not a headcount of people.

**Holder growth (2026-08-17).** `holder_growth.{1h,24h,7d}` reports `entered` (first Transfer at-or-after the window's `cutoff_block`), `entered_still_holding`, `exited` (pre-existing holders whose last movement in the window left them at zero) and `net` ≈ Δ holder_count — possible because the fold keeps first_seen_block/last_block and retains zero-balance rows. The Solana census has no history and cannot answer this.

## Path parameters

- `address` string, required

## Query parameters

- `limit` integer
- `offset` integer
- `after` string
- `include_wallet_flags` boolean

## Response `200`

OK. Check `verified` before relying on the numbers.

- object
  - `chain` 'robinhood'
  - `token_address` string
  - `verified` boolean: True only when reconstructed supply matches on-chain totalSupply().
  - `unverified_reason` string, nullable
  - `share_basis` object: Plain-language denominator of each per-holder ratio (share, share_of_supply, share_of_circulating) and the burn addresses.
  - `holders` object[]
    - `holder` string
    - `balance` string: Raw uint256 as a decimal STRING — not a number.
    - `share` number, nullable: balance / non-burned supply (liquidity pools INCLUDED), [0,1]. null on burn rows (is_burn). Not the concentration basis: use share_of_circulating for that.
    - `share_of_supply` number, nullable: balance / total folded supply (pools and burns included), [0,1]. Defined for every row, including burn and pool rows. null = unknown.
    - `share_of_circulating` number, nullable: balance / circulating supply (pools and burns excluded), [0,1]: the same basis as concentration.top1_share. null on pool and burn rows, or when unknown.
    - `last_block` integer, nullable
    - `is_pool` boolean
    - `is_burn` boolean
    - `is_deployer` boolean
    - `wallet_flags` object, nullable: Only with include_wallet_flags=true; null for pools/burns, invalid addresses or unavailable sources. RHC has no sniper or wallet-level bundler classifier: those are always null.
      - `is_sniper` boolean, nullable
      - `is_bundler` boolean, nullable
      - `is_kol` boolean
      - `is_alpha_tracked` boolean
      - `likely_bot` boolean, nullable
      - `is_dumper` boolean
      - `dump_cluster_as_of` string, nullable
      - `label_coverage` object: Per label: evaluated=false means no sufficient evidence (not a verified negative).
  - `count` integer
  - `wallet_flags_meta` object: Only with include_wallet_flags=true.
    - `status` 'available' | 'partial' | 'unavailable'
    - `rule_version` string
    - `note` string
  - `limit` integer
  - `offset` integer
  - `has_more` boolean
  - `next_after` string, nullable: Keyset cursor for the next page — pass it unchanged as `after`. null on the last page (or when the last row has no balance). Preferred over `offset` for full walks: offset is capped at 10,000, `after` is not.
  - `after` string, nullable: Echo of the `after` cursor this page was read from (null on the first page).
  - `concentration` object, nullable
    - `holder_count` integer, nullable
    - `circulating` string, nullable
    - `top1_share` number, nullable
    - `top10_share` number, nullable
    - `top50_share` number, nullable
    - `hhi` number, nullable: Herfindahl index over circulating shares.
    - `pool_held_pct` number, nullable
    - `burned_pct` number, nullable
    - `deployer_pct` number, nullable
  - `holder_growth` object, nullable: Entered / exited holders per window, read from first_seen_block + last_block of the Transfer-log fold (mig 325). null only if the growth read failed; a single window is null when the chain had no ingested trades in it (cutoff unresolvable).
    - `1h` RhcHolderGrowthWindow, nullable: One holder-growth window on /rhc/tokens/{address}/holders. Pools and burn addresses are excluded from every count.
      - `cutoff_block` integer, nullable: Lowest block observed at-or-after now()−window (resolved from our trade ingest, ~10 blocks/s).
      - `entered` integer, nullable: Addresses whose first Transfer of this token landed at-or-after cutoff_block (any current balance).
      - `entered_still_holding` integer, nullable: entered ∩ balance > 0.
      - `exited` integer, nullable: Pre-existing holders whose last Transfer in the window left them at zero.
      - `net` integer, nullable: entered_still_holding − exited ≈ change in holder_count over the window.
    - `24h` RhcHolderGrowthWindow, nullable: One holder-growth window on /rhc/tokens/{address}/holders. Pools and burn addresses are excluded from every count.
      - `cutoff_block` integer, nullable: Lowest block observed at-or-after now()−window (resolved from our trade ingest, ~10 blocks/s).
      - `entered` integer, nullable: Addresses whose first Transfer of this token landed at-or-after cutoff_block (any current balance).
      - `entered_still_holding` integer, nullable: entered ∩ balance > 0.
      - `exited` integer, nullable: Pre-existing holders whose last Transfer in the window left them at zero.
      - `net` integer, nullable: entered_still_holding − exited ≈ change in holder_count over the window.
    - `7d` RhcHolderGrowthWindow, nullable: One holder-growth window on /rhc/tokens/{address}/holders. Pools and burn addresses are excluded from every count.
      - `cutoff_block` integer, nullable: Lowest block observed at-or-after now()−window (resolved from our trade ingest, ~10 blocks/s).
      - `entered` integer, nullable: Addresses whose first Transfer of this token landed at-or-after cutoff_block (any current balance).
      - `entered_still_holding` integer, nullable: entered ∩ balance > 0.
      - `exited` integer, nullable: Pre-existing holders whose last Transfer in the window left them at zero.
      - `net` integer, nullable: entered_still_holding − exited ≈ change in holder_count over the window.
    - `note` string
  - `history_coverage` object: Per-token history continuity of the Transfer-log fold (COV-24). Present only when the coverage read is enabled. `state`: `verified_interval` (fold proven continuous from the token's birth and reconciled), `recovery_pending` (a repair is rebuilding it), `partial_history` (folded only while tracked, a re-entry gap, failed/non-standard token, or the coverage read failed — `reason` says which). `recon_ok` alone is NOT proof of correct individual balances.
    - `state` 'verified_interval' | 'recovery_pending' | 'partial_history'
    - `history` string
    - `reason` string, nullable
    - `fold_from_block` integer, nullable
    - `compared_at_block` integer, nullable
    - `verified_at_block` integer, nullable
  - `reconciliation` object, nullable: recon_supply vs chain_supply at recon_block.
  - `source` object: Method, sweep cursor and completeness.

## Other responses

- `400`: Invalid EVM token address.
- `401`: Missing or invalid API key, or an expired free-tier key. Authentication-stage error: no `X-RateLimit-*` headers, no `_rid`.
- `403`: PRO tier required.
- `429`: Too many requests. Every 429 carries `Retry-After`. A quota 429 (`rate_limit_exceeded`, with `X-RateLimit-*`), a heavy-query concurrency 429 (`error_kind` `concurrency`/`capacity`), or the per-IP authentication-failure block (30 failed auths/min; plain `error` + `retry_after_seconds`, no `X-RateLimit-*`).
- `500`: Unexpected server error from the route (`Internal server error`, with `_rid`). Safe to retry with backoff. A failed API-key lookup is a 503 `auth_backend_unavailable`, never a 500.
- `503`: Temporarily unavailable — a Postgres statement timeout while the dataset is under load or maintenance (`statement_timeout`, with `X-RateLimit-*` and `_rid`), or the API-key lookup itself unavailable (`auth_backend_unavailable`, authentication stage: no `X-RateLimit-*`, no `_rid`, not counted as a failed authentication). Always carries `Retry-After`; honour it.

---

[API](https://skmtc.dev/madeonsol/apis/madeonsol-robinhood-chain-api.md) · [All operations](https://skmtc.dev/madeonsol/apis/madeonsol-robinhood-chain-api/llms.txt) · [OpenAPI document](https://skmtc.dev/madeonsol/apis/madeonsol-robinhood-chain-api/revisions/9ea9a35ee2bf?raw)
