---
title: "Net buy/sell flow by trader cohort on a Robinhood Chain token (PRO+)"
method: GET
path: "/rhc/tokens/{address}/flow"
tags: ["Robinhood Chain"]
---

# Net buy/sell flow by trader cohort on a Robinhood Chain token (PRO+)

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

## Request

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

Splits a token's trade flow into mutually-exclusive trader cohorts over a window, so you can see *who* is accumulating and *who* is distributing.

**Sign convention: `net_eth = sell − buy`.** Positive means the cohort **distributed** (took ETH out); negative means it **accumulated**. Cohorts are assigned by a priority ladder and each trader lands in exactly one: `kol` → `bot` → `dump_cluster` → `early_buyer` → `unprofiled` → `smart_money` → `retail`.

`smart_money` is derived (win-rate ≥ 0.5 and net positive across all tokens), not a stored label. `unprofiled` is a real answer, not a gap — the trader has not met the reputation matview's thresholds. There is deliberately no `fresh_wallet` cohort: Robinhood Chain has no wallet-level first-seen, so it cannot be computed honestly.

## Path parameters

- `address` string, required

## Query parameters

- `window` '1h' | '6h' | '24h' | '7d'

## Response `200`

OK. `cohorts` is empty when the token had no trades in the window.

- object
  - `chain` 'robinhood'
  - `token_address` string
  - `window` '1h' | '6h' | '24h' | '7d'
  - `cohorts` object[]
    - `cohort` 'kol' | 'bot' | 'dump_cluster' | 'early_buyer' | 'unprofiled' | 'smart_money' | 'retail'
    - `traders` integer
    - `trades` integer
    - `buy_eth` number
    - `sell_eth` number
    - `net_eth` number: sell − buy. Positive = distributed.
  - `totals` object: Sum across cohorts; always equals the parts.
  - `sign_convention` string
  - `attribution` object: Interim attribution disclosure: cohort figures are computed from attributed trades only (`trader_eoa IS NOT NULL`), and trader_eoa was only written reliably from 2026-07-18 — pre-floor history is not reflected. Removed once the trader_eoa backfill lands.
    - `attribution_complete_from` string, date-time
    - `note` string

## Other responses

- `400`: Invalid EVM token address, or window not in {1h,6h,24h,7d}.
- `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-api.md) · [All operations](https://skmtc.dev/madeonsol/apis/madeonsol-api/llms.txt) · [OpenAPI document](https://skmtc.dev/madeonsol/apis/madeonsol-api/revisions/96ce84657f55?raw)
