openapi: 3.2.0 info: title: MadeOnSol Robinhood Chain API version: 1.20.0 description: Real-time Solana & Robinhood Chain trading intelligence — KOL wallet trades, deployer reputation, token buyer-quality scoring, wallet tracking, and copy-trade signals across both chains (Robinhood Chain paths under `/rhc/*`). contact: name: MadeOnSol url: https://madeonsol.com/contact license: name: Proprietary url: https://madeonsol.com/terms servers: - url: https://madeonsol.com/api/v1 description: Production security: - BearerAuth: [] tags: - name: Robinhood Chain description: Robinhood Chain (chain id 4663) coverage — same intel, EVM-native contracts (0x addresses, eth_amount, tx_hash). Bundled into existing tiers at no extra cost. paths: /rhc/kol/feed: get: tags: - Robinhood Chain summary: KOL trade feed on Robinhood Chain (BASIC+; 5-min delay on free) description: 'Every buy/sell from tracked Solana KOLs'' verified EVM wallets on Robinhood Chain (chain id 4663), attributed to the effective trading account from our self-hosted node (tx.from normally, or the ERC-4337 userOp sender when bundled — never the bundler) — DEX swaps and launchpad curve snipes, within seconds of execution on PRO and up (the free tier serves this feed on a 5-minute delay). The KOL→EVM mapping is recovered by tracing each KOL''s Solana→EVM bridge deposits (deBridge / Relay / Mayan / Wormhole) — a dataset unique to MadeOnSol. Every row is enriched with the token''s current MC/liquidity/peak, the deployer''s reputation tier, and `mc_multiple_since_trade` (current MC ÷ MC when the KOL bought — ''did the call run''). Tier: **BASIC** (any valid key).' parameters: - $ref: '#/components/parameters/Limit' - name: before in: query schema: type: string format: date-time description: 'Cursor: return trades strictly older than this ISO timestamp. Pass `next_before` from the previous response to page backwards.' - name: cursor in: query schema: type: string maxLength: 200 description: 'PREFERRED pagination (audit F09 follow-up): the `next_cursor` from a previous page — an opaque strict (traded_at, id) keyset, so paging never repeats or skips rows that share a timestamp and progresses with limit=1 through runs of identical timestamps. Malformed or tampered → 400. Cannot be combined with `before=` (400); `before=` stays supported as the legacy bound.' - name: action in: query schema: type: string enum: - buy - sell description: Only buys or only sells. - name: kol in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Filter to a single KOL by their EVM wallet address (0x, 40 hex). - name: min_eth in: query schema: type: number minimum: 0 description: Minimum trade size in ETH. - name: exclude_sells in: query schema: type: string enum: - 'true' - 'false' - '1' - '0' description: Convenience alias for `action=buy` — drops sells from the feed. Ignored if `action` is set explicitly. - name: min_mc_usd in: query schema: type: number minimum: 0 description: Only trades where the token's market cap at trade time was at least this (USD). - name: max_mc_usd in: query schema: type: number minimum: 0 description: Only trades where the token's market cap at trade time was at most this (USD). Combine with `min_mc_usd` for a band; `min_mc_usd` must be <= `max_mc_usd` or the request 400s. - name: token_age_max_min in: query schema: type: integer minimum: 1 maximum: 43200 description: Only trades on tokens first seen at most this many minutes ago — the 'fresh launches KOLs are buying' filter. Tokens with unknown first-seen time are excluded. - name: min_kol_winrate in: query schema: type: number minimum: 0 maximum: 1 description: 'Only trades by KOLs whose 7-day win rate (mv_rhc_kol_scores.winrate_7d, CLOSED positions only — sold ≥ 90 % of bought) is at least this (0–1). KOLs with no closed positions have a NULL win rate and are dropped, so `min_kol_winrate=0` is NOT a no-op: it means "scored".' - name: strategy in: query schema: type: string enum: - scalper - day_trader - swing - inactive - unscored description: Only trades by KOLs in this hold-time bucket (mv_rhc_kol_scores.strategy). An RHC-specific bucket, not Solana's auto_strategy_tag. responses: '200': description: '`chain` echoes `robinhood`; `next_before` is the pagination cursor; `data_age_seconds` is the age of the newest row.' content: application/json: schema: type: object properties: chain: type: string enum: - robinhood trades: type: array items: type: object properties: evm_address: type: string description: The KOL's Robinhood-Chain wallet (0x). kol_name: type: string nullable: true kol_twitter: type: string nullable: true token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true launchpad: type: string nullable: true description: pons | flap | clanker | hood.fun | virtuals | null. is_graduated: type: boolean nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer description: Reputation tier of the token's deployer. token_age_minutes: type: integer nullable: true description: Token age at request time (first-seen → now). action: type: string enum: - buy - sell eth_amount: type: number nullable: true description: Trade size in ETH. token_amount: type: number nullable: true price_usd_at_trade: type: number nullable: true market_cap_usd_at_trade: type: number nullable: true description: Token market cap when the KOL traded. current_mc_usd: type: number nullable: true description: Token market cap now. peak_mc_usd: type: number nullable: true description: All-time-high market cap observed since ingestion. liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: How liquidity_usd was derived. uniswap-v4 has no per-pool balances, so its figure is virtual reserves clamped to the PoolManager's total holdings — a provable CEILING, not measured per-pool TVL. All other venues are measured from real balances. risk: $ref: '#/components/schemas/RhcTokenRiskSummary' mc_multiple_since_trade: type: number nullable: true description: current_mc_usd ÷ market_cap_usd_at_trade — how far the token ran after the KOL's trade. dex: type: string description: uniswap-v2/v3/v4 or the launchpad name for curve trades. pool: type: string nullable: true tx_hash: type: string block_number: type: integer traded_at: type: string format: date-time kol_score: type: object nullable: true description: The KOL's row in mv_rhc_kol_scores. null = no row yet (too few closed positions), never "not looked up". properties: winrate_7d: type: number nullable: true description: 0–1, CLOSED positions only (sold ≥ 90 % of bought). winrate_30d: type: number nullable: true strategy: type: string nullable: true description: 'Hold-time bucket: scalper | day_trader | swing | inactive | unscored.' closed_positions_30d: type: integer nullable: true count: type: integer filtered_by: type: object description: Echo of the KOL-score filters (null = not applied). properties: min_kol_winrate: type: number nullable: true strategy: type: string nullable: true matched_kols: type: integer nullable: true description: KOLs matching min_kol_winrate/strategy; null when neither filter is set. data_age_seconds: type: integer nullable: true next_before: type: string format: date-time nullable: true next_cursor: type: string nullable: true description: Opaque keyset cursor for the next (older) page — pass as `cursor=`. PREFERRED over next_before, which is a strict timestamp bound that skips same-timestamp siblings of the boundary row. has_more: type: boolean description: false only when the feed is exhausted (not merely when the page is short). scan: type: object description: 'Present when a filter had to be applied after the candidate fetch (audit F09): has_more is then false only when the candidates ran out, and scan_truncated=true means the per-request scan budget ran out first — more matches MAY exist past next_cursor.' properties: post_filtered: type: boolean scanned: type: integer description: Candidate rows examined scan_truncated: type: boolean description: The per-request scan budget ran out before `limit` matches — more matches MAY exist past the cursor/offset scan_budget: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcKolFeed x-operation-id-source: derived /rhc/kol/leaderboard: get: tags: - Robinhood Chain summary: KOL activity leaderboard on Robinhood Chain (BASIC+) description: 'KOLs on Robinhood Chain ranked by trade count, then net ETH flow, over the chosen window. Tier: **BASIC**. (Net ETH is buy−sell flow, not realized PnL — cost-basis PnL is a planned addition.)' parameters: - name: period in: query schema: type: string enum: - 24h - 7d - 30d default: 24h description: Rolling window. - $ref: '#/components/parameters/Limit' responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood period: type: string enum: - 24h - 7d - 30d leaderboard: type: array items: type: object properties: kol_name: type: string nullable: true kol_twitter: type: string nullable: true trades: type: integer buys: type: integer sells: type: integer buy_eth: type: number description: Total ETH bought in the window. sell_eth: type: number description: Total ETH sold in the window. net_eth: type: number description: buy_eth − sell_eth (flow, not realized PnL). tokens_traded: type: integer description: Distinct tokens traded in the window. last_trade_at: type: string format: date-time count: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcKolLeaderboard x-operation-id-source: derived /rhc/kol/hot-tokens: get: tags: - Robinhood Chain summary: Consensus tokens — bought by 2+ KOLs on Robinhood Chain (BASIC+) description: 'Robinhood Chain tokens bought by **2 or more distinct tracked KOLs** inside the window (a consensus signal), ranked by KOL-buyer count then buy volume. Each row is enriched with launchpad, deployer reputation tier, graduation status and current market cap. Tier: **BASIC**.' parameters: - name: window in: query schema: type: string enum: - 5m - 15m - 1h - 6h - 24h default: 1h description: Rolling consensus window. responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood window: type: string enum: - 5m - 15m - 1h - 6h - 24h tokens: type: array items: type: object properties: token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true launchpad: type: string nullable: true description: noxa | flap | pons | hood.fun | clanker | null. is_graduated: type: boolean nullable: true deployer_tier: type: string nullable: true description: elite | good | neutral | spammer | null. kols_buying: type: integer description: Distinct KOL buyers in the window (>= 2). buys: type: integer sells: type: integer buy_eth: type: number net_eth: type: number description: buy_eth − sell_eth. market_cap_usd: type: number nullable: true description: Current market cap. last_trade_at: type: string format: date-time count: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcKolHotTokens x-operation-id-source: derived /rhc/tokens/hot: get: tags: - Robinhood Chain summary: Alias of /rhc/kol/hot-tokens (BASIC+) description: Same handler as `/rhc/kol/hot-tokens` — tokens bought by 2+ tracked KOLs in the window. Added 2026-09-05 because customers guess this URL; `window` passes through. Prefer the canonical path in new code. parameters: - name: window in: query schema: type: string enum: - 5m - 15m - 1h - 6h - 24h default: 1h responses: '200': description: Identical to /rhc/kol/hot-tokens. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcTokensHot x-operation-id-source: derived /rhc/tokens/trending: get: tags: - Robinhood Chain summary: Alias of /rhc/kol/hot-tokens (BASIC+) description: Same handler as `/rhc/kol/hot-tokens` — tokens bought by 2+ tracked KOLs in the window. Added 2026-09-05 because customers guess this URL; `window` passes through. Prefer the canonical path in new code. parameters: - name: window in: query schema: type: string enum: - 5m - 15m - 1h - 6h - 24h default: 1h responses: '200': description: Identical to /rhc/kol/hot-tokens. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcTokensTrending x-operation-id-source: derived /rhc/kol/coordination: get: tags: - Robinhood Chain summary: KOL coordination / consensus clustering on Robinhood Chain (BASIC+) description: 'Tokens being bought by **multiple distinct tracked KOLs** inside a time window on Robinhood Chain (chain id 4663) — the coordination / consensus signal. Computed read-time from `rhc_kol_trades`: window buys grouped by token, distinct KOL wallets counted, then enriched with in-window sells (net-flow / exit math), token metadata, current price/MC/liquidity and the deployer''s reputation tier. EVM-native fields (`eth_amount`, `evm_address`, 0x). Ranked by distinct KOL count, then buy ETH, then recency. Tier: **BASIC** (any valid key).' parameters: - name: period in: query schema: type: string enum: - 1h - 6h - 24h - 7d default: 24h description: 'Rolling window (alias: `window`). Filters on `traded_at`.' - name: min_kols in: query schema: type: integer minimum: 2 maximum: 50 default: 2 description: Minimum distinct KOL buyers for a token to qualify. - name: limit in: query schema: type: integer minimum: 1 maximum: 50 default: 20 - name: min_mc_usd in: query schema: type: number minimum: 0 maximum: 1000000000000 description: Filter on market cap at the first KOL buy (USD). Tokens with unknown MC at first buy are excluded when a band is set. - name: max_mc_usd in: query schema: type: number minimum: 0 maximum: 1000000000000 description: Upper bound on MC at first KOL buy (USD). Must be ≥ min_mc_usd. responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood coordination: type: array items: type: object properties: token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer token_age_minutes: type: integer nullable: true kol_count: type: integer description: Distinct KOL buyers in the window (≥ min_kols). total_buys: type: integer buy_eth: type: number description: Total ETH bought by KOLs in the window. sell_eth: type: number description: Total ETH sold by those KOLs in the window. net_eth: type: number description: buy_eth − sell_eth. signal: type: string enum: - accumulating - distributing description: accumulating when net_eth ≥ 0, else distributing. exited_count: type: integer description: KOLs whose in-window sells exceed their buys. holders_count: type: integer description: kol_count − exited_count. first_buy_at: type: string format: date-time last_buy_at: type: string format: date-time time_to_consensus_sec: type: integer description: Seconds between the first and last KOL buy. market_cap_usd_at_first_buy: type: number nullable: true current_mc_usd: type: number nullable: true peak_mc_usd: type: number nullable: true liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: How liquidity_usd was derived. v4_virtual_ceiling = uniswap-v4 virtual reserves clamped to the PoolManager's total holdings — a provable ceiling, not measured per-pool TVL. kols: type: array items: type: object properties: evm_address: type: string description: The KOL's Robinhood-Chain wallet (0x). name: type: string nullable: true twitter_url: type: string nullable: true buy_eth: type: number sell_eth: type: number exited: type: boolean description: sell_eth > buy_eth for this KOL. count: type: integer period: type: string enum: - 1h - 6h - 24h - 7d min_kols: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters (e.g. min_mc_usd > max_mc_usd). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcKolCoordination x-operation-id-source: derived /rhc/kol/first-touches: get: tags: - Robinhood Chain summary: Earliest KOL entry per token on Robinhood Chain (BASIC+) description: 'The **first time any tracked KOL bought** each token on Robinhood Chain — an early-entry / discovery signal. Computed read-time from `rhc_kol_trades` (a DISTINCT-ON per token yielding the global earliest KOL buy), enriched with token metadata and current/peak MC. EVM-native fields (`eth_amount`, `evm_address`, `tx_hash`, 0x). Tier: **BASIC** — but below the API-access tiers (PRO/ULTRA/BUSINESS) `limit` is clamped to 20, and the first KOL''s `evm_address` is revealed only to **ULTRA/BUSINESS**.' parameters: - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 50 description: Clamped to 20 for keys below the API-access tiers. - name: since in: query schema: type: string format: date-time description: Only first-touches at/after this ISO8601 timestamp. - name: before in: query schema: type: string format: date-time description: 'Cursor: only first-touches before this ISO8601 timestamp. Pass `next_before` to page.' - name: cursor in: query schema: type: string maxLength: 200 description: 'PREFERRED pagination (audit F09 follow-up): the `next_cursor` from a previous page — an opaque strict (first_buy_at, id) keyset, so paging never repeats or skips rows that share a timestamp and progresses with limit=1 through runs of identical timestamps. Malformed or tampered → 400. Cannot be combined with `before=` (400); `before=` stays supported as the legacy bound.' - name: min_eth in: query schema: type: number minimum: 0 maximum: 100000 description: 'Minimum ETH size of the first KOL buy (alias: `min_sol`).' - name: token_age_max_min in: query schema: type: integer minimum: 1 maximum: 43200 description: Only tokens younger than N minutes at first touch. - name: launchpad in: query schema: type: string pattern: ^[a-zA-Z0-9._-]{1,32}$ description: Filter to one launchpad. - name: min_mc_usd in: query schema: type: number minimum: 0 maximum: 1000000000000 description: Minimum MC at first buy (USD). - name: max_mc_usd in: query schema: type: number minimum: 0 maximum: 1000000000000 description: 'Maximum MC at first buy (USD; alias: `mc_max`). Must be ≥ min_mc_usd.' responses: '200': description: '`next_before` is the pagination cursor (oldest first_buy_at on the page); `data_age_seconds` is the age of the newest event.' content: application/json: schema: type: object properties: chain: type: string enum: - robinhood events: type: array items: type: object properties: token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true first_buy_at: type: string format: date-time eth_amount: type: number nullable: true description: Size of the first KOL buy in ETH. token_amount: type: number nullable: true tx_hash: type: string token_age_minutes: type: integer nullable: true description: Token age at first touch. market_cap_usd_at_first_buy: type: number nullable: true price_usd_at_first_buy: type: number nullable: true current_mc_usd: type: number nullable: true peak_mc_usd: type: number nullable: true first_kol: type: object properties: evm_address: type: string description: The KOL's Robinhood-Chain wallet (0x). Present only for ULTRA/BUSINESS keys. name: type: string nullable: true twitter_url: type: string nullable: true count: type: integer next_before: type: string format: date-time nullable: true next_cursor: type: string nullable: true description: 'Opaque keyset cursor for the next (older) page — pass as `cursor=`. PREFERRED over next_before, which is a strict timestamp bound that skips same-timestamp siblings of the boundary row. null on a server that predates the rhc_kol_first_touches_page migration (legacy path: no id tiebreak).' has_more: type: boolean nullable: true description: Exact (limit+1 probe). null when the server is on the legacy path and cannot tell — page on next_before until an empty page. data_age_seconds: type: integer nullable: true headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters (e.g. min_mc_usd > max_mc_usd). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcKolFirstTouches x-operation-id-source: derived /rhc/kol/{wallet}: get: tags: - Robinhood Chain summary: Single KOL profile on Robinhood Chain (BASIC+) description: 'Aggregate stats over one KOL''s last 200 RHC trades plus their 50 most recent trades. Tier: **BASIC**.' parameters: - name: wallet in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: KOL EVM wallet address (0x, 40 hex). responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood evm_address: type: string kol_name: type: string nullable: true kol_twitter: type: string nullable: true stats: type: object properties: trades: type: integer buys: type: integer sells: type: integer buy_eth: type: number sell_eth: type: number net_eth: type: number tokens_traded: type: integer window: type: string example: last 200 trades trades: type: array description: 50 most recent trades (token, action, eth_amount, price/MC at trade, dex, tx_hash, traded_at). Each row carries `liquidity_basis` (`v4_virtual_ceiling` | `measured`) — uniswap-v4 liquidity_usd is a virtual-reserve ceiling, not measured per-pool TVL. items: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: No RHC activity found for this address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcKolByWallet x-operation-id-source: derived /rhc/trades: get: tags: - Robinhood Chain summary: Robinhood Chain DEX trade tape (PRO+) description: 'Every Uniswap v2/v3/v4 swap on chain 4663 from our self-hosted node, within seconds of execution. Each row carries the **real trader wallet** (`trader_eoa` — the userOp sender on ERC-4337 transactions, never the router or the bundler), gas/ordering for MEV analysis, pool state, and flags for whether the trader is a tracked KOL or a known deployer. Cursor via `next_before`. Tier: **PRO+**. **Where the rows come from** (*added 2026-08-29*): closed months older than the newest three move from Postgres to a Parquet archive; pages are split at `history.postgres_from` (ISO) — rows at/after it from Postgres, older rows from the archive reader, same ordering and `before` cursor. `history.archive_used`, `archive_months`, `archive_available` (`null` = not configured) and `truncated` (older history requested but the archive did not answer — retry rather than treating `has_more:false` as the end) mirror `/tokens/{mint}/trades`. Header `X-Read-Source`: `core`, `core+archive` or `archive`.' parameters: - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 - name: token in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Filter to one token address. - name: dex in: query schema: type: string enum: - uniswap-v2 - uniswap-v3 - uniswap-v4 description: Filter by DEX version. - name: action in: query schema: type: string enum: - buy - sell - name: min_eth in: query schema: type: number minimum: 0 description: Minimum trade size in ETH. - name: before in: query schema: type: string description: Opaque cursor from next_before; a bare ISO block_time is also accepted for backward compatibility (loses intra-second position). responses: '200': description: OK. `next_before` is the opaque pagination cursor — pass it back as `before` to page losslessly; `has_more` says whether another page exists. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood trades: type: array items: type: object properties: block_number: type: integer block_time: type: string format: date-time tx_hash: type: string log_index: type: integer dex: type: string pool: type: string trader: type: string nullable: true description: Swap-log recipient — the ROUTER for aggregated swaps. Use trader_eoa for wallet analytics. trader_eoa: type: string nullable: true description: Authoritative trader wallet. Normally tx.from; on ERC-4337 transactions this is the userOp sender (the account that actually traded) and tx.from — the bundler — is not returned. router: type: string nullable: true description: Router/aggregator contract (tx.to). token_address: type: string nullable: true action: type: string enum: - buy - sell nullable: true eth_amount: type: number nullable: true price_native: type: number nullable: true price_usd: type: number nullable: true mc_usd_at_trade: type: number nullable: true gas_price: type: number nullable: true description: Effective gas price, gwei. tx_index: type: integer nullable: true description: Transaction position within the block (ordering / sandwich detection). method_selector: type: string nullable: true description: 4-byte calldata selector. liquidity: type: number nullable: true description: v3/v4 in-range liquidity at the trade. launchpad: type: string nullable: true is_kol: type: boolean description: True if trader_eoa is a tracked KOL wallet. kol_name: type: string nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer description: Set if trader_eoa is a known deployer. count: type: integer has_more: type: boolean description: True when another page exists beyond this one. next_before: type: string nullable: true description: Opaque (block_time, id) keyset cursor for the next page; null when has_more is false. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTrades x-operation-id-source: derived /rhc/equities: get: tags: - Robinhood Chain summary: Tokenized stocks & ETFs on Robinhood Chain (BASIC+) description: 'Every official Robinhood tokenized equity (stocks + ETFs, e.g. NVDA, SPY, AAPL) with live price / MC / liquidity and 24h trades / ETH volume / buyer-seller split. **Identity is the issuer BEACON, not the name**: a token is listed only if its contract is an EIP-1967 beacon proxy on Robinhood''s issuer beacon 0xe10b6f6b…151b00, read from our own node (scripts/rhc-classify-tokens.mjs, every 10 min). The day this shipped there were 20 fake ''GameStop • Robinhood Token'' contracts and 8 fake NVDAs with the exact official suffix — none appear here. Tier: **BASIC** (discovery surface; per-token drill-downs keep their own gates). 24h stats cached 60 s.' parameters: - name: sort in: query schema: type: string enum: - volume - trades - market_cap - last_trade - symbol default: volume - name: limit in: query schema: type: integer minimum: 1 maximum: 300 default: 100 - name: symbol in: query schema: type: string description: Exact ticker, case-insensitive (NVDA). - name: q in: query schema: type: string description: Substring of symbol or name. responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood equities: type: array items: type: object properties: token_address: type: string symbol: type: string nullable: true name: type: string nullable: true description: Underlying name with the '• Robinhood Token' suffix stripped (display only). onchain_name: type: string nullable: true asset_class: type: string enum: - equity verified: type: boolean description: Always true here — beacon-verified by construction. issuer_beacon: type: string nullable: true decimals: type: integer nullable: true listed_at: type: string format: date-time nullable: true price_usd: type: number nullable: true price_native: type: number nullable: true market_cap_usd: type: number nullable: true fdv_usd: type: number nullable: true peak_mc_usd: type: number nullable: true liquidity_usd: type: number nullable: true liquidity_basis: type: string nullable: true primary_dex: type: string nullable: true primary_pool: type: string nullable: true last_trade_time: type: string format: date-time nullable: true trades_24h: type: integer volume_eth_24h: type: number buys_24h: type: integer sells_24h: type: integer buyers_24h: type: integer sellers_24h: type: integer count: type: integer total_equities: type: integer sort: type: string identity: type: object description: method:'beacon', issuer_beacon, note. stats_window: type: string enum: - 24h stats_as_of: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters (code invalid_query). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcEquities x-operation-id-source: derived /rhc/tokens/new: get: tags: - Robinhood Chain summary: Alias of /rhc/tokens?sort=newest (PRO+) description: 'The launch feed: newest tokens first by first_seen_at. Same handler as /rhc/tokens with sort pinned; since=, limit, asset_class, launchpad and min_* pass through. Tier: **PRO+** (inherits the /rhc/tokens gate).' parameters: - name: since in: query schema: type: string format: date-time - name: limit in: query schema: type: integer - name: asset_class in: query schema: type: string enum: - equity - other responses: '200': description: Identical to /rhc/tokens?sort=newest. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood tokens: type: array items: type: object properties: token_address: type: string symbol: type: string nullable: true name: type: string nullable: true asset_class: type: string nullable: true enum: - equity description: '''equity'' = beacon-verified Robinhood tokenized stock/ETF; null = everything else.' first_seen_at: type: string format: date-time nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true deployer_address: type: string nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer price_usd: type: number nullable: true market_cap_usd: type: number nullable: true fdv_usd: type: number nullable: true peak_mc_usd: type: number nullable: true peak_mc_at: type: string format: date-time nullable: true drawdown_from_peak_pct: type: integer nullable: true description: Percent below all-time-high MC. liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured primary_dex: type: string nullable: true primary_pool: type: string nullable: true last_trade_time: type: string format: date-time nullable: true count: type: integer sort: type: string enum: - newest since: type: string format: date-time nullable: true next_since: type: string format: date-time nullable: true description: Feed back as since= to poll for launches newer than this page. note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensNew x-operation-id-source: derived /rhc/tokens/recent: get: tags: - Robinhood Chain summary: Alias of /rhc/tokens?sort=newest (PRO+) description: Same as /rhc/tokens/new. parameters: - name: since in: query schema: type: string format: date-time - name: limit in: query schema: type: integer responses: '200': description: Identical to /rhc/tokens?sort=newest. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood tokens: type: array items: type: object properties: token_address: type: string symbol: type: string nullable: true name: type: string nullable: true asset_class: type: string nullable: true enum: - equity description: '''equity'' = beacon-verified Robinhood tokenized stock/ETF; null = everything else.' first_seen_at: type: string format: date-time nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true deployer_address: type: string nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer price_usd: type: number nullable: true market_cap_usd: type: number nullable: true fdv_usd: type: number nullable: true peak_mc_usd: type: number nullable: true peak_mc_at: type: string format: date-time nullable: true drawdown_from_peak_pct: type: integer nullable: true description: Percent below all-time-high MC. liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured primary_dex: type: string nullable: true primary_pool: type: string nullable: true last_trade_time: type: string format: date-time nullable: true count: type: integer sort: type: string enum: - newest since: type: string format: date-time nullable: true next_since: type: string format: date-time nullable: true description: Feed back as since= to poll for launches newer than this page. note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensRecent x-operation-id-source: derived /rhc/tokens: get: tags: - Robinhood Chain summary: Robinhood Chain token discovery (PRO+) description: 'Live-priced Robinhood Chain tokens with market cap, liquidity, peak MC + drawdown, launchpad, and deployer reputation tier. Sortable and filterable. Filters the candidate query cannot express are served by a bounded scan (`scan` block) — a short or empty page never implies exhaustion unless has_more is false. Tier: **PRO+**.' parameters: - $ref: '#/components/parameters/Limit' - name: sort in: query schema: type: string enum: - last_trade - market_cap - liquidity - peak_mc - newest - oldest default: last_trade description: 'Ordering (all descending unless noted): most recent trade, market cap, current liquidity, all-time-high MC, newest (first_seen_at DESC — the launch feed; unpriced tokens list with null price fields; response adds next_since), or oldest (first_seen_at ASC — a resumable backfill walk through the full historical token set; response adds next_after + has_more).' - name: since in: query schema: type: string format: date-time description: 'Only with sort=newest: tokens first seen at or after this ISO8601 time (inclusive — first_seen_at is block-second granularity and several tokens can share one second, so the cursor row repeats; dedupe on token_address). Feed back the response''s next_since to poll for launches.' - name: after in: query schema: type: string format: date-time description: 'LEGACY — prefer cursor=. Only with sort=oldest: tokens first seen at or after this ISO8601 time (inclusive). With more same-second tokens than `limit` it cannot advance — use cursor=. Feed back next_after (dedupe on token_address); stop when has_more is false.' - name: cursor in: query schema: type: string description: 'Only with sort=oldest (PREFERRED over after=): the next_cursor from a previous page — a strict compound (first_seen_at, address) keyset, so the walk never repeats or skips a row and progresses with limit=1 through runs of identical timestamps. Malformed → 400; cannot be combined with after=.' - name: has_pool in: query schema: type: string enum: - 'true' - 'false' description: Filter on whether the token has a discovered pool (primary_pool from rhc_token_prices non-null). A token can be listed (first_seen_at set) before its pool is found — pair with sort=oldest&has_pool=true for a one-time backfill of every RHC token with a pool. - name: asset_class in: query schema: type: string enum: - equity - other description: equity = beacon-verified Robinhood tokenized stock/ETF (issuer beacon read from our node — never the name); other = everything else. - name: min_mc_usd in: query schema: type: number minimum: 0 description: Minimum current market cap (USD). - name: min_liquidity_usd in: query schema: type: number minimum: 0 description: Minimum current liquidity (USD). - name: launchpad in: query schema: type: string description: 'Filter by launchpad: pons, flap, clanker, hood.fun, noxa, virtuals.' - name: max_age_days in: query schema: type: integer minimum: 1 maximum: 365 default: 30 description: 'Value sorts only (market_cap / liquidity / peak_mc): exclude tokens whose last trade is older than this many days. Default 30 — a screener ranks what is tradeable; widen explicitly for dormant tokens.' responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood tokens: type: array items: type: object properties: token_address: type: string symbol: type: string nullable: true name: type: string nullable: true decimals: type: integer nullable: true description: From rhc_tokens. Added 2026-09-08 — needed to parse on-chain raw amounts correctly. asset_class: type: string nullable: true enum: - equity description: '`equity` = beacon-verified Robinhood tokenized stock/ETF (issuer beacon read from our node — never the name); null = everything else.' first_seen_at: type: string format: date-time nullable: true description: When OUR node first saw the token trade or get a pool — not the contract creation block. launchpad: type: string nullable: true is_graduated: type: boolean nullable: true deployer_address: type: string nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer price_usd: type: number nullable: true market_cap_usd: type: number nullable: true fdv_usd: type: number nullable: true peak_mc_usd: type: number nullable: true peak_mc_at: type: string format: date-time nullable: true drawdown_from_peak_pct: type: integer nullable: true description: Percent below all-time-high MC. liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: How liquidity_usd was derived. uniswap-v4 has no per-pool balances, so its figure is virtual reserves clamped to the PoolManager's total holdings — a provable CEILING, not measured per-pool TVL. All other venues are measured from real balances. primary_dex: type: string nullable: true primary_pool: type: string nullable: true last_trade_time: type: string format: date-time nullable: true count: type: integer sort: type: string since: type: string format: date-time nullable: true description: sort=newest only — echoes the request's since=. next_since: type: string format: date-time nullable: true description: sort=newest only. Feed back as since= to poll for newer launches. note: type: string description: sort=newest / sort=oldest only — constant explanation of the first_seen_at semantics and the cursor contract. after: type: string format: date-time nullable: true description: sort=oldest only — echoes the request's after=. has_more: type: boolean description: sort=oldest only — false ONLY when the candidates ran out (never inferred from a short filtered page). cursor: type: string nullable: true description: sort=oldest only — echoes the request's cursor=. next_cursor: type: string nullable: true description: sort=oldest only (PREFERRED). Feed back as cursor= — strict (first_seen_at, address) keyset; null = walk complete. next_after: type: string format: date-time nullable: true description: sort=oldest only, LEGACY inclusive cursor. Feed back as after= (dedupe on token_address). When a scanned page matched nothing it advances to the last scanned row. scan: type: object description: 'Present when a filter (launchpad / has_pool / price criteria) had to be scanned after the candidate fetch (audit F09): has_more is then false only when the candidates ran out, and scan_truncated=true means the per-request budget ran out first — more matches MAY exist.' properties: post_filtered: type: boolean scanned: type: integer description: Candidate rows examined scan_truncated: type: boolean description: The per-request scan budget ran out before `limit` matches — more matches MAY exist past the cursor/offset scan_budget: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokens x-operation-id-source: derived /rhc/tokens/{address}: get: tags: - Robinhood Chain summary: Robinhood Chain token bundle (BASIC+) description: 'Full snapshot for one token: metadata, live price/MC/FDV, peak MC + drawdown, graduation status, deployer reputation block (+ other tokens by the same deployer), KOL activity summary, and pool inventory with reserves. Tier: **BASIC**.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string symbol: type: string nullable: true name: type: string nullable: true decimals: type: integer nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true graduated_pool: type: string nullable: true graduated_at: type: string format: date-time nullable: true deployer_address: type: string nullable: true deployer_identity_status: type: string enum: - known - unresolved - unavailable description: known = the token row names its creator (identity does not depend on reputation); unresolved = no creator recorded; unavailable = the token lookup failed first_seen_at: type: string format: date-time nullable: true token_age_minutes: type: integer nullable: true price_usd: type: number nullable: true price_native: type: number nullable: true price_observed_at: type: string format: date-time nullable: true description: The last trade that set the native price — the price's own age anchor (same stale-price contract as GET /token/{mint}) price_age_seconds: type: integer nullable: true price_is_stale: type: boolean description: true when price_age_seconds > 900 price_updated_at: type: string format: date-time nullable: true description: Row write time — can move without a trade (USD re-derivation); not a price-age anchor market_cap_usd: type: number nullable: true fdv_usd: type: number nullable: true peak_mc_usd: type: number nullable: true peak_mc_at: type: string format: date-time nullable: true drawdown_from_peak_pct: type: integer nullable: true total_supply_raw: type: string nullable: true liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: How liquidity_usd was derived. uniswap-v4 has no per-pool balances, so its figure is virtual reserves clamped to the PoolManager's total holdings — a provable CEILING, not measured per-pool TVL. liquidity_note: type: string description: Human-readable statement of the uniswap-v4 ceiling semantics; constant. primary_dex: type: string nullable: true primary_pool: type: string nullable: true last_trade_time: type: string format: date-time nullable: true deployer: type: object nullable: true description: Deployer identity + reputation. Non-null whenever the creator address is known, even before the reputation view has it (history_status pending). properties: identity_status: type: string enum: - known history_status: type: string enum: - computed - pending - unavailable description: computed = in the reputation view · pending = known creator, reputation not computed yet (NOT "new") · unavailable = the reputation lookup failed address: type: string tier: type: string enum: - elite - good - neutral - spammer tokens_deployed: type: integer graduation_rate: type: number nullable: true runner_rate: type: number nullable: true runners: type: integer best_peak_mc_usd: type: number nullable: true launchpads: type: array items: type: string deployer_other_tokens: type: array items: type: string description: Up to 10 other tokens by the same deployer (symbol or address). kol_activity: type: object description: Complete aggregate over the token's whole KOL history (rhc_token_kol_activity), keyed on the stable KOL id — two KOLs sharing a display name no longer collapse. If the aggregate is unavailable it falls back to a LABELLED newest-200 sample (basis latest_200_trades, complete=false when truncated, sample_size). properties: distinct_kols: type: integer description: Distinct KOL ids (not display names) names: type: array items: type: string buys: type: integer sells: type: integer net_eth: type: number distinct_wallets: type: integer buy_eth: type: number sell_eth: type: number participants: type: array description: Up to 20 KOLs, most recent first items: type: object properties: kol_id: type: string name: type: string nullable: true twitter_url: type: string nullable: true buys: type: integer sells: type: integer last_trade_at: type: string format: date-time identity: type: string enum: - kol_wallet_id window: type: object properties: kind: type: string enum: - all_time - latest_trades first_trade_at: type: string format: date-time nullable: true last_trade_at: type: string format: date-time nullable: true basis: type: string description: all_trades (complete aggregate) or latest_N_trades (fallback sample) complete: type: boolean sample_size: type: integer description: Fallback sample only degraded_fields: type: array items: type: string description: Blocks whose lookup failed (e.g. deployer_other_tokens) — their values are unknown, not empty pools: type: array description: Up to 20 pools with reserves/liquidity/sqrt_price. Each entry carries `liquidity_basis` (`v4_virtual_ceiling` | `measured`) for its own `liquidity_usd`. items: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Token not found on Robinhood Chain. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcTokensByAddress x-operation-id-source: derived /rhc/tokens/{address}/candles: get: tags: - Robinhood Chain summary: OHLC candles on Robinhood Chain (PRO+) description: 'Chronological OHLC candles aggregated from the 1-minute base series: price + market-cap OHLC, close liquidity, volume with buy/sell split, and trade/buy/sell counts. Tier: **PRO+**, with every field and the full available history on PRO (unlike the Solana `/tokens/{mint}/candles`, which limits PRO to 30 days). Windows over 999 buckets are paged newest-first on the timeframe grid; `truncated` reports a page budget that ran out.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address. - name: tf in: query schema: type: string enum: - 1m - 5m - 15m - 1h - 4h - 1d default: 1m description: Candle timeframe, rolled up server-side from the 1-minute base series. Also accepted as `timeframe`. Defaults to `1m` (this endpoint's original behaviour), unlike the Solana `/tokens/{mint}/candles` route which defaults to `1h`. - name: limit in: query schema: type: integer minimum: 1 maximum: 1500 default: 240 description: Number of candles (most recent first, returned chronological). 1500 = one full day of 1m bars with margin. - name: from in: query schema: type: string format: date-time description: Lower bound on bucket_start (inclusive). If neither `from` nor `to` is given, the window is anchored on the token's most recent candle — so quiet tokens still return their last `limit` candles. - name: to in: query schema: type: string format: date-time description: Upper bound on bucket_start (exclusive). responses: '200': description: OK. Candles ordered oldest→newest. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string timeframe: type: string enum: - 1m - 5m - 15m - 1h - 4h - 1d example: 1m description: Echoes the timeframe actually served. from: type: string format: date-time nullable: true to: type: string format: date-time nullable: true candles: type: array items: type: object properties: bucket_start: type: string format: date-time open_price_usd: type: number high_price_usd: type: number low_price_usd: type: number close_price_usd: type: number open_mc_usd: type: number nullable: true high_mc_usd: type: number nullable: true low_mc_usd: type: number nullable: true close_mc_usd: type: number nullable: true close_liquidity_usd: type: number nullable: true close_supply: type: number nullable: true volume_usd: type: number volume_buy_usd: type: number nullable: true volume_sell_usd: type: number nullable: true trades: type: integer buy_count: type: integer nullable: true sell_count: type: integer nullable: true dex: type: string nullable: true pool_address: type: string nullable: true count: type: integer truncated: type: boolean description: true when the 3-page budget (up to 999 buckets each) ran out before `limit` candles or `from` were reached. covered_from: type: string format: date-time nullable: true description: Oldest instant actually searched; equals `from` when the whole window was scanned. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressCandles x-operation-id-source: derived /rhc/tokens/{address}/kol-consensus: get: tags: - Robinhood Chain summary: KOL consensus on a Robinhood Chain token (PRO+) description: 'How the tracked-KOL cohort is positioned on a token: distinct KOL buyers vs sellers, exit rate (bought AND sold), net ETH flow, median entry MC, and first-touch wallet/time. Full parity with the Solana `/tokens/{mint}/kol-consensus` (sourced from `rhc_kol_trades`), EVM-denominated (`net_flow_eth`). ULTRA additionally returns the `buyers` and `exited` wallet lists. Tier: **PRO+**.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). responses: '200': description: OK. `consensus` is null when no tracked KOL has traded the token. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string current_mc_usd: type: number nullable: true current_price_usd: type: number nullable: true consensus: type: object nullable: true properties: total_kol_buyers: type: integer total_kol_sellers: type: integer kol_exit_rate: type: number description: Fraction of KOL buyers who also sold (0–1). net_flow_eth: type: number total_buy_eth: type: number total_sell_eth: type: number first_kol_buy_at: type: string format: date-time nullable: true last_kol_buy_at: type: string format: date-time nullable: true first_touch_wallet: type: string nullable: true first_touch_at: type: string format: date-time nullable: true median_entry_mc_usd: type: number nullable: true description: Median MC at KOL buy — over the buys that carried an MC-at-trade (see entry_mc_samples). Null when the RHC pricer withheld MC under its liquidity gate. entry_mc_samples: type: integer description: Number of buys with a market_cap_usd_at_trade — the median's sample size. total_trades: type: integer buyers: type: array items: type: string description: ULTRA only — distinct KOL buyer wallets. exited: type: array items: type: string description: ULTRA only — KOL wallets that bought and sold. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressKolConsensus x-operation-id-source: derived /rhc/tokens/{address}/buyer-quality: get: tags: - Robinhood Chain summary: Early-buyer quality on a Robinhood Chain token (BASIC+) description: 'A 0–100 quality read on a token''s earliest distinct buyer cohort (first 20), derived live from `rhc_trades` and enriched with `mv_rhc_alpha_wallets` history. Full parity with the Solana scorer: win-rate, KOL-presence, bot-domination and **bundle-buyer** legs (a bundled early buyer in the top 10 costs −5; a heavily bundled cohort of >10 costs −15), plus the **dump-cluster ensemble** — `dump_cluster_count` counts early buyers that repeatedly sit in launches that crashed off their own peak (rolling 42-day model, out-of-sample validated on RHC). Dump-cluster is **informational**: it flags the pattern but does not move the score. Tier: **BASIC** (any valid key).' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). responses: '200': description: OK. Neutral score (50) with `note` when the token has no buyer history yet. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string current_mc_usd: type: number nullable: true cohort_selection: type: string enum: - distinct_first_buy - legacy_row_window description: distinct_first_buy = the first 20 DISTINCT buyer EOAs by their first buy (block, tx index, log index), selected before the limit. legacy_row_window = pre-rhc/011 fallback (oldest 300 buy rows, deduped — a repeat buyer can crowd out later distinct buyers); served only until that migration is applied. quality: type: object properties: score: type: integer minimum: 0 maximum: 100 confidence: type: string enum: - insufficient_data - low - medium - high description: 'Confidence in the PREDICTIVE inputs: counts only buyers whose win rate fed the score (≥3 tokens of history, not bot-flagged, not zero-cost-dump dominated). insufficient_data = none did — the score is the neutral-50 default plus penalties. 1 → low, 5+ → medium, 11+ → high.' signal: type: string enum: - positive - neutral - negative breakdown: type: object properties: wallets_with_history: type: integer description: Buyers with ≥3 tokens of history (cohort identification — not predictive) qualified_win_rate_wallets: type: integer description: Buyers whose win rate fed the score — the basis of confidence early_buyers_analyzed: type: integer alpha_wallet_count: type: integer kol_count: type: integer bundle_buyer_count: type: integer description: Early buyers flagged as part of a same-block launch bundle (mig 255). dump_cluster_count: type: integer description: Early buyers on the rolling dump-cluster list (≥5 crashed-off-peak cohorts, 0 runner cohorts, trailing 42d, OOS-validated). Informational — high count = strong dump signal. recycled_early_buyer_count: type: integer description: Early buyers with ≥5 recent early-buyer appearances of any kind (dump_cluster_count is a subset). avg_historical_win_rate: type: number nullable: true description: Percent (0–100), non-bot buyers with ≥3 tokens of history. bot_dominated: type: boolean coverage: type: object description: Signal availability. Dump-cluster is available but informational (does not move the score). properties: bundle_detection: type: string enum: - available dump_cluster_signal: type: string enum: - available note: type: string earliest_buyers_caveat: type: string description: For launches before 2026-07-18 the earliest-buyers cohort is the earliest 20 ATTRIBUTED buyers (trader_eoa backfill pending), not necessarily the first 20 buyers. note: type: string description: Present only when buyer data is insufficient. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcTokensByAddressBuyerQuality x-operation-id-source: derived /rhc/tokens/{address}/bundle: get: tags: - Robinhood Chain summary: Launch-bundle detection on a Robinhood Chain token (BASIC+) description: 'Detects a coordinated launch bundle in a token''s earliest-buyer cohort and measures how much of what the bundle bought it still holds. Mirrors the Solana `/tokens/{mint}/bundle` detector: rank the first 20 distinct buyers by on-chain order, flag a bundle when 3+ of them make their first buy in the **same block**, then report the cohort''s current-held %. Robinhood Chain is an Arbitrum Orbit L2 with no atomic multi-signer transaction, so there is no `atomic_tx` kind — a detected bundle is `same_block` (else `none`). Scores tokens ingested live (the near-launch window where bundling happens). Field-gated by tier: **BASIC** gets the scalar `bundle` signal only; **PRO** adds the top-10 wallets; **ULTRA** returns the full cohort enriched with alpha-wallet identity (win-rate, bot, KOL).' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). responses: '200': description: 'OK. `wallet_count` 0 with `bundle_kind: none` when no same-block early-buyer cluster is present.' content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string bundle: type: object properties: wallet_count: type: integer description: Bundle-cohort size (0 when none). bundle_kind: type: string enum: - same_block - none description: '`same_block` = 3+ early buyers first-bought in one block; `none` = no cluster. `atomic_tx` does not exist on EVM.' held_ratio: type: number nullable: true description: Net tokens still held ÷ tokens bought, [0,1]. The primary signal. held_pct_of_supply: type: number nullable: true description: Net tokens held ÷ total supply, [0,1]; null when supply is unknown. fully_exited: type: boolean description: True when the cohort holds ≤0.5% of what it bought. buy_volume: type: number description: Cohort cumulative buy-side token volume (human-scaled). tokens_held: type: number description: Cohort net position (Σbuys − Σsells, human-scaled). wallets: type: array description: Empty for BASIC; top-10 for PRO; full cohort for ULTRA. items: type: object properties: rank: type: integer description: Early-buyer rank (1 = first buyer). wallet: type: string description: Buyer wallet (lowercase 0x). held_ratio: type: number nullable: true has_sold: type: boolean is_kol: type: boolean description: Wallet is a tracked RHC KOL. win_rate: type: number nullable: true description: ULTRA only — historical win-rate [0,1]. likely_bot: type: boolean description: ULTRA only — bot heuristic from mv_rhc_alpha_wallets. tokens_held: type: number description: ULTRA only — net position, human-scaled. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcTokensByAddressBundle x-operation-id-source: derived /rhc/tokens/{address}/top-traders: get: tags: - Robinhood Chain summary: Top traders of a Robinhood Chain token, ranked by realized ETH (PRO+) description: 'Lifetime per-trader performance on one token, ranked by realized ETH flow, enriched with alpha-wallet reputation (win-rate, bot heuristic, KOL identity), dump-cluster membership and early-buyer rank. **`net_eth` is realized flow (sell − buy), not PnL.** It does not value a trader''s remaining bag, so a wallet that bought and still holds ranks last. There is no cost basis in the underlying rollup, so true PnL is not available here — use `/rhc/wallet/{address}/pnl` for FIFO cost-basis PnL. **PRO** returns up to 50 rows; **ULTRA/BUSINESS** up to 200.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 description: Rows to return. Capped at 50 on PRO, 200 on ULTRA/BUSINESS. - name: offset in: query schema: type: integer minimum: 0 maximum: 10000 default: 0 description: Rows to skip. responses: '200': description: OK. `traders` is empty for a token with no attributed traders yet — a 200, not an error. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string traders: type: array items: type: object properties: trader_eoa: type: string description: Trader address (lowercase 0x). buy_eth: type: number nullable: true sell_eth: type: number nullable: true net_eth: type: number nullable: true description: sell_eth − buy_eth. Realized only. trades: type: integer last_trade_at: type: string format: date-time nullable: true avg_trade_mc: type: number nullable: true description: Mean market cap at time of trade (USD). win_rate: type: number nullable: true description: Wallet-level historical win-rate [0,1]. likely_bot: type: boolean nullable: true is_known_kol: type: boolean nullable: true kol_name: type: string nullable: true description: Null when the KOL is tracked but unnamed. wallet_net_eth: type: number nullable: true description: Trader's net across ALL tokens, for context. wallet_tokens: type: integer nullable: true dump_cohorts: type: integer nullable: true description: Dump-cluster cohort count; >0 means recycled dumper. early_buyer_rank: type: integer nullable: true description: 1–20 when this trader was an early buyer. count: type: integer limit: type: integer offset: type: integer has_more: type: boolean metric: type: string description: States the net_eth semantics explicitly. attribution: type: object description: 'Interim attribution disclosure: the underlying rollup filters `trader_eoa IS NOT NULL`, and trader_eoa was only written reliably from 2026-07-18, so pre-floor history is not reflected. Removed once the trader_eoa backfill lands.' properties: attribution_complete_from: type: string format: date-time note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address, or bad limit/offset. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressTopTraders x-operation-id-source: derived /rhc/tokens/{address}/flow: get: tags: - Robinhood Chain summary: Net buy/sell flow by trader cohort on a Robinhood Chain token (PRO+) description: '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.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). - name: window in: query schema: type: string enum: - 1h - 6h - 24h - 7d default: 24h description: Lookback window. responses: '200': description: OK. `cohorts` is empty when the token had no trades in the window. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string window: type: string enum: - 1h - 6h - 24h - 7d cohorts: type: array items: type: object properties: cohort: type: string enum: - kol - bot - dump_cluster - early_buyer - unprofiled - smart_money - retail traders: type: integer trades: type: integer buy_eth: type: number sell_eth: type: number net_eth: type: number description: sell − buy. Positive = distributed. totals: type: object description: Sum across cohorts; always equals the parts. sign_convention: type: string attribution: type: object description: '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.' properties: attribution_complete_from: type: string format: date-time note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address, or window not in {1h,6h,24h,7d}. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressFlow x-operation-id-source: derived /rhc/tokens/{address}/peak-history: get: tags: - Robinhood Chain summary: Peak market cap, drawdown and high-water curve for a Robinhood Chain token… description: 'Peak market cap, current drawdown from peak, and a running high-water curve. **Two peaks are returned, and they can disagree.** `peak_mc_usd_recorded` is the stored high-water mark every other Robinhood Chain surface keys off (deployer runner-rate, the $40K graduation bar). `peak_mc_usd_observed` is the maximum of the 1-minute candle highs — trade-level truth, and always ≥ the recorded value. The recorded figure is sampled from write batches so it can undercount an intra-batch spike; both are surfaced rather than silently swapping one for the other, which would desync this endpoint from deployer tiering. Candle history begins 2026-07-15, so a token that peaked earlier cannot have its peak reconstructed — `observed_covers_full_history` tells you whether the observed figure spans the token''s whole life. Curve binning is chosen server-side (1m→4h) to keep the series bounded.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). - name: window in: query schema: type: string enum: - 24h - 7d - 30d - all default: 7d description: Curve window. - name: curve in: query schema: type: string enum: - 'true' - 'false' default: 'true' description: Set false to skip the series and return only the peak summary. responses: '200': content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string name: type: string nullable: true symbol: type: string nullable: true current: type: object description: Live market cap, liquidity, price, FDV. peak: type: object properties: peak_mc_usd_recorded: type: number nullable: true peak_mc_at_recorded: type: string format: date-time nullable: true peak_mc_usd_observed: type: number nullable: true description: Candle-derived max; ≥ recorded. peak_mc_at_observed: type: string format: date-time nullable: true observed_covers_full_history: type: boolean description: False when candle history starts after the token did. pct_of_peak: type: number nullable: true description: Current MC ÷ best-known peak, [0,1]. drawdown_from_peak: type: number nullable: true description: 1 − pct_of_peak. curve: type: object properties: window: type: string bucket: type: string description: Server-chosen bin size (1m/5m/15m/1h/4h). points: type: array items: type: object properties: bucket_start: type: string format: date-time high_mc_usd: type: number nullable: true close_mc_usd: type: number nullable: true running_peak_mc: type: number nullable: true description: Monotonically non-decreasing high-water mark. count: type: integer description: OK. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address, or bad window. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Token not found on Robinhood Chain. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressPeakHistory x-operation-id-source: derived /rhc/tokens/{address}/risk: get: tags: - Robinhood Chain summary: EVM-native risk assessment for a Robinhood Chain token (PRO+) description: 'Risk assessment computed **live** against our own Robinhood Chain node at the chain head. **This is not the Solana risk model.** EVM has no mint or freeze authority. Measured across 300 random Robinhood Chain tokens, only 2.3% even expose an `owner()` function and 0% expose `mint` in their own bytecode — so an absent flag is the norm, not a safety signal. The axes that actually discriminate here are proxy upgradeability, LP custody, and sellability. **Sellability is the strongest signal.** A sell is simulated through the router at head using state overrides, which detects a token that can be bought but not sold. It is computed live, never cached — whether a token is sellable can change the moment an owner flips a setting. Proxies are resolved before capability scanning: EIP-1167 minimal proxies (14% of tokens) carry zero selectors of their own, and the tokenized equities are beacon proxies whose *implementation* is what exposes `mint`/`pause`/`upgradeTo`. `lp_custody` is only read for uniswap-v2 pools; v3/v4 liquidity sits in an LP NFT whose custody needs a position-manager trace, and is reported `unknown` rather than guessed.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). responses: '200': description: OK. Absent capability flags are the norm on this chain and are not a safety guarantee. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string checked_at: type: string format: date-time description: Computed live; always current. code_size: type: integer description: Runtime bytecode length in bytes. is_contract: type: boolean proxy: type: object properties: kind: type: string enum: - none - eip1167_minimal - eip1967 - eip1967_beacon - legacy implementation: type: string nullable: true admin: type: string nullable: true upgradeable: type: boolean description: False for eip1167_minimal — the target is baked into immutable code. owner: type: object properties: model: type: string enum: - none - renounced - eoa - contract description: '`none` = no owner function at all, which is NOT the same as renounced.' address: type: string nullable: true capabilities: type: object properties: can_mint: type: boolean can_pause: type: boolean has_access_control: type: boolean selectors_found: type: array items: type: string liquidity: type: object properties: primary_pool: type: string nullable: true dex: type: string nullable: true lp_custody: type: string enum: - burned - locked - at_risk - unknown lp_burned_pct: type: number nullable: true last_removed_at: type: string format: date-time nullable: true description: Most recent LP withdrawal observed on this token (uniswap-v2/v3 `Burn`, uniswap-v4 negative `ModifyLiquidity`). `null` means none seen since removal capture began on 2026-08-05 — not that none ever happened. sellability: type: object properties: sellable: type: string enum: - 'yes' - 'no' - unknown reason: type: string nullable: true flags: type: array items: type: string description: Derived from the fields above. Includes `lp_removed_24h` when liquidity was withdrawn from this token in the last 24 hours. score: type: integer nullable: true description: 0–100, conservative. Absence of evidence is not evidence of safety. assessment: type: object description: 'Whether every input was actually read (2026-09-21). A failed read is an UNKNOWN input, never a silent all-clear: e.g. lp_removal_history unknown ⇒ the absence of `lp_removed_24h` proves nothing; observed_sells unknown ⇒ a simulated sell revert is reported sellable=unknown, not a honeypot.' properties: status: type: string enum: - complete - incomplete unknown_inputs: type: array items: type: string enum: - lp_removal_history - pools - holder_probes - observed_sells coverage: type: object description: What this model does and does not read — see the endpoint description. properties: model: type: string enum: - evm_native liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: 'Basis of any liquidity_usd figure quoted for this token: uniswap-v4 values are virtual reserves clamped to the PoolManager''s total holdings — a provable ceiling, not measured per-pool TVL.' liquidity_note: type: string note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressRisk x-operation-id-source: derived /rhc/tokens/{address}/early-buyers: get: tags: - Robinhood Chain summary: First buyers of a Robinhood Chain token, and whether they still hold (PRO+) description: 'The first buyers of a Robinhood Chain token, in order, joined to what happened next. `rhc_early_buyers` ranks the first 20 buyers of 437k tokens and is recomputed daily; until now it was read only as a per-wallet COUNT, never exposed as a per-token list. The Solana counterpart is `GET /kol/tokens/{mint}/entry-order`. **`realized_eth` is a profit only when `position` is `closed`.** It is `sold_eth - bought_eth`, so a buyer who is still holding shows a negative figure - they have spent and not yet sold. Always read `position` alongside it. **`still_holding` comes from the ERC-20 Transfer-log fold**, the same source as `/rhc/tokens/{address}/holders`. Treat it as exact only when `holdings_verified` is true. **Ranks are as of `computed_at`, not live.** A token that began trading after the last sweep returns an empty list with a stated reason - never an assertion that it had no early buyers. Wallets may be ERC-4337 smart accounts, so a wallet is an address, not a person.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). - name: limit in: query schema: type: integer minimum: 1 maximum: 20 default: 20 description: Ranking depth is 20 by construction. responses: '200': description: OK. An empty early_buyers array with a note means the token is not yet ranked. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string early_buyers: type: array items: type: object properties: rank: type: integer description: 1 = first buyer observed. wallet: type: string first_buy_at: type: string format: date-time nullable: true first_buy_block: type: integer nullable: true still_holding: type: boolean nullable: true description: Null when no holding data exists for this wallet. balance: type: string nullable: true description: Raw uint256 as a decimal STRING. position: type: string enum: - closed - open - unknown bought_eth: type: number nullable: true sold_eth: type: number nullable: true realized_eth: type: number nullable: true description: sold_eth - bought_eth. A profit ONLY when position is closed. trades: type: integer nullable: true avg_entry_mc_usd: type: number nullable: true count: type: integer computed_at: type: string format: date-time nullable: true holdings_verified: type: boolean nullable: true description: True only when the token reconciles against on-chain totalSupply(). summary: type: object nullable: true properties: ranked: type: integer with_holding_data: type: integer still_holding: type: integer exited: type: integer closed_positions: type: integer realized_eth_closed_only: type: number nullable: true note: type: string description: Present only when the list is empty. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid token address or query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Tier gate - requires PRO or above. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressEarlyBuyers x-operation-id-source: derived /rhc/tokens/{address}/holders: get: tags: - Robinhood Chain summary: Holder set and concentration for a Robinhood Chain token (PRO+) description: '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.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Token address (0x, 40 hex). - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 description: Capped at 50 on PRO, 200 on ULTRA/BUSINESS. - name: offset in: query schema: type: integer minimum: 0 maximum: 10000 default: 0 description: Position paging, capped at 10,000 (OFFSET is O(n)). For a full walk use `after`. - name: after in: query schema: type: string description: 'Keyset cursor (2026-09-05): pass the previous page''s `next_after` unchanged to continue past the offset cap. Same order (balance DESC, holder ASC); supersedes offset. `next_after` is null on the last page.' responses: '200': description: OK. Check `verified` before relying on the numbers. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string verified: type: boolean description: True only when reconstructed supply matches on-chain totalSupply(). unverified_reason: type: string nullable: true holders: type: array items: type: object properties: holder: type: string balance: type: string description: Raw uint256 as a decimal STRING — not a number. share: type: number nullable: true description: Share of circulating (pools/burns excluded), [0,1]. last_block: type: integer nullable: true is_pool: type: boolean is_burn: type: boolean is_deployer: type: boolean count: type: integer limit: type: integer offset: type: integer has_more: type: boolean next_after: type: string nullable: true description: '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: type: string nullable: true description: Echo of the `after` cursor this page was read from (null on the first page). concentration: type: object nullable: true properties: holder_count: type: integer nullable: true circulating: type: string nullable: true top1_share: type: number nullable: true top10_share: type: number nullable: true top50_share: type: number nullable: true hhi: type: number nullable: true description: Herfindahl index over circulating shares. pool_held_pct: type: number nullable: true burned_pct: type: number nullable: true deployer_pct: type: number nullable: true holder_growth: type: object nullable: true description: 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). properties: 1h: $ref: '#/components/schemas/RhcHolderGrowthWindow' 24h: $ref: '#/components/schemas/RhcHolderGrowthWindow' 7d: $ref: '#/components/schemas/RhcHolderGrowthWindow' note: type: string reconciliation: type: object nullable: true description: recon_supply vs chain_supply at recon_block. source: type: object description: Method, sweep cursor and completeness. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressHolders x-operation-id-source: derived /rhc/deployer-hunter/leaderboard: get: tags: - Robinhood Chain summary: Deployer reputation leaderboard on Robinhood Chain (BASIC+) description: 'Robinhood Chain deployers ranked by reputation, from a 5-min-refresh rollup over every launchpad token we''ve indexed (160K+ ranked deployers). Most RHC launchpads are direct-to-DEX (no bonding curve), so "graduation" is a market-cap milestone: `graduation_rate` = share of the deployer''s tokens that reached a $40K+ peak MC; `runner_rate` = share that reached $100K+. **`tier` is earned on `runner_rate`, NOT `graduation_rate`:** elite = 5+ launches, 24h+ of deployer history and runner_rate >= 0.50; good = same but >= 0.25; spammer = 20+ launches with graduation_rate < 0.05 (the only tier still keyed on the $40K bar). The $40K bar is cheap enough to manufacture — operators mass-relaunch one ticker across rotating wallets — so it is reported but no longer sets the tier. Tier: **BASIC** (any valid key).' parameters: - name: sort in: query schema: type: string enum: - graduation_rate - runner_rate - tokens_deployed - best_peak_mc_usd - last_deploy_at default: graduation_rate description: Ordering (all descending, NULLs last). - name: tier in: query schema: type: string enum: - elite - good - neutral - spammer description: Filter to one reputation tier. - name: min_tokens in: query schema: type: integer minimum: 1 maximum: 100000 default: 3 description: Minimum tokens deployed. Default 3 — the minimum sample for a graded tier; lower it to include one-shot deployers. - name: limit in: query schema: type: integer minimum: 1 maximum: 50 default: 20 - name: offset in: query schema: type: integer minimum: 0 maximum: 10000 default: 0 responses: '200': description: OK. `total` is the filtered deployer count; page with limit/offset until `has_more` is false. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood deployers: type: array items: type: object properties: deployer_address: type: string description: Deployer wallet (lowercase 0x). tokens_deployed: type: integer graduated: type: integer description: Tokens that reached a $40K+ peak MC (the graduation milestone). graduation_rate: type: number description: graduated ÷ tokens_deployed — share of the deployer's tokens that reached $40K+ peak MC. runners: type: integer description: Tokens that peaked ≥ $100K MC. runner_rate: type: number description: runners ÷ tokens_deployed. best_peak_mc_usd: type: number nullable: true description: All-time-high MC across all their tokens. launchpads: type: array items: type: string description: Launchpads this deployer has used. first_deploy_at: type: string format: date-time nullable: true last_deploy_at: type: string format: date-time nullable: true tier: type: string enum: - elite - good - neutral - spammer total: type: integer limit: type: integer offset: type: integer has_more: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterLeaderboard x-operation-id-source: derived /rhc/deployer-hunter/alerts: get: tags: - Robinhood Chain summary: Deployer signal alert feed on Robinhood Chain (BASIC+) description: 'The deployer alert feed on Robinhood Chain (from `rhc_deployer_alerts`) — new deploys and graduations from tracked deployers, newest first. RHC domain values differ from Solana: `tier` is elite | good | neutral | spammer, `priority` is high | medium, `alert_type` is new_deploy | graduated (RHC has no bonded/kol_buy alert types, and no KOL-buy enrichment). **Two behaviours changed 2026-07-25.** (1) A tradability filter is now applied **BY DEFAULT** (`liquidity_usd >= $100`; unknown liquidity fails it) — the feed was serving alerts on tokens that had pumped and drained, one at $45K MC against $68 of liquidity. Pass `include_untradeable=true` for the raw tape; the active filter is echoed as `tradability_filter`. (2) `tier` and the `message` explaining it are now resolved at **READ time** from the live deployer rollup instead of being frozen at insert, so a demoted deployer can no longer be advertised as good-tier indefinitely. The original snapshot is preserved as `tier_at_alert`, with `tier_is_stale` flagging disagreement. Rows also carry `liquidity_usd` and `current_mc_usd`. **Paging (2026-09-21, audit F09 follow-up):** the tradability and tier gates are served by a bounded SCAN over (event_at DESC, id DESC) — `has_more` is false only at the real end, `scan.scan_truncated` says the budget ran out first; page with `cursor=` (`next_cursor`). Alerts with a NULL event_at (none in production) are excluded. Tier: **BASIC** (any valid key) — **ULTRA** gets the full requested `limit`, while BASIC/PRO share a 50-alert cap per request.' parameters: - name: deployer_tier in: query schema: type: string enum: - elite - good - neutral - spammer description: Filter to one deployer reputation tier. Applied to the RESOLVED (read-time) tier, not the stored snapshot, so the filter and the reported `tier` always agree. - name: include_untradeable in: query schema: type: boolean default: false description: Set true to disable the default liquidity_usd >= $100 tradability filter and receive the raw alert tape. - name: priority in: query schema: type: string enum: - high - medium description: Filter by alert priority. - name: alert_type in: query schema: type: string enum: - new_deploy - graduated - name: launchpad in: query schema: type: string minLength: 1 maxLength: 32 description: Filter to one launchpad. - name: min_mc in: query schema: type: number minimum: 0 description: Minimum market cap at alert time (USD). - name: limit in: query schema: type: integer minimum: 1 maximum: 500 default: 50 description: Capped at 50 for BASIC/PRO; ULTRA gets the full requested value. - name: since in: query schema: type: string format: date-time description: 'Incremental polling: return only alerts with `event_at` strictly newer than this ISO timestamp. Pass back `next_event_at` from the previous response to receive just what is new.' - name: before in: query schema: type: string format: date-time description: 'Cursor: return only alerts with `event_at` strictly older than this ISO timestamp. Pass `next_before` from the previous response to page backwards. Takes precedence over `offset`.' - name: offset in: query schema: type: integer minimum: 0 maximum: 10000 default: 0 description: Offset pagination (RAW rows, before the gates), used when no cursor is supplied. Prefer `cursor` for stable paging over a live feed. - name: cursor in: query schema: type: string maxLength: 200 description: 'PREFERRED pagination (audit F09 follow-up): the `next_cursor` from a previous page — an opaque strict (event_at, id) keyset, so paging never repeats or skips rows that share a sort value and progresses with limit=1 through runs of identical timestamps. Malformed or tampered → 400. Cannot be combined with `before=` or `offset=` (400).' responses: '200': description: '`next_event_at` is the newest event_at on the page (poll cursor); `data_age_seconds` is the age of the newest alert.' content: application/json: schema: type: object properties: chain: type: string enum: - robinhood alerts: type: array items: type: object properties: id: type: string deployer_address: type: string description: Deployer wallet (0x). token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true alert_type: type: string enum: - new_deploy - graduated title: type: string nullable: true message: type: string nullable: true launchpad: type: string nullable: true tier: type: string nullable: true enum: - elite - good - neutral - spammer description: Deployer reputation tier resolved at READ time from the live deployer rollup (falls back to the snapshot when the deployer is not in the rollup). tier_at_alert: type: string nullable: true enum: - elite - good - neutral - spammer description: Snapshot of the tier written when the alert fired. tier_is_stale: type: boolean description: true when the read-time tier differs from tier_at_alert. mc_at_alert: type: number nullable: true description: Market cap when the alert fired (USD). liquidity_usd: type: number nullable: true description: Token liquidity now (USD). liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: 'How liquidity_usd was derived. A uniswap-v4 row passing the $100 tradability filter is a CEILING-pass: its figure is virtual reserves clamped to the PoolManager''s total holdings, not measured per-pool TVL.' current_mc_usd: type: number nullable: true description: Token market cap now (USD). risk: $ref: '#/components/schemas/RhcTokenRiskSummary' priority: type: string enum: - high - medium is_active: type: boolean created_at: type: string format: date-time event_at: type: string format: date-time nullable: true limit: type: integer offset: type: integer tradability_filter: type: string description: 'The active tradability gate, echoed: `liquidity_usd >= $100`, or `off (include_untradeable=true)`.' liquidity_note: type: string description: Constant statement of the uniswap-v4 ceiling semantics — a v4 row passing the tradability filter is a ceiling-pass; per-row `liquidity_basis` says which rows that applies to. next_event_at: type: string format: date-time nullable: true description: Newest event_at on this page — pass as ?since= to poll forward. next_before: type: string format: date-time nullable: true description: 'Legacy cursor — event_at of the last row consumed (returned or gated out); pass as ?before= to page backward. Strict: skips alerts sharing that event_at. Prefer next_cursor.' next_cursor: type: string nullable: true description: Opaque keyset cursor for the next (older) page — pass as `cursor=`. null = end of feed. PREFERRED over the strict-timestamp legacy cursor, which skips same-timestamp siblings of the boundary row. has_more: type: boolean description: false only when the candidate feed is exhausted (not merely when the page is short). scan: type: object description: 'Present when a filter had to be applied after the candidate fetch (audit F09): has_more is then false only when the candidates ran out, and scan_truncated=true means the per-request scan budget ran out first — more matches MAY exist past next_cursor.' properties: post_filtered: type: boolean scanned: type: integer description: Candidate rows examined scan_truncated: type: boolean description: The per-request scan budget ran out before `limit` matches — more matches MAY exist past the cursor/offset scan_budget: type: integer data_age_seconds: type: integer nullable: true headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterAlerts x-operation-id-source: derived /rhc/deployer-hunter/recent-bonds: get: tags: - Robinhood Chain summary: Recent graduations on Robinhood Chain (BASIC+) description: 'Recently graduated tokens on Robinhood Chain, newest first. On RHC a "graduation" is the **$40K peak-MC milestone**, not a bonding-curve completion — most RHC launchpads are direct-to-DEX. The set is defined purely by `peak_mc_usd ≥ $40,000` (independent of the sometimes-unreliable `is_graduated` flag), then enriched with token metadata and the deployer''s reputation tier. Ordered by (peak_mc_at DESC, token_address DESC); page with `cursor=` (`next_cursor`, added 2026-09-21). `deployer_tier` is served by a bounded scan — see `has_more` / `scan`. Tier: **BASIC** (any valid key).' parameters: - name: deployer_tier in: query schema: type: string enum: - elite - good - neutral - spammer description: Filter to one deployer reputation tier (post-filter over the peak-MC-ordered set). - name: min_peak in: query schema: type: number minimum: 0 description: Raise the peak-MC floor above the $40K graduation milestone (USD). Never lowers it below $40K. - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 - name: cursor in: query schema: type: string maxLength: 200 description: 'PREFERRED pagination (audit F09 follow-up): the `next_cursor` from a previous page — an opaque strict (peak_mc_at, token_address) keyset, so paging never repeats or skips rows that share a sort value and progresses with limit=1 through runs of identical timestamps. Malformed or tampered → 400.' responses: '200': description: '`graduation_mc` echoes the $40K milestone; `next_peak_mc_at` is the newest peak timestamp on the page.' content: application/json: schema: type: object properties: chain: type: string enum: - robinhood graduation_mc: type: integer description: The $40K peak-MC graduation milestone (USD). tokens: type: array items: type: object properties: address: type: string symbol: type: string nullable: true name: type: string nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true deployer_address: type: string nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer first_seen_at: type: string format: date-time nullable: true market_cap_usd: type: number nullable: true description: Live market cap. peak_mc_usd: type: number nullable: true description: All-time-high MC observed since ingestion. peak_mc_at: type: string format: date-time nullable: true limit: type: integer next_peak_mc_at: type: string format: date-time nullable: true next_cursor: type: string nullable: true description: Opaque keyset cursor for the next (older) page — pass as `cursor=`. null = end of feed. PREFERRED over the strict-timestamp legacy cursor, which skips same-timestamp siblings of the boundary row. has_more: type: boolean description: false only when the candidate feed is exhausted (not merely when the page is short). scan: type: object description: 'Present when a filter had to be applied after the candidate fetch (audit F09): has_more is then false only when the candidates ran out, and scan_truncated=true means the per-request scan budget ran out first — more matches MAY exist past next_cursor.' properties: post_filtered: type: boolean scanned: type: integer description: Candidate rows examined scan_truncated: type: boolean description: The per-request scan budget ran out before `limit` matches — more matches MAY exist past the cursor/offset scan_budget: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterRecentBonds x-operation-id-source: derived /rhc/deployer-hunter/{address}: get: tags: - Robinhood Chain summary: Single deployer profile on Robinhood Chain (BASIC+) description: 'One deployer''s full reputation row (tier, bonding_rate, runner_rate, best peak MC, launchpads, deploy timeline) plus their 50 most recent tokens enriched with live MC and peak MC. Unknown wallets return 200 with `is_deployer: false` (not a 404) so clients can branch cheaply. Tier: **BASIC** (any valid key).' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Deployer EVM wallet address (0x, 40 hex). responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood is_deployer: type: boolean description: False if this wallet has never deployed a tracked token (deployer is then null). address: type: string deployer: type: object nullable: true properties: deployer_address: type: string tokens_deployed: type: integer curve_tokens: type: integer graduated: type: integer bonding_rate: type: number nullable: true runners: type: integer runner_rate: type: number best_peak_mc_usd: type: number nullable: true launchpads: type: array items: type: string first_deploy_at: type: string format: date-time nullable: true last_deploy_at: type: string format: date-time nullable: true tier: type: string enum: - elite - good - neutral - spammer recent_tokens: type: array description: Up to 50 most recent tokens by this deployer. items: type: object properties: address: type: string symbol: type: string nullable: true name: type: string nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true graduated_at: type: string format: date-time nullable: true graduated_pool: type: string nullable: true first_seen_at: type: string format: date-time nullable: true market_cap_usd: type: number nullable: true description: Live market cap. peak_mc_usd: type: number nullable: true description: All-time-high MC observed since ingestion. peak_mc_at: type: string format: date-time nullable: true recent_tokens_count: type: integer description: Rows returned (capped at 50) — the true total is deployer.tokens_deployed. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterByAddress x-operation-id-source: derived /rhc/deployer-hunter/{address}/history: get: tags: - Robinhood Chain summary: Deployer token-deploy history on Robinhood Chain (PRO+) description: 'A deployer''s full **token-deploy history** on Robinhood Chain: their `mv_rhc_deployers` reputation row plus every token they''ve deployed (paginated, newest first) enriched with live and peak MC. Note: RHC has no per-day reputation snapshot table, so this is a token-deploy history, not a daily tier/rate time-series. Unknown addresses return 200 with `is_deployer: false`. Tier: **PRO+** (the point-in-time `/rhc/deployer-hunter/{address}` profile stays BASIC).' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Deployer EVM wallet address (0x, 40 hex). - name: limit in: query schema: type: integer minimum: 1 maximum: 1000 default: 100 - name: offset in: query schema: type: integer minimum: 0 maximum: 100000 default: 0 responses: '200': description: OK. `total` is the deployer's full token count; page with limit/offset until `has_more` is false. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood is_deployer: type: boolean description: False if this wallet has never deployed a tracked token (deployer/tokens then empty). address: type: string description: Lowercased 0x deployer address. deployer: type: object nullable: true properties: deployer_address: type: string tokens_deployed: type: integer graduated: type: integer graduation_rate: type: number description: Share of tokens that reached a $40K+ peak MC. runners: type: integer runner_rate: type: number description: Share of tokens that reached $100K+ peak MC. best_peak_mc_usd: type: number nullable: true launchpads: type: array items: type: string first_deploy_at: type: string format: date-time nullable: true last_deploy_at: type: string format: date-time nullable: true tier: type: string enum: - elite - good - neutral - spammer tokens: type: array description: This page of the deployer's tokens, newest first. items: type: object properties: address: type: string symbol: type: string nullable: true name: type: string nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true graduated_at: type: string format: date-time nullable: true graduated_pool: type: string nullable: true first_seen_at: type: string format: date-time nullable: true market_cap_usd: type: number nullable: true description: Live market cap. peak_mc_usd: type: number nullable: true description: All-time-high MC observed since ingestion. peak_mc_at: type: string format: date-time nullable: true total: type: integer limit: type: integer offset: type: integer has_more: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address or query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcDeployerHunterByAddressHistory x-operation-id-source: derived /rhc/deployer-hunter/{address}/trajectory: get: tags: - Robinhood Chain summary: Is this RHC deployer getting better or worse? (BASIC+) description: 'Streak, rolling-rate and trend shape for one Robinhood Chain deployer, so you can tell a deployer on the way up from one coasting on old hits. Field names keep the Solana `bond` wording for drop-in compatibility, but `success_metric` states what was actually counted: the **$40K graduation**, deliberately NOT the $100K tier bar — $100K is rare enough that most deployers would return an all-zero curve. Unknown wallets return 200 with `is_deployer: false` (never a 404). Tier: **BASIC**.' parameters: - name: address in: path required: true schema: type: string description: Deployer wallet (0x, case-insensitive). responses: '200': description: OK. `truncated` is true when the deployer has more launches than the 500-token analysis cap. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood is_deployer: type: boolean address: type: string deployer: type: object nullable: true success_metric: type: string example: graduated ($40K+ peak market cap) trajectory: type: object nullable: true properties: current_streak: type: object properties: type: type: string enum: - bond - fail - none count: type: integer longest_bond_streak: type: integer longest_fail_streak: type: integer rolling_bond_rates: type: array items: type: object properties: window_end: type: integer bond_rate: type: number description: 10-launch rolling hit rate. trend: type: string enum: - improving - declining - stable avg_days_between_deploys: type: number nullable: true avg_recovery_tokens: type: number nullable: true description: Launches burned between a miss and the next hit. best_stretch: type: object nullable: true worst_stretch: type: object nullable: true total_tokens_analyzed: type: integer truncated: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterByAddressTrajectory x-operation-id-source: derived /rhc/deployer-hunter/{address}/tokens: get: tags: - Robinhood Chain summary: Full paginated launch history for one RHC deployer (BASIC+) description: 'Every token a Robinhood Chain deployer has launched, enriched with live MC, peak MC and liquidity. Each token carries `liquidity_basis` (`v4_virtual_ceiling` | `measured`) — uniswap-v4 liquidity_usd is a virtual-reserve ceiling, not measured per-pool TVL. Distinct from `/rhc/deployer-hunter/{address}`, which caps `recent_tokens` at 50 and is a profile read — this is the enumerable history. Unknown wallets return 200 with `is_deployer: false`. Tier: **BASIC**.' parameters: - name: address in: path required: true schema: type: string - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 50 - name: offset in: query schema: type: integer minimum: 0 maximum: 10000 default: 0 - name: sort in: query schema: type: string enum: - first_seen_at - peak_mc_usd default: first_seen_at description: '`peak_mc_usd` sorts the RETURNED PAGE only (peak MC lives in another table) — the response echoes `sort_scope: "page"` so it cannot be mistaken for a global ranking.' responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood is_deployer: type: boolean address: type: string deployer: type: object nullable: true tokens: type: array items: type: object total: type: integer description: Lifetime launch count (not the page size). limit: type: integer offset: type: integer has_more: type: boolean sort: type: string sort_scope: type: string enum: - page headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address or query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterByAddressTokens x-operation-id-source: derived /rhc/deployer-hunter/best-tokens: get: tags: - Robinhood Chain summary: Top launches from reputable RHC deployers (BASIC+) description: 'The highest-peaking tokens launched by good/elite Robinhood Chain deployers in a window — "what did the deployers worth tracking actually produce". Gated on tier by design; for an unfiltered ranking use `/rhc/tokens?sort=peak_mc_usd`. Each token carries `liquidity_basis` (`v4_virtual_ceiling` | `measured`) — uniswap-v4 liquidity_usd is a virtual-reserve ceiling, not measured per-pool TVL. `truncated: true` means the window exceeded the 1,000-candidate scan, so the top-N is drawn from the most RECENT launches rather than the whole period. Tier: **BASIC**.' parameters: - name: period in: query schema: type: string enum: - 24h - 7d - 30d - all default: 7d - name: limit in: query schema: type: integer minimum: 1 maximum: 50 default: 10 responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood tokens: type: array items: type: object period: type: string limit: type: integer reputable_deployers: type: integer candidates_scanned: type: integer truncated: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterBestTokens x-operation-id-source: derived /rhc/deployer-hunter/stats: get: tags: - Robinhood Chain summary: Chain-wide RHC deployer reputation census (BASIC+) description: 'Population and token count per reputation tier across Robinhood Chain, plus alert volume. `tier_rules` echoes the ACTIVE thresholds so a consumer can see what "elite" currently means instead of inferring it from the label. Tier: **BASIC**.' responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood total_deployers: type: integer total_tokens: type: integer reputable_deployers: type: integer description: elite + good. by_tier: type: object additionalProperties: type: object properties: deployers: type: integer tokens: type: integer spam_token_share: type: number nullable: true alerts_24h: type: integer alerts_7d: type: integer tier_rules: type: object description: The live tier CASE, e.g. elite = "tokens_deployed >= 5 AND runner_rate >= 0.50". graduation_definition: type: string example: peak market cap >= $40,000 runner_definition: type: string example: peak market cap >= $100,000 headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcDeployerHunterStats x-operation-id-source: derived /rhc/token/batch: post: tags: - Robinhood Chain summary: Up to 50 Robinhood Chain tokens in one call (BASIC+) description: 'Set-based batch read — three queries regardless of batch size, not a fan-out. Returns token metadata, price/MC/liquidity and deployer reputation. Deliberately does NOT compute buyer-quality (that is a per-token cohort computation; use `/rhc/tokens/batch/buyer-quality`) so a caller who only wants prices does not pay for it. Accepts `addresses` or `mints` so a ported Solana client works unchanged. **One entry is returned per REQUESTED address, in order** — unknown tokens come back as `found: false` rather than being silently omitted. Tier: **BASIC**.' requestBody: required: true content: application/json: schema: type: object properties: addresses: type: array items: type: string minItems: 1 maxItems: 50 description: 0x EVM token addresses. mints: type: array items: type: string description: Alias for `addresses` (Solana-client compatibility). responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood tokens: type: array items: type: object properties: address: type: string found: type: boolean status: type: string enum: - ok - no_price_yet - mc_unavailable - not_seen_yet description: 'Why a price field is null: no_price_yet (seen, no priced trade yet), mc_unavailable (priced, MC failed the plausibility gate or supply unknown), not_seen_yet (found:false).' hint: type: string description: found:false only. symbol: type: string nullable: true name: type: string nullable: true decimals: type: integer nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true graduated_at: type: string format: date-time nullable: true first_seen_at: type: string format: date-time nullable: true price_usd: type: number nullable: true market_cap_usd: type: number nullable: true fdv_usd: type: number nullable: true liquidity_usd: type: number nullable: true peak_mc_usd: type: number nullable: true peak_mc_at: type: string format: date-time nullable: true primary_dex: type: string nullable: true last_trade_time: type: string format: date-time nullable: true deployer: type: object nullable: true description: address + source, plus the deployer's reputation row (tier, tokens_deployed, graduated, graduation_rate, runners, runner_rate) when known. requested: type: integer found: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: 'Body must be { addresses: string[] } with 1-50 valid 0x addresses.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: postRhcTokenBatch x-operation-id-source: derived /rhc/tokens/batch/buyer-quality: post: tags: - Robinhood Chain summary: Early-buyer quality for up to 20 RHC tokens (BASIC+) description: 'Scores several tokens'' earliest-buyer cohorts in one call. **The cap is 20, not the Solana 50** — RHC buyer-quality is a per-token cohort computation (ordered early-buyer scan + bundle RPC + alpha/cluster joins) that cannot collapse into one set-based query, so 50 would mean ~200 round-trips behind a single request. A per-token failure degrades to an `error` entry rather than failing the batch. Scores are identical to the single-token endpoint (shared scorer). Tier: **BASIC**.' requestBody: required: true content: application/json: schema: type: object properties: addresses: type: array items: type: string minItems: 1 maxItems: 20 mints: type: array items: type: string description: Alias for `addresses`. responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood tokens: type: array items: type: object description: Either a scored result or `{ token_address, error }`. requested: type: integer scored: type: integer max_addresses: type: integer example: 20 coverage: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: 'Body must be { addresses: string[] } with 1-20 valid 0x addresses. Response echoes `max_addresses`.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: postRhcTokensBatchBuyerQuality x-operation-id-source: derived /rhc/token/{address}: get: tags: - Robinhood Chain summary: Alias of /rhc/tokens/{address} (BASIC+) description: 'Path alias so a Solana integration ported to Robinhood Chain does not 404 on a capability we ship. Solana exposes the single-token read at `/token/{mint}` (SINGULAR); the RHC tree uses `/rhc/tokens/{address}` (plural). Identical handler and response — not a redirect. Tier: **BASIC**.' parameters: - name: address in: path required: true schema: type: string responses: '200': description: Identical to `/rhc/tokens/{address}`. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string symbol: type: string nullable: true name: type: string nullable: true decimals: type: integer nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true graduated_pool: type: string nullable: true graduated_at: type: string format: date-time nullable: true deployer_address: type: string nullable: true first_seen_at: type: string format: date-time nullable: true token_age_minutes: type: integer nullable: true price_usd: type: number nullable: true price_native: type: number nullable: true market_cap_usd: type: number nullable: true fdv_usd: type: number nullable: true peak_mc_usd: type: number nullable: true peak_mc_at: type: string format: date-time nullable: true drawdown_from_peak_pct: type: integer nullable: true total_supply_raw: type: string nullable: true liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: How liquidity_usd was derived. uniswap-v4 has no per-pool balances, so its figure is virtual reserves clamped to the PoolManager's total holdings — a provable CEILING, not measured per-pool TVL. liquidity_note: type: string description: Human-readable statement of the uniswap-v4 ceiling semantics; constant. primary_dex: type: string nullable: true primary_pool: type: string nullable: true last_trade_time: type: string format: date-time nullable: true deployer: type: object nullable: true description: Deployer reputation. properties: address: type: string tier: type: string enum: - elite - good - neutral - spammer tokens_deployed: type: integer graduation_rate: type: number nullable: true runner_rate: type: number nullable: true runners: type: integer best_peak_mc_usd: type: number nullable: true launchpads: type: array items: type: string deployer_other_tokens: type: array items: type: string description: Up to 10 other tokens by the same deployer (symbol or address). kol_activity: type: object properties: distinct_kols: type: integer names: type: array items: type: string buys: type: integer sells: type: integer net_eth: type: number pools: type: array description: Up to 20 pools with reserves/liquidity/sqrt_price. Each entry carries `liquidity_basis` (`v4_virtual_ceiling` | `measured`) for its own `liquidity_usd`. items: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcTokenByAddress x-operation-id-source: derived /rhc/lp-events: get: tags: - Robinhood Chain summary: Liquidity REMOVALS feed — the rug signal (PRO+) description: 'Liquidity removals on Robinhood Chain from our own node''s log subscription: Uniswap v2/v3 Burn and v4 ModifyLiquidity with a negative delta, for tracked pools. **By default removals only** — a request without `action` returns exactly what it always did, so an empty default page means ''no removals seen'', never ''no liquidity activity''. Amounts are RAW on-chain integers as strings; token0/token1 say which side is which and token_amount_raw/quote_amount_raw pre-resolve the token side. v4 rows carry liquidity only (the pool manager emits no token amounts). provider_is_token_deployer is the classic rug tell. Cursor via next_before (same opaque (block_time,id) keyset as /rhc/trades). Data since 2026-08-05. **Adds, pool creations and depth fields (2026-09-23):** `action=add|pool_created|all` opts into liquidity adds (v2/v3 Mint, v4 positive ModifyLiquidity; kept 7 days) and live pool creations (kept 30 days like removals), persisted since the WS Phase 3 producer — earlier windows hold removals only. Every row also carries `tick_lower`, `tick_upper`, `liquidity_delta`, `in_range`, `active_liquidity_delta`, `active_share` (v3/v4, a share of liquidity at the current price, not of TVL), `share_of_reserves` (v2) and `material` (a removal of at least 25 % of reserves / active liquidity), null where the pool state was unknown and on older rows. `provider` is the log''s sender/owner — usually the router or position manager on v3/v4, not the beneficial owner. The same events are pushed live on WS channel `rhc:lp_events` (ULTRA+). Tier: **PRO+**.' parameters: - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 description: Rows per page (1-200, default 50). - name: token in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Filter to one token address. - name: pool in: query schema: type: string description: Pool address (v2/v3) or bytes32 poolId (v4). - name: provider in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Filter to one liquidity provider (the wallet that pulled). - name: dex in: query schema: type: string enum: - uniswap-v2 - uniswap-v3 - uniswap-v4 - name: action in: query schema: type: string enum: - remove - add - pool_created - all default: remove description: Which liquidity actions to return (2026-09-23). Default `remove` = the historical removals-only feed, unchanged. `add` (kept 7 days), `pool_created` or `all` opt into the rows persisted since the WS Phase 3 producer. - name: before in: query schema: type: string description: Opaque cursor from next_before. responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood events: type: array items: type: object properties: event: type: string enum: - remove - add - pool_created description: The row's action. Always `remove` on a request without `action`. pool: type: string dex: type: string enum: - uniswap-v2 - uniswap-v3 - uniswap-v4 fee_tier: type: integer nullable: true token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true token_decimals: type: integer nullable: true launchpad: type: string nullable: true provider: type: string nullable: true description: Wallet that removed liquidity. provider_is_token_deployer: type: boolean description: True when the provider is the token's own deployer — the classic rug shape. provider_deployer_tier: type: string nullable: true provider_kol_name: type: string nullable: true liquidity: type: string nullable: true description: Raw liquidity units removed (v3/v4). String — uint256. amount0: type: string nullable: true description: Raw token0 amount (v2/v3 only). String. amount1: type: string nullable: true description: Raw token1 amount (v2/v3 only). String. token0: type: string nullable: true token1: type: string nullable: true token_amount_raw: type: string nullable: true description: amount0 or amount1, whichever is the token side. quote_token: type: string nullable: true quote_amount_raw: type: string nullable: true block_number: type: integer block_time: type: string format: date-time description: Exact block header timestamp. tx_hash: type: string log_index: type: integer tick_lower: type: integer nullable: true description: Position range lower tick (v3/v4); null on v2 (full range) and on rows written before 2026-09-23. tick_upper: type: integer nullable: true description: Position range upper tick (v3/v4). liquidity_delta: type: string nullable: true description: Signed liquidity change (+ add, - remove), v3/v4. String — int256. in_range: type: boolean nullable: true description: tick_lower <= current tick < tick_upper just before the event; null when the pool's tick was unknown. active_liquidity_delta: type: string nullable: true description: 'Change to ACTIVE liquidity: liquidity_delta when in range, "0" out of range, null when unknown.' active_share: type: number nullable: true description: '|active delta| / active liquidity before (v3/v4). 0 for an out-of-range change; adds can exceed 1; null when unknown.' share_of_reserves: type: number nullable: true description: 'v2 only: amount / reserve before, from the pair''s Sync; null for a pair''s first liquidity or when the Sync was not found.' material: type: boolean nullable: true description: true = a REMOVAL of at least 25 % of reserves (v2) or active liquidity (v3/v4); false = a removal with a known smaller share; null for adds, pool creations and unknown shares. count: type: integer has_more: type: boolean next_before: type: string nullable: true coverage: type: object description: 'Honesty block: events (the actions this response covers — [remove] by default), adds_persisted (true since 2026-09-23), adds_retention_days (7), note, since.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters (code invalid_query). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcLpEvents x-operation-id-source: derived /rhc/tokens/locks: get: tags: - Robinhood Chain summary: Token locks & vesting feed — newest lock contracts across all tokens (PRO+) description: 'Newest token lock / vesting contracts CREATED on Robinhood Chain, newest first: who just locked tokens, of what, how much, until when. Decoded from the locker contracts'' own events on our node (services/rhc-lock-tracker, chain-wide topic0 probe with no address filter — a new deployment of a known locker shape is caught on first sight): PinkLock-compatible, HoodLock (+ vesting), Team Finance-compatible (+ LP NFT), Titan Locker (token / LP / position), UNCX v2/v3-compatible LP lockers, Sablier Lockup v4 (linear / tranched / dynamic). Every row carries the on-chain schedule (start / cliff / end, cliff amount, tranches) and a live derived view: `locked_*` (still locked right now), `unlocked_*`, `next_unlock` (cliff | final | tranche), `status`; `sender` is the depositor/creator (compare with the token''s deployer for a dev lock), `recipient` the beneficiary when different; `cancelable` / `cancelable_by_sender` from Sablier''s flag (null where the family does not say). Amounts are RAW base units as strings; ui/usd/pct are null when decimals/price are unknown. **Create-only tape**: withdrawals / cancels are NOT tracked (no RHC locker publishes a verified release event shape) — `withdrawn` is null (unknown), never 0, and the `coverage` block says `withdrawals_tracked: false`. LP locks (subject=lp — RHC launchpads auto-lock LP on every launch) are stored but excluded unless `subject=lp|all`, carry pair/liquidity units and never claim usd/pct. Cursor: `cursor=` (`pagination.next_cursor`, strict (created_at, id) — preferred), `since=` (`pagination.next_since`) / legacy `before=`. The status / min_usd / min_pct_of_supply post-filters are served by a bounded scan (`pagination.scan`). Pushed live as `rhc:token_lock` on WS channel `rhc:token_locks`. Tier: **PRO+**.' parameters: - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 50 - name: since in: query schema: type: string format: date-time description: Only locks created after this instant (poll cursor = pagination.next_since). - name: before in: query schema: type: string format: date-time description: 'Legacy: only locks created strictly before this instant (page back = pagination.next_before; skips locks sharing that created_at — prefer cursor).' - name: cursor in: query schema: type: string maxLength: 200 description: 'PREFERRED pagination (audit F09 follow-up): the `next_cursor` from a previous page — an opaque strict (created_at, id) keyset, so paging never repeats or skips rows that share a sort value and progresses with limit=1 through runs of identical timestamps. Malformed or tampered → 400. Cannot be combined with `before=` (400).' - name: token in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ - name: sender in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Depositor / creator wallet. - name: recipient in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Beneficiary wallet. - name: locker in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Locker contract address. - name: family in: query schema: type: string enum: - pinklock - teamfinance - teamfinance-nft - uncx-v2-lp - uncx-v3-lp - uncx-vesting - vesting-fork - goplus - titan - titan-position - titan-vesting - hoodlock - hoodlock-vesting - sablier - name: kind in: query schema: type: string enum: - lock - vesting - name: subject in: query schema: type: string enum: - token - lp - all default: token description: token (default) excludes LP locks; lp = only LP locks; all = both. - name: status in: query schema: type: string enum: - active - completed - name: min_usd in: query schema: type: number minimum: 0 description: Post-filter on the deposited amount in USD (bounded scan — see pagination.scan). - name: min_pct_of_supply in: query schema: type: number minimum: 0 maximum: 100 description: Post-filter on the deposited amount as % of supply. responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood locks: type: array items: type: object properties: lock_id: type: string description: '`:` — the row identity.' locker: type: string locker_name: type: string nullable: true provider: type: object description: 'Who runs the lock contract, and how sure we are. identity: verified = a known provider deployment (by contract address); compatible = only the event shape (ABI) matches a known provider, the operator is NOT identified; unverified = unknown. id/website_url are null unless verified. lock_url is a per-lock page on the provider''s site, emitted ONLY where the URL format is proven (HoodLock vault: /proof/lock/{locker_lock_id}); otherwise null (never guessed).' properties: id: type: string nullable: true name: type: string nullable: true identity: type: string enum: - verified - compatible - unverified compatible_with: type: string nullable: true website_url: type: string nullable: true lock_url: type: string nullable: true explorer: type: object description: Independent evidence on Blockscout. properties: locker_url: type: string nullable: true creation_tx_url: type: string nullable: true price_usd: type: number nullable: true description: Token price used for the *_usd fields (null when unknown or guarded as phantom). seconds_until_end: type: integer nullable: true description: Seconds until fully unlocked (>= 0). 0 once completed; null when there is no end date (perpetual) or the lock was cancelled/closed. seconds_until_next_unlock: type: integer nullable: true description: Seconds until next_unlock.at (>= 0); null when there is no next unlock. family: type: string family_name: type: string locker_lock_id: type: string nullable: true kind: type: string enum: - lock - vesting subject: type: string enum: - token - lp status: type: string enum: - active - completed token_address: type: string lp: type: object nullable: true description: 'Only on subject=lp: kind (v2_pair | v3_position | v4_position), pool, token0, token1, token_id.' sender: type: string description: Depositor / creator — the dev-lock comparison key. recipient: type: string nullable: true tx_sender: type: string nullable: true name: type: string nullable: true amount_raw: type: string nullable: true amount: type: number nullable: true amount_usd: type: number nullable: true amount_pct_of_supply: type: number nullable: true amount_unit: type: string nullable: true description: token | lp_token | liquidity (uncx-v3) — LP rows never claim usd/pct. locked_raw: type: string nullable: true locked: type: number nullable: true locked_usd: type: number nullable: true locked_pct_of_supply: type: number nullable: true unlocked_raw: type: string nullable: true unlocked: type: number nullable: true withdrawn_raw: type: string nullable: true description: Always null — withdrawals are not tracked on RHC. withdrawn: type: number nullable: true start_at: type: string nullable: true cliff_at: type: string nullable: true end_at: type: string nullable: true cliff_amount_raw: type: string nullable: true cliff_amount: type: number nullable: true continuous: type: boolean description: Linear per-second release between cliff and end. perpetual: type: boolean schedule: type: array nullable: true description: 'Tranches (Sablier tranched/dynamic): release_at, amount_raw, amount.' items: type: object next_unlock: type: object nullable: true description: at, kind (cliff | final | tranche), amount_raw, amount, amount_usd. cancelable: type: boolean nullable: true cancelable_by_sender: type: boolean nullable: true transferable: type: boolean nullable: true created_at: type: string format: date-time description: = block_time of the creation event. created_at_estimated: type: boolean description: Always false on RHC. block_number: type: integer block_time: type: string format: date-time tx_hash: type: string log_index: type: integer layout_verified: type: boolean description: false only for families decoded from published source without a live log yet (titan-vesting). token: type: object properties: symbol: type: string nullable: true name: type: string nullable: true decimals: type: integer nullable: true price_usd: type: number nullable: true market_cap_usd: type: number nullable: true liquidity_usd: type: number nullable: true pagination: type: object properties: limit: type: integer count: type: integer has_more: type: boolean description: false only when the candidate feed is exhausted (not merely when the page is short). next_cursor: type: string nullable: true description: Opaque keyset cursor for the next (older) page — pass as `cursor=`. null = end of feed. PREFERRED over the strict-timestamp legacy cursor, which skips same-timestamp siblings of the boundary row. next_since: type: string nullable: true next_before: type: string nullable: true description: 'Legacy: created_at of the last row consumed (strict bound — skips ties).' scan: type: object description: 'Present when a filter had to be applied after the candidate fetch (audit F09): has_more is then false only when the candidates ran out, and scan_truncated=true means the per-request scan budget ran out first — more matches MAY exist past next_cursor.' properties: post_filtered: type: boolean scanned: type: integer description: Candidate rows examined scan_truncated: type: boolean description: The per-request scan budget ran out before `limit` matches — more matches MAY exist past the cursor/offset scan_budget: type: integer stream: type: object description: 'WS pointer: channel rhc:token_locks, event rhc:token_lock.' coverage: type: object description: 'Honesty block: families, withdrawals_tracked false, cancels_tracked false, lp_locks, note.' meta: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters (code invalid_query). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensLocks x-operation-id-source: derived /rhc/tokens/{address}/locks: get: tags: - Robinhood Chain summary: Token locks & vesting on one token — live locked / next unlock / 7d & 30d… description: 'Every lock / vesting contract on one Robinhood Chain token with a live derived view: what is still locked right now (deposited − unlocked-so-far by the schedule), what unlocks next, the 7d / 30d unlock schedule and whether the locker can cancel — ''did the team lock, how much, until when''. `summary` covers the token-subject rows (counts by family / kind, distinct depositing wallets and locker contracts, locked / deposited raw + ui + usd + % of supply, `unlocking_7d_*` / `unlocking_30d_*`, nearest `next_unlock`, `active_cancelable_by_sender`); LP locks on the token''s pools are listed under subject=lp and counted apart (`lp_lock_count`, `lp_lock_active_count`) because their amounts are pair / liquidity units. Rows are active-first, largest locked first. `token.facts_resolved` is false when decimals are unknown — every ui / usd / pct field is then null. Same create-only caveat as the feed (`coverage.withdrawals_tracked: false`): an unlocked-but-unclaimed balance counts as unlocked. Tier: **PRO+**.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ - name: status in: query schema: type: string enum: - active - completed - name: family in: query schema: type: string - name: subject in: query schema: type: string enum: - token - lp - all default: all - name: limit in: query schema: type: integer minimum: 1 maximum: 500 default: 200 description: Rows returned; the summary always covers every row on the token (up to 5000). responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood token_address: type: string token: type: object properties: symbol: type: string nullable: true name: type: string nullable: true decimals: type: integer nullable: true price_usd: type: number nullable: true supply: type: number nullable: true market_cap_usd: type: number nullable: true liquidity_usd: type: number nullable: true facts_resolved: type: boolean summary: type: object properties: lock_count: type: integer complete: type: boolean rows_considered: type: integer token_lock_count: type: integer lp_lock_count: type: integer lp_lock_active_count: type: integer active_count: type: integer by_family: type: object by_kind: type: object distinct_lockers: type: integer distinct_locker_contracts: type: integer locked_raw: type: string locked: type: number nullable: true locked_usd: type: number nullable: true locked_pct_of_supply: type: number nullable: true deposited_raw: type: string deposited: type: number nullable: true deposited_usd: type: number nullable: true unlocking_7d_raw: type: string unlocking_7d: type: number nullable: true unlocking_7d_usd: type: number nullable: true unlocking_7d_pct_of_supply: type: number nullable: true unlocking_30d_raw: type: string unlocking_30d: type: number nullable: true unlocking_30d_usd: type: number nullable: true unlocking_30d_pct_of_supply: type: number nullable: true next_unlock: type: object nullable: true active_cancelable_by_sender: type: integer locks: type: array items: type: object description: Same row shape as /rhc/tokens/locks (without the token embed). coverage: type: object meta: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid address (code invalid_address) or query (code invalid_query). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressLocks x-operation-id-source: derived /rhc/tokens/unlocks: get: tags: - Robinhood Chain summary: Upcoming unlock events across all active RHC lock / vesting contracts (PRO+) description: 'Upcoming unlock EVENTS on Robinhood Chain — each active token lock / vesting contract''s NEXT cliff, tranche or final unlock inside the window: which tokens have supply hitting the market this week, how much, from whose lock. `amount_*` is the next event, `window_amount_*` that contract''s total release over the whole window; linear per-second streams (Sablier linear, HoodLock / Titan vesting) contribute cliff / final events only. Token subject only (LP locks excluded). Candidates come off the writer-maintained `next_unlock_at` column (rolled forward every 2 min) so every active contract is considered per call; 60 s in-process cache with the window quantised to the same bucket. Prices with an implied market cap above $100B are treated as phantom → usd null. Tier: **PRO+**.' parameters: - name: within in: query schema: type: string enum: - 1h - 6h - 24h - 3d - 7d - 14d - 30d - 90d default: 7d - name: token in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ - name: family in: query schema: type: string - name: kind in: query schema: type: string enum: - lock - vesting - name: min_usd in: query schema: type: number minimum: 0 description: On the next-event amount. - name: min_pct_of_supply in: query schema: type: number minimum: 0 maximum: 100 description: On the next-event amount. - name: sort in: query schema: type: string enum: - soonest - largest_usd - largest_pct default: soonest - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood window: type: object properties: within: type: string from: type: string format: date-time to: type: string format: date-time unlocks: type: array items: type: object properties: unlock_at: type: string format: date-time in_seconds: type: integer event: type: string enum: - cliff - final - tranche amount_raw: type: string amount: type: number nullable: true amount_usd: type: number nullable: true amount_pct_of_supply: type: number nullable: true window_amount_raw: type: string window_amount: type: number nullable: true window_amount_usd: type: number nullable: true window_amount_pct_of_supply: type: number nullable: true token_address: type: string token: type: object lock: type: object description: lock_id, locker, locker_name, family, kind, name, sender, recipient, amount_*, locked_*, cliff_at, end_at, cancelable_by_sender, tx_hash. pagination: type: object properties: limit: type: integer count: type: integer total_in_window: type: integer has_more: type: boolean candidates_capped: type: boolean coverage: type: object meta: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters (code invalid_query). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensUnlocks x-operation-id-source: derived /rhc/tokens/{address}/lp-events: get: tags: - Robinhood Chain summary: Alias of /rhc/lp-events?token= (PRO+) description: 'Path alias: liquidity removals for one token. Delegates to /rhc/lp-events with token pinned to the path segment; pagination, enrichment and the removals-only honesty block are identical. Tier: **PRO+**.' parameters: - name: address in: path required: true schema: type: string - name: limit in: query schema: type: integer - name: before in: query schema: type: string - name: dex in: query schema: type: string enum: - uniswap-v2 - uniswap-v3 - uniswap-v4 - name: action in: query schema: type: string enum: - remove - add - pool_created - all default: remove description: 'Same as on /rhc/lp-events: default `remove` (unchanged), or opt into adds / pool creations (2026-09-23).' responses: '200': description: Identical to /rhc/lp-events?token={address}. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood events: type: array items: type: object properties: event: type: string enum: - remove - add - pool_created description: The row's action. Always `remove` on a request without `action`. pool: type: string dex: type: string enum: - uniswap-v2 - uniswap-v3 - uniswap-v4 fee_tier: type: integer nullable: true token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true token_decimals: type: integer nullable: true launchpad: type: string nullable: true provider: type: string nullable: true description: Wallet that removed liquidity. provider_is_token_deployer: type: boolean description: True when the provider is the token's own deployer — the classic rug shape. provider_deployer_tier: type: string nullable: true provider_kol_name: type: string nullable: true liquidity: type: string nullable: true description: Raw liquidity units removed (v3/v4). String — uint256. amount0: type: string nullable: true description: Raw token0 amount (v2/v3 only). String. amount1: type: string nullable: true description: Raw token1 amount (v2/v3 only). String. token0: type: string nullable: true token1: type: string nullable: true token_amount_raw: type: string nullable: true description: amount0 or amount1, whichever is the token side. quote_token: type: string nullable: true quote_amount_raw: type: string nullable: true block_number: type: integer block_time: type: string format: date-time description: Exact block header timestamp. tx_hash: type: string log_index: type: integer tick_lower: type: integer nullable: true description: Position range lower tick (v3/v4); null on v2 (full range) and on rows written before 2026-09-23. tick_upper: type: integer nullable: true description: Position range upper tick (v3/v4). liquidity_delta: type: string nullable: true description: Signed liquidity change (+ add, - remove), v3/v4. String — int256. in_range: type: boolean nullable: true description: tick_lower <= current tick < tick_upper just before the event; null when the pool's tick was unknown. active_liquidity_delta: type: string nullable: true description: 'Change to ACTIVE liquidity: liquidity_delta when in range, "0" out of range, null when unknown.' active_share: type: number nullable: true description: '|active delta| / active liquidity before (v3/v4). 0 for an out-of-range change; adds can exceed 1; null when unknown.' share_of_reserves: type: number nullable: true description: 'v2 only: amount / reserve before, from the pair''s Sync; null for a pair''s first liquidity or when the Sync was not found.' material: type: boolean nullable: true description: true = a REMOVAL of at least 25 % of reserves (v2) or active liquidity (v3/v4); false = a removal with a known smaller share; null for adds, pool creations and unknown shares. count: type: integer has_more: type: boolean next_before: type: string nullable: true coverage: type: object description: 'Honesty block: events (the actions this response covers — [remove] by default), adds_persisted (true since 2026-09-23), adds_retention_days (7), note, since.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressLpEvents x-operation-id-source: derived /rhc/tokens/{address}/trades: get: tags: - Robinhood Chain summary: Alias of /rhc/trades?token= (PRO+) description: 'Path alias: Solana exposes per-token trades as a SUBPATH (`/tokens/{mint}/trades`) while RHC exposes it as a FILTER on the trade tape. Delegates to `/rhc/trades` with `token` pinned to the path segment, so pagination, enrichment and gating stay identical. A caller-supplied `token` query param is overridden by the path. Tier: **PRO+** (inherits the /rhc/trades gate — BASIC gets 403).' parameters: - name: address in: path required: true schema: type: string - name: limit in: query schema: type: integer - name: before in: query schema: type: string description: Opaque cursor from next_before; a bare ISO block_time is also accepted for backward compatibility. - name: action in: query schema: type: string enum: - buy - sell responses: '200': description: Identical to `/rhc/trades?token={address}`. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood trades: type: array items: type: object properties: block_number: type: integer block_time: type: string format: date-time tx_hash: type: string log_index: type: integer dex: type: string pool: type: string trader: type: string nullable: true description: Swap-log recipient — the ROUTER for aggregated swaps. Use trader_eoa for wallet analytics. trader_eoa: type: string nullable: true description: Authoritative trader wallet. Normally tx.from; on ERC-4337 transactions this is the userOp sender (the account that actually traded) and tx.from — the bundler — is not returned. router: type: string nullable: true description: Router/aggregator contract (tx.to). token_address: type: string nullable: true action: type: string enum: - buy - sell nullable: true eth_amount: type: number nullable: true price_native: type: number nullable: true price_usd: type: number nullable: true mc_usd_at_trade: type: number nullable: true gas_price: type: number nullable: true description: Effective gas price, gwei. tx_index: type: integer nullable: true description: Transaction position within the block (ordering / sandwich detection). method_selector: type: string nullable: true description: 4-byte calldata selector. liquidity: type: number nullable: true description: v3/v4 in-range liquidity at the trade. launchpad: type: string nullable: true is_kol: type: boolean description: True if trader_eoa is a tracked KOL wallet. kol_name: type: string nullable: true deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer description: Set if trader_eoa is a known deployer. count: type: integer has_more: type: boolean description: True when another page exists beyond this one. next_before: type: string nullable: true description: Opaque (block_time, id) keyset cursor for the next page; null when has_more is false. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM token address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcTokensByAddressTrades x-operation-id-source: derived /rhc/kol/tokens/hot: get: tags: - Robinhood Chain summary: Alias of /rhc/kol/hot-tokens (BASIC+) description: 'Path alias matching Solana''s `/kol/tokens/hot`. Identical handler — note it takes `window`, not `limit`. Tier: **BASIC**.' parameters: - name: window in: query schema: type: string default: 1h responses: '200': description: Identical to `/rhc/kol/hot-tokens`. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood window: type: string enum: - 5m - 15m - 1h - 6h - 24h tokens: type: array items: type: object properties: token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true launchpad: type: string nullable: true description: noxa | flap | pons | hood.fun | clanker | null. is_graduated: type: boolean nullable: true deployer_tier: type: string nullable: true description: elite | good | neutral | spammer | null. kols_buying: type: integer description: Distinct KOL buyers in the window (>= 2). buys: type: integer sells: type: integer buy_eth: type: number net_eth: type: number description: buy_eth − sell_eth. market_cap_usd: type: number nullable: true description: Current market cap. last_trade_at: type: string format: date-time count: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: FREE x-badges: - name: FREE position: after color: '#64748b' operationId: getRhcKolTokensHot x-operation-id-source: derived /rhc/alpha/leaderboard: get: tags: - Robinhood Chain summary: Alias of /rhc/alpha-wallets (PRO+) description: 'Path alias matching Solana''s `/alpha/leaderboard`. Identical handler, including the PRO+ gate. Tier: **PRO**.' responses: '200': description: Identical to `/rhc/alpha-wallets`. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood wallets: type: array items: type: object properties: wallet: type: string description: Trader EOA (lowercase 0x). classification: type: string enum: - bot - smart_money - trader is_known_kol: type: boolean trades: type: integer tokens: type: integer buy_eth: type: number sell_eth: type: number net_eth: type: number description: Realized net flow (sell − buy). win_rate: type: number nullable: true memecoin_share: type: number nullable: true description: Share of trades in launchpad memecoins (vs tokenized stocks/stables). avg_trade_mc_usd: type: number nullable: true last_trade_at: type: string format: date-time nullable: true zero_cost_share: type: number nullable: true description: Share of gross ETH extracted from tokens with no recorded buy (deployer/insider dumps). Null = never sold. ≥0.5 wallets are excluded unless include_zero_cost_dumps=true. total: type: integer limit: type: integer offset: type: integer has_more: type: boolean attribution: type: object description: 'Interim attribution disclosure: mv_rhc_alpha_wallets is built 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 in win_rate/net_eth/classification. Removed once the trader_eoa backfill lands.' properties: attribution_complete_from: type: string format: date-time note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': description: PRO+ tier required. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcAlphaLeaderboard x-operation-id-source: derived /rhc/alpha-wallets: get: tags: - Robinhood Chain summary: Smart-money wallet ranking on Robinhood Chain (PRO+) description: 'Robinhood Chain trader wallets ranked by realized on-chain performance — the reverse of KOL discovery: instead of tracing Solana wallets onto RHC, we rank the wallets we already watch trade. `net_eth` is realized net flow (sell − buy, honest about ignoring unrealized holdings); `win_rate` is the share of traded tokens taken out profitably; `likely_bot` flags atomic-arb/MM fleets (near-perfect win rate across many tokens). Because RHC is dual-natured (launchpad memecoins vs tokenized stocks/stables), `memecoin_share` = launchpad-token trade share — filter with `min_memecoin_share` to isolate memecoin traders, or `max_avg_mc_usd` for low-caps. Derived from our self-hosted node, refreshed every 15 min. **Zero-cost-basis dumps, filtered by default** (*added 2026-08-29*): `net_eth` is `sell_eth − buy_eth` per wallet, and for a token a wallet never bought (its own on-chain buy leg unattributed — almost always a deployer/insider allocation sold with no purchase), the whole sale counts as "profit" even though it isn''t trading skill. `zero_cost_share` is the fraction of a wallet''s gross ETH extracted (sell-side) that came from such tokens; wallets at or above 0.5 are excluded from this listing by default (~23% of tracked wallets, concentrated at the very top of a raw net_eth sort) since their ranking and win_rate are inflated by dumps, not performance. The row still exists in the underlying dataset — pass `include_zero_cost_dumps=true` for the unfiltered ranking, and read `zero_cost_share` on each row either way; do not treat a high `net_eth` from this endpoint as trading profit without checking it. Tier: **PRO+**.' parameters: - name: classification in: query schema: type: string enum: - all - human - bot - smart_money default: all description: human = not likely_bot; smart_money = human + net_eth ≥ 2 + win_rate ≥ 0.45. - name: identity in: query schema: type: string enum: - all - known_kol - unknown default: all description: known_kol = already mapped to a tracked Solana KOL; unknown = net-new RHC smart money. - name: min_memecoin_share in: query schema: type: number minimum: 0 maximum: 1 description: Minimum share of trades in launchpad memecoins (0.7 ≈ mostly-memecoin traders). Excludes tokenized-stock/stablecoin traders. - name: max_avg_mc_usd in: query schema: type: number description: Maximum average market cap traded — filter to low-cap degens. - name: min_net_eth in: query schema: type: number - name: min_win_rate in: query schema: type: number minimum: 0 maximum: 1 - name: max_win_rate in: query schema: type: number minimum: 0 maximum: 1 - name: min_trades in: query schema: type: integer minimum: 0 - name: min_tokens in: query schema: type: integer minimum: 0 - name: min_buy_eth in: query schema: type: number description: Minimum ETH deployed (whale/size filter). - name: active_hours in: query schema: type: integer minimum: 1 maximum: 720 description: Only wallets that traded within the last N hours. - name: sort in: query schema: type: string enum: - net_eth - win_rate - trades - tokens - buy_eth - memecoin_share - last_trade_at default: net_eth - name: order in: query schema: type: string enum: - desc - asc default: desc - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 25 - name: offset in: query schema: type: integer minimum: 0 maximum: 10000 default: 0 - name: include_zero_cost_dumps in: query schema: type: boolean default: false description: Include wallets whose net_eth/win_rate are ≥50% inflated by zero-cost-basis dumps (excluded by default — see zero_cost_share). responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood wallets: type: array items: type: object properties: wallet: type: string description: Trader EOA (lowercase 0x). classification: type: string enum: - bot - smart_money - trader is_known_kol: type: boolean trades: type: integer tokens: type: integer buy_eth: type: number sell_eth: type: number net_eth: type: number description: Realized net flow (sell − buy). win_rate: type: number nullable: true memecoin_share: type: number nullable: true description: Share of trades in launchpad memecoins (vs tokenized stocks/stables). avg_trade_mc_usd: type: number nullable: true last_trade_at: type: string format: date-time nullable: true zero_cost_share: type: number nullable: true description: Share of gross ETH extracted from tokens with no recorded buy (deployer/insider dumps). Null = never sold. ≥0.5 wallets are excluded unless include_zero_cost_dumps=true. total: type: integer limit: type: integer offset: type: integer has_more: type: boolean attribution: type: object description: 'Interim attribution disclosure: mv_rhc_alpha_wallets is built 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 in win_rate/net_eth/classification. Removed once the trader_eoa backfill lands.' properties: attribution_complete_from: type: string format: date-time note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcAlphaWallets x-operation-id-source: derived /rhc/wallet/{address}: get: tags: - Robinhood Chain summary: Wallet profile on Robinhood Chain (PRO+) description: 'Any Robinhood Chain wallet''s 90-day trading profile: FIFO cost-basis PnL, per-token breakdown, recent trades, and a reputation block (tracked KOL, known deployer + tier, alpha-ranked, dump-cluster membership, early-buyer count). **Denomination is ETH**, matching the rest of the RHC tree (`eth_amount`, `net_eth`) — not USD. A USD cost basis would silently mix in the tokenized-stock quote assets some flap bonding curves price in. **Sourced from `trader_eoa` — the effective trading account, never the swap-log `trader`**, which is the router address on any aggregated swap. `stats.analyzed_trades + stats.unattributed_trades + stats.unsized_trades === stats.total_trades` always holds — no trade silently vanishes from the accounting. The two exclusions mean different things: **`unattributed_trades`** is swaps with no token side at all (token↔token exotic pools, unclassified pools) and is routine, often large for MM bots; **`unsized_trades`** is a token-side trade whose quantity could not be reconstructed from `rhc_trades`'' raw uint256 leg amounts, which is the actual quality signal and should be ~0. **Attribution floor:** analysis starts at `notes.attribution_complete_from` (2026-07-18) rather than the full 90 days — `trader_eoa` was written for under half of earlier trades, and a partial view produces positions the wallet no longer holds. A wallet exceeding the 50,000-trade analysis cap returns `stats.partial: true`. Heavy wallets that blow the query budget return the reputation block with `stats_unavailable: true` rather than a 500. Responses are cached 60s per address. Tier: **PRO+**.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: EVM wallet address (0x, 40 hex). Case-insensitive; echoed lowercase. responses: '200': description: OK. `stats` is null only when the wallet is known solely through a reputation table (e.g. a deployer that has never traded). content: application/json: schema: type: object properties: chain: type: string enum: - robinhood address: type: string stats: type: object nullable: true properties: first_seen: type: string format: date-time nullable: true last_seen: type: string format: date-time nullable: true total_trades: type: integer analyzed_trades: type: integer description: Trades that entered the FIFO computation. unattributed_trades: type: integer description: Swaps with no token side or direction — token↔token exotic pools and pools our resolver has not classified. Routine, and a large share for MM bots (47% on one 512k-trade fleet wallet). NOT a data-quality signal. unsized_trades: type: integer description: Token-side trades whose QUANTITY could not be reconstructed — excluded from PnL entirely. This IS the quality signal and should be ~0 (measured 0 across a 512k-trade wallet). buys: type: integer sells: type: integer bought_eth: type: number sold_eth: type: number realized_pnl_eth: type: number unrealized_pnl_eth: type: number description: 'Mark-to-market on FIFO-open positions using rhc_token_prices.last_price_native. Unpriced positions contribute 0. **FIFO figure, not a holding**: it includes lots transferred out since the buy. For PnL on what is actually held use `holdings.unrealized_known_eth`.' total_pnl_eth: type: number description: realized_pnl_eth + unrealized_pnl_eth (FIFO). held_value_eth: type: number description: 'FIFO-unmatched DEX buys x current price. **Not an on-chain balance**: a token sent out by transfer still counts here. The proven current value is `holdings.verified_value_eth`.' unique_tokens: type: integer open_positions: type: integer description: FIFO-open positions (unmatched DEX buys). How many are actually still held is in `holdings`. window_days: type: integer example: 90 partial: type: boolean description: Present only when the 50,000-trade cap was hit. flags: type: object properties: is_kol: type: boolean kol_name: type: string nullable: true is_deployer: type: boolean deployer_tier: type: string nullable: true enum: - elite - good - neutral - spammer deployer_tokens: type: integer nullable: true deployer_runner_rate: type: number nullable: true is_alpha_tracked: type: boolean alpha_win_rate: type: number nullable: true alpha_net_eth: type: number nullable: true alpha_tokens_traded: type: integer nullable: true likely_bot: type: boolean nullable: true description: Atomic-arb / MM signature from mv_rhc_alpha_wallets. is_dumper: type: boolean description: ≥5 dump cohorts AND 0 runner cohorts, rolling 42d. Rebuilt daily — up to ~48h stale. Absence means NOT OBSERVED, not verified clean. dump_cluster: type: object nullable: true early_buyer_tokens: type: integer description: Tokens where this wallet was in the first-20 buyer cohort. top_tokens: type: array maxItems: 10 items: type: object properties: still_holding: type: boolean description: 'FIFO meaning: an unmatched DEX buy exists. NOT an on-chain balance; see holding_status.' holding_status: type: string nullable: true enum: - HELD - PARTIALLY_REDUCED - TRANSFERRED_OR_DISPOSED - EXTERNAL_INFLOW - BALANCE_UNVERIFIED description: On-chain status of a FIFO-open token; null when the token is FIFO-closed. holdings: type: object nullable: true description: 'On-chain verification of every FIFO-open position: balanceOf + decimals read from our own Robinhood Chain node in one Multicall3 batch (cached 30 s). `complete: false` means at least one position is BALANCE_UNVERIFIED (node unreachable, call reverted, non-standard token, decimals mismatch) and contributes NO value.' properties: balance_source: type: string enum: - rhc_node_multicall3 checked_at: type: string format: date-time complete: type: boolean fifo_open_positions: type: integer held: type: integer partially_reduced: type: integer transferred_or_disposed: type: integer external_inflow: type: integer unverified: type: integer verified_value_eth: type: number description: 'PROVEN balances x current price: the current value of the tokens this wallet bought on a DEX and still holds. Unverified and unpriced positions contribute nothing.' unpriced_held: type: integer cost_basis_held_eth: type: number description: Cost basis of the FIFO-known portion still in the wallet. unrealized_known_eth: type: number description: Unrealized PnL on the portion whose cost basis is known AND still held. External inflows never add trading profit. cost_basis_not_held_eth: type: number description: 'Cost basis of FIFO lots no longer in the wallet (transferred out or disposed outside indexed swaps). Outcome unknown: neither realized nor unrealized.' recent_trades: type: array maxItems: 20 items: type: object derived: type: object nullable: true properties: win_rate: type: number nullable: true wins: type: integer losses: type: integer avg_trade_size_eth: type: number nullable: true is_active: type: boolean stats_unavailable: type: boolean description: Present when the trade aggregation was skipped on a timeout. Absence of stats is then UNPROVEN — do not read it as an inactive wallet. cache_hit: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: No recorded Robinhood Chain activity for this address as a trading account (`trader_eoa`). The body carries `address_type` (`eoa` / `eoa_7702` / `contract` / `unknown`, from eth_getCode); for a contract also `contract_trader_swaps_last_hour` (swaps where it is the swap-log trader; null = not measured) and a `note`. A contract cannot sign transactions, so its own swaps are never attributed to a wallet here; identities are not merged. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletByAddress x-operation-id-source: derived /rhc/wallet/{address}/funding: get: tags: - Robinhood Chain summary: Robinhood Chain shared-funder evidence for a tracked wallet (PRO+) description: Robinhood Chain (eip155:4663). Addresses that sent a qualifying native ETH or ERC-20 transfer to this wallet AND to other tracked wallets (KOL EVM wallets, elite/good deployers), with the supporting transactions. Evidence of a funding connection — not proof of common ownership. Internal (contract → wallet) ETH transfers are not observed. Forward-looking coverage from monitoring start; no historical backfill. parameters: - name: address in: path required: true schema: type: string description: EVM address (0x…, case-insensitive). - name: limit in: query schema: type: integer minimum: 1 maximum: 20 default: 10 description: Shared funders per page. - name: offset in: query schema: type: integer minimum: 0 maximum: 100 default: 0 responses: '200': description: 'OK. `status`: ok | partial_coverage | not_tracked | collection_disabled | collection_stale | not_started. `collection_stale` = the collector has not reported within the staleness window, so evidence after `coverage.heartbeat_at` may be missing. An empty `shared_funders` with status ok means no shared funder was OBSERVED within coverage — never that wallets are independent.' content: application/json: schema: type: object properties: chain: type: string enum: - solana - robinhood chain_id: type: string native_asset: type: string address: type: string status: type: string enum: - ok - partial_coverage - not_tracked - collection_disabled - collection_stale - not_started summary: type: string shared_funders: type: array items: type: object properties: funder: type: string funder_explorer_url: type: string funder_label: type: object nullable: true properties: label: type: string category: type: string verified: type: boolean service_funder: type: boolean description: 'Known exchange/service: a common funding source, not a connection signal' to_this_wallet: type: array items: type: object properties: asset: type: string description: '''native'' or the token contract' symbol: type: string nullable: true decimals: type: integer nullable: true amount_raw: type: string description: Exact integer (raw units) amount: type: string nullable: true description: Exact decimal string when decimals are known transfer_count: type: integer first_seen: type: string format: date-time description: Chain block time of the earliest transfer when resolved; otherwise the collector's observation time (Solana block times are resolved asynchronously and can stay unknown after bounded retries). Not a guaranteed on-chain timestamp. last_seen: type: string format: date-time description: Same basis as first_seen, for the latest transfer. transactions: type: array items: type: object properties: tx: type: string explorer_url: type: string connected_wallets: type: array items: type: object properties: address: type: string explorer_url: type: string tracked_as: type: array items: type: string transfers: type: array items: type: object properties: asset: type: string description: '''native'' or the token contract' symbol: type: string nullable: true decimals: type: integer nullable: true amount_raw: type: string description: Exact integer (raw units) amount: type: string nullable: true description: Exact decimal string when decimals are known transfer_count: type: integer first_seen: type: string format: date-time description: Chain block time of the earliest transfer when resolved; otherwise the collector's observation time (Solana block times are resolved asynchronously and can stay unknown after bounded retries). Not a guaranteed on-chain timestamp. last_seen: type: string format: date-time description: Same basis as first_seen, for the latest transfer. transactions: type: array items: type: object properties: tx: type: string explorer_url: type: string pagination: type: object properties: limit: type: integer offset: type: integer total: type: integer has_more: type: boolean coverage: type: object additionalProperties: true description: collection_enabled, mode (off|shadow|on), heartbeat_at, collector_current, monitoring_started_at, last_committed_position, last_committed_at, tracked_intervals, known_gaps, supported/unsupported transfer types, recovery, history note disclaimer: type: string direct_funding: type: object additionalProperties: true description: 'Optional, additive: where THIS wallet was funded from (the same block as `funding` on the wallet/deployer profiles). Absent when the direct read fails — the shared-funder answer above still stands. `observed: false` carries `coverage`, `coverage_explanation`, `observation_started_at` and `note` (no funding observed within coverage is not evidence the wallet was never funded). `observed: true` adds the coverage fields, `asset_scope`, `native_funding`, `token_funding`, `sources[]` and `source_count` (PRO); cross-wallet `relationships` counts are ULTRA+ and removed below ULTRA.' properties: observed: type: boolean coverage: type: string description: Coverage level of the funding evidence, e.g. forward_only. coverage_explanation: type: string observation_started_at: type: string format: date-time nullable: true note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid address or query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid API key. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Tier below PRO. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': description: '`code: feature_disabled` (feature switched off by the operator; on in production since 2026-09-20) or `code: funding_data_unavailable` (data error — NOT an empty result; retry).' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/Error' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletByAddressFunding x-operation-id-source: derived /rhc/wallet/{address}/pnl: get: tags: - Robinhood Chain summary: FIFO cost-basis PnL on Robinhood Chain (PRO+) description: 'Full FIFO cost-basis PnL for one RHC wallet over 90 days: realized and unrealized split, a daily realized curve, every closed position with ROI and token-weighted hold time, and every open position marked to the current price. This runs the **same FIFO implementation as the Solana `/wallet/{address}/pnl`** — the algorithm is imported, not reimplemented — with ETH substituted for SOL. Field names keep the Solana convention with the denomination swapped (`realized_eth`, `pnl_eth`), so porting a Solana integration is a mechanical rename. It also shares its loader with `/rhc/wallet/{address}`, so the two endpoints cannot report different PnL for the same wallet. **Cost basis is only observable inside the window** (`notes.cost_basis_observable_from`). Tokens sold that were bought before it contribute no realized PnL rather than a fabricated one — figures read low, never invented. **Attribution floor (`notes.attribution_complete_from`, 2026-07-18):** the window is clamped forward to this date because `trader_eoa` — the column every wallet endpoint filters on — was written for under half of earlier trades. The gap is ASYMMETRIC per wallet: a token''s buys can carry it while its sell does not, which leaves FIFO holding a position that was actually closed. Analysing only the attributed era is narrower but honest. `notes.window_clamped` flags it. Cached 120s per address. Tier: **PRO+**.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood address: type: string window_days: type: integer example: 90 summary: type: object properties: realized_eth: type: number unrealized_eth: type: number total_pnl_eth: type: number total_bought_eth: type: number total_sold_eth: type: number wins: type: integer losses: type: integer win_rate: type: number nullable: true description: Fraction in [0,1] across CLOSED positions. profit_factor: type: number nullable: true description: Gross wins / gross losses. null when there are no losses (undefined math), 0 when there are no wins. avg_hold_minutes: type: integer nullable: true median_hold_minutes: type: integer nullable: true max_drawdown_eth: type: number description: Magnitude — always ≥ 0. open_positions_count: type: integer closed_positions_count: type: integer total_tokens_traded: type: integer best_realized: type: object nullable: true worst_realized: type: object nullable: true pnl_curve: type: array description: Sparse daily UTC buckets of REALIZED PnL. `cumulative_pnl` is the running sum of `day_pnl`; days with no realized events are omitted. items: type: object properties: date: type: string example: '2026-07-24' day_pnl: type: number cumulative_pnl: type: number trades: type: integer closed_positions: type: array items: type: object properties: token_address: type: string token_symbol: type: string nullable: true buy_count: type: integer sell_count: type: integer bought_eth: type: number sold_eth: type: number pnl_eth: type: number roi_pct: type: number nullable: true hold_minutes: type: integer nullable: true description: Token-weighted across matched FIFO lots — correct for re-entered tokens. result: type: string enum: - win - loss - breakeven first_trade: type: string format: date-time nullable: true last_trade: type: string format: date-time nullable: true open_positions: type: array description: Unsold FIFO tail marked to the current price. Each entry carries `liquidity_basis` (`v4_virtual_ceiling` | `measured`) — uniswap-v4 liquidity_usd is a virtual-reserve ceiling, not measured per-pool TVL. items: type: object notes: type: object properties: denomination: type: string enum: - ETH cost_basis_observable_from: type: string format: date-time data_through: type: string format: date-time nullable: true description: 'Newest trade this answer was computed from — the response''s vintage. Equals `stats.last_seen` on /rhc/wallet/{address} when both ran over the same data. Use this, not a trade count, to tell whether two responses are comparable: the count saturates at the analysis cap.' trades_seen: type: integer trades_analyzed: type: integer trades_unattributed: type: integer description: No token side / direction (exotic or unresolved pool). Routine. trades_unsized: type: integer description: Token-side trades with no reconstructable quantity. Should be ~0. partial: type: boolean partial_reason: type: string cache_hit: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Wallet has no Robinhood Chain trades in the data window. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '422': description: Trades exist but none carry a reconstructable token amount, so no PnL can be computed. Returning zeroes would assert the wallet is flat, which is a different claim. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletByAddressPnl x-operation-id-source: derived /rhc/wallet/{address}/positions: get: tags: - Robinhood Chain summary: Open positions on Robinhood Chain (PRO+) description: 'Only what the wallet is still holding, marked to the current price — the same FIFO pass as `/pnl` without the curve and closed-position payload, for clients polling "what is this wallet in right now". **"Open" means FIFO-unmatched buys inside the window: a TRADING position, NOT an on-chain balance.** This cuts both ways and the second direction is the dangerous one: a token acquired by transfer or bridge does not appear, and a token **disposed of by plain ERC-20 transfer rather than sold on a DEX still appears as held**, because only swaps are indexed. Since 2026-10-02 every position is **checked against the chain**: `current_onchain_balance` (balanceOf from our own node, Multicall3, cached 30 s) sits next to `fifo_unmatched_amount`, and `holding_status` says which applies: `HELD` (balance within 0.5 % of FIFO), `PARTIALLY_REDUCED` (0 FIFO; the excess has no cost basis), `BALANCE_UNVERIFIED` (read failed, non-standard token, or our decimals differ from on-chain decimals: fail closed, no value). The pre-existing fields (`token_amount`, `current_value_eth`, `unrealized_eth`, the `summary` totals) keep their FIFO meaning; `summary.holdings` and the `current_holding_value_eth` / `unrealized_known_eth` fields are the proven-holdings view. **Attribution floor:** analysis starts at `notes.attribution_complete_from` (2026-07-18), not the full 90 days — `trader_eoa` was written for under half of earlier trades, and a partial view yields positions the wallet no longer holds. `notes.window_clamped` flags when this is what bounds the result. `total_unrealized_eth` is computed against the cost basis of the PRICED subset only — `unpriced_positions` counts what is missing from the totals, so a zero is never mistaken for worthless. Tier: **PRO+**.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ responses: '200': description: OK. Sorted by current value, then cost basis. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood address: type: string window_days: type: integer summary: type: object properties: open_positions: type: integer total_cost_basis_eth: type: number total_current_value_eth: type: number description: Priced positions only. total_unrealized_eth: type: number description: Against the cost basis of the priced subset only. unpriced_positions: type: integer holdings: type: object nullable: true description: 'On-chain verification of every FIFO-open position: balanceOf + decimals read from our own Robinhood Chain node in one Multicall3 batch (cached 30 s). `complete: false` means at least one position is BALANCE_UNVERIFIED (node unreachable, call reverted, non-standard token, decimals mismatch) and contributes NO value.' properties: balance_source: type: string enum: - rhc_node_multicall3 checked_at: type: string format: date-time complete: type: boolean fifo_open_positions: type: integer held: type: integer partially_reduced: type: integer transferred_or_disposed: type: integer external_inflow: type: integer unverified: type: integer verified_value_eth: type: number description: 'PROVEN balances x current price: the current value of the tokens this wallet bought on a DEX and still holds. Unverified and unpriced positions contribute nothing.' unpriced_held: type: integer cost_basis_held_eth: type: number description: Cost basis of the FIFO-known portion still in the wallet. unrealized_known_eth: type: number description: Unrealized PnL on the portion whose cost basis is known AND still held. External inflows never add trading profit. cost_basis_not_held_eth: type: number description: 'Cost basis of FIFO lots no longer in the wallet (transferred out or disposed outside indexed swaps). Outcome unknown: neither realized nor unrealized.' positions: type: array items: type: object properties: token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true launchpad: type: string nullable: true is_graduated: type: boolean nullable: true token_amount: type: number cost_basis_eth: type: number avg_entry_price_eth: type: number current_price_eth: type: number nullable: true current_value_eth: type: number nullable: true unrealized_eth: type: number nullable: true unrealized_pct: type: number nullable: true current_mc_usd: type: number nullable: true liquidity_usd: type: number nullable: true liquidity_basis: type: string enum: - v4_virtual_ceiling - measured description: How liquidity_usd was derived. uniswap-v4 figures are virtual reserves clamped to the PoolManager's total holdings — a provable ceiling, not measured per-pool TVL. buys_in_position: type: integer realized_so_far_eth: type: number description: Partial exits already taken on this token. first_buy_at: type: string format: date-time nullable: true last_buy_at: type: string format: date-time nullable: true fifo_unmatched_amount: type: number nullable: true description: DEX buys not matched by a DEX sell (same as token_amount). A trading position, not a balance. current_onchain_balance: type: number nullable: true description: balanceOf(wallet) / 10^decimals from our node. null = not proven (BALANCE_UNVERIFIED). holding_status: type: string enum: - HELD - PARTIALLY_REDUCED - TRANSFERRED_OR_DISPOSED - EXTERNAL_INFLOW - BALANCE_UNVERIFIED holding_unverified_reason: type: string nullable: true enum: - rpc_unavailable - call_failed - decimals_failed - over_cap - decimals_mismatch - decimals_unknown held_known_amount: type: number nullable: true description: 'min(balance, FIFO): the held part whose cost basis is known.' external_inflow_amount: type: number nullable: true current_holding_value_eth: type: number nullable: true description: current_onchain_balance x current price. 0 when transferred out; null when unverified or unpriced. cost_basis_held_eth: type: number nullable: true unrealized_known_eth: type: number nullable: true description: Unrealized on the known-cost, still-held portion only. cost_basis_not_held_eth: type: number nullable: true description: Cost basis of the FIFO portion no longer in the wallet. Outcome unknown. notes: type: object headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Wallet has no Robinhood Chain trades in the data window. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletByAddressPositions x-operation-id-source: derived /rhc/wallet/{address}/trades: get: tags: - Robinhood Chain summary: One wallet's Robinhood Chain trade tape (PRO+) description: 'A single wallet''s swaps, newest first, cursor-paginated (opaque `next_before` keyset). Distinct from `/rhc/trades?token=` — that filters the global tape by TOKEN, this filters by WALLET, which is a different index path (`idx_rhc_trades_trader_eoa_bt`). `token_amount` is reconstructed from raw uint256 leg amounts and is **null when it cannot be** — never zero, and never a guess. Tier: **PRO+**. **Where the rows come from** (*added 2026-08-29*): closed months older than the newest three move from Postgres to a Parquet archive; pages are split at `history.postgres_from` (ISO) — rows at/after it from Postgres, older rows from the archive reader, same ordering and `before` cursor. `history.archive_used`, `archive_months`, `archive_available` (`null` = not configured) and `truncated` (older history requested but the archive did not answer — retry rather than treating `has_more:false` as the end) mirror `/tokens/{mint}/trades`. Header `X-Read-Source`: `core`, `core+archive` or `archive`.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 - name: before in: query schema: type: string description: Opaque cursor from next_before; a bare ISO block_time is also accepted for backward compatibility (loses intra-second position). - name: since in: query schema: type: string format: date-time - name: action in: query schema: type: string enum: - buy - sell - name: token in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Restrict to one token. responses: '200': description: OK. `next_before` is the opaque pagination cursor — pass it back as `before`; `has_more` says whether another page exists. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood address: type: string trades: type: array items: type: object properties: token_address: type: string nullable: true token_symbol: type: string nullable: true token_name: type: string nullable: true launchpad: type: string nullable: true action: type: string enum: - buy - sell nullable: true eth_amount: type: number nullable: true token_amount: type: number nullable: true description: null when no decimals row and no execution price exist for the token. price_native: type: number nullable: true price_usd: type: number nullable: true mc_usd_at_trade: type: number nullable: true dex: type: string nullable: true pool: type: string nullable: true router: type: string nullable: true method_selector: type: string nullable: true tx_hash: type: string log_index: type: integer block_number: type: integer block_time: type: string format: date-time count: type: integer has_more: type: boolean description: True when another page exists beyond this one. next_before: type: string nullable: true description: Opaque (block_time, id) keyset cursor for the next page; null when has_more is false. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address or query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletByAddressTrades x-operation-id-source: derived /rhc/wallet-tracker/watchlist: get: tags: - Robinhood Chain summary: List tracked Robinhood Chain wallets (PRO+) description: 'Your Robinhood Chain watchlist. **Quotas are per chain** — PRO 50 / ULTRA 100 / BUSINESS 500 RHC wallets, independent of your Solana watchlist, so adopting RHC never shrinks an existing Solana list. Tier: **PRO+**.' responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood wallets: type: array items: type: object properties: wallet_address: type: string label: type: string nullable: true added_at: type: string format: date-time count: type: integer limit: type: integer remaining: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletTrackerWatchlist x-operation-id-source: derived post: tags: - Robinhood Chain summary: Add a Robinhood Chain wallet to your watchlist (PRO+) description: 'Addresses are stored lowercase so they match `rhc_trades.trader_eoa`; a checksummed `0xAbC…` would otherwise join to nothing and look like a permanently silent wallet. Tier: **PRO+**.' requestBody: required: true content: application/json: schema: type: object required: - wallet_address properties: wallet_address: type: string pattern: ^0x[0-9a-fA-F]{40}$ label: type: string maxLength: 64 responses: '201': description: Added. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address or JSON body. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '409': description: Wallet already in watchlist, or the per-tier RHC limit is reached. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: postRhcWalletTrackerWatchlist x-operation-id-source: derived /rhc/wallet-tracker/watchlist/{address}: delete: tags: - Robinhood Chain summary: Remove a Robinhood Chain wallet from your watchlist (PRO+) description: 'Remove a wallet from your Robinhood Chain tracker watchlist, addressed by the `address` path param (0x + 40 hex; matched and returned lowercase). The watchlist quota is per chain and separate from Solana: PRO 50, ULTRA 100, BUSINESS 500 wallets. 400 for an invalid EVM address, 404 if the wallet isn''t on your watchlist.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ responses: '200': description: Removed. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood removed: type: string description: The lowercased EVM address that was removed. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not in watchlist. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: deleteRhcWalletTrackerWatchlistByAddress x-operation-id-source: derived patch: tags: - Robinhood Chain summary: Relabel a tracked Robinhood Chain wallet (PRO+) description: 'Set or clear the label on a wallet in your Robinhood Chain tracker watchlist, addressed by the `address` path param (0x + 40 hex). Send `{ label }` in the JSON body: 1-64 characters, or null to clear it. 400 for an invalid address or body, 404 if the wallet isn''t on your watchlist.' parameters: - name: address in: path required: true schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ requestBody: required: true content: application/json: schema: type: object required: - label properties: label: type: string maxLength: 64 nullable: true responses: '200': description: Updated. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood wallet: type: object properties: wallet_address: type: string label: type: string nullable: true added_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid EVM address or body. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not in watchlist. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: patchRhcWalletTrackerWatchlistByAddress x-operation-id-source: derived /rhc/copytrade/subscriptions: get: tags: - Robinhood Chain summary: List RHC copy-trade rules (PRO+) description: 'Your Robinhood Chain copy-trade rules. Quotas are per chain — PRO 3 rules × 5 wallets / ULTRA 20 × 50 / BUSINESS 100 × 250, independent of your Solana copy-trade rules. Tier: **PRO+**.' responses: '200': description: OK — { chain, subscriptions[] }. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscriptions: type: array items: type: object properties: id: type: integer description: Numeric rule id (used in /rhc/copytrade/subscriptions/{id}) name: type: string nullable: true source_wallets: type: array items: type: string description: Lowercase 0x EVM wallets being mirrored (1-250). Any valid address once source_admission is any_wallet; under the legacy kol_only engine only tracked KOL wallets (kol_evm_wallets) can fire — see source_admission and operational_state. min_trade_eth: type: number only_action: type: string enum: - buy - sell - both sizing_mode: type: string enum: - fixed - proportional - percent_source sizing_amount: type: number delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time source_wallets_tracked: $ref: '#/components/schemas/RhcCopytradeTrackedWallets' source_wallets_untracked: $ref: '#/components/schemas/RhcCopytradeUntrackedWallets' operational_state: $ref: '#/components/schemas/RhcCopytradeOperationalState' source_admission: $ref: '#/components/schemas/RhcCopytradeSourceAdmission' monitoring_reasons: $ref: '#/components/schemas/RhcCopytradeMonitoringReasons' warnings: $ref: '#/components/schemas/RhcCopytradeRuleWarnings' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcCopytradeSubscriptions x-operation-id-source: derived post: tags: - Robinhood Chain summary: Create an RHC copy-trade rule (PRO+) description: 'Mirror chosen Robinhood Chain wallets to a webhook or the `rhc:copytrade:signals` WebSocket channel. Any valid 0x source wallet fires, KOL or not (`source_admission: any_wallet`, production since 2026-10-04; KOL membership is enrichment only and copy-trade sources do not use Wallet Tracker quota); `operational_state` says whether the rule can fire right now. A source trade must be at most 5 s old by chain time. Addresses are **lowercased on write** — the evaluator matches the lowercased event address, so a checksummed rule would never fire. Amounts are ETH. Idempotency is `(subscription_id, tx_hash)`, so a replayed event can never double-fire. **No `min_mc_usd`/`max_mc_usd`**: the RHC trade event carries no market cap, so an MC band could only be a per-event database lookup on a ~3.3M trades/day chain or a filter that silently never matches. Returns `webhook_secret` once, never again.' requestBody: required: true content: application/json: schema: type: object required: - source_wallets - sizing_amount properties: name: type: string maxLength: 64 source_wallets: type: array minItems: 1 maxItems: 250 items: type: string description: Lowercase 0x EVM address min_trade_eth: type: number minimum: 0 default: 0 only_action: type: string enum: - buy - sell - both default: buy sizing_mode: type: string enum: - fixed - proportional - percent_source default: fixed sizing_amount: type: number exclusiveMinimum: 0 description: ETH when sizing_mode=fixed, else a multiplier of the source trade delivery_mode: type: string enum: - webhook - websocket - both default: webhook webhook_url: type: string format: uri description: HTTPS only. Required unless delivery_mode is websocket. responses: '200': description: Created — includes one-time webhook_secret. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscription: type: object properties: id: type: integer name: type: string nullable: true source_wallets: type: array items: type: string min_trade_eth: type: number only_action: type: string enum: - buy - sell - both sizing_mode: type: string enum: - fixed - proportional - percent_source sizing_amount: type: number delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time source_wallets_tracked: $ref: '#/components/schemas/RhcCopytradeTrackedWallets' source_wallets_untracked: $ref: '#/components/schemas/RhcCopytradeUntrackedWallets' operational_state: $ref: '#/components/schemas/RhcCopytradeOperationalState' source_admission: $ref: '#/components/schemas/RhcCopytradeSourceAdmission' monitoring_reasons: $ref: '#/components/schemas/RhcCopytradeMonitoringReasons' warnings: $ref: '#/components/schemas/RhcCopytradeRuleWarnings' warnings: $ref: '#/components/schemas/RhcCopytradeRuleWarnings' webhook_secret: type: string nullable: true description: One-time HMAC secret — only present when webhook delivery is configured. note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body, EVM address, webhook URL, or wallet count above the tier cap. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '409': description: RHC copy-trade rule limit reached for the tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: postRhcCopytradeSubscriptions x-operation-id-source: derived /rhc/copytrade/subscriptions/{id}: get: tags: - Robinhood Chain summary: Get one RHC copy-trade rule (PRO+) description: Fetch one Robinhood Chain copy-trade rule you own, addressed by the numeric `id` path param. Returns its source wallets, minimum trade size in ETH, buy / sell filter, sizing mode and amount, delivery config (webhook, websocket or both) and `is_active` state. 400 for a non-numeric id, 404 if the id doesn't exist or isn't yours. parameters: - name: id in: path required: true schema: type: integer responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscription: type: object properties: id: type: integer name: type: string nullable: true source_wallets: type: array items: type: string min_trade_eth: type: number only_action: type: string enum: - buy - sell - both sizing_mode: type: string enum: - fixed - proportional - percent_source sizing_amount: type: number delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time source_wallets_tracked: $ref: '#/components/schemas/RhcCopytradeTrackedWallets' source_wallets_untracked: $ref: '#/components/schemas/RhcCopytradeUntrackedWallets' operational_state: $ref: '#/components/schemas/RhcCopytradeOperationalState' source_admission: $ref: '#/components/schemas/RhcCopytradeSourceAdmission' monitoring_reasons: $ref: '#/components/schemas/RhcCopytradeMonitoringReasons' warnings: $ref: '#/components/schemas/RhcCopytradeRuleWarnings' warnings: $ref: '#/components/schemas/RhcCopytradeRuleWarnings' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcCopytradeSubscriptionsById x-operation-id-source: derived patch: tags: - Robinhood Chain summary: Update an RHC copy-trade rule (PRO+) description: Partial update. The wallet cap is re-checked, so a PRO rule cannot be PATCHed past its tier limit. parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: type: object properties: name: type: string nullable: true source_wallets: type: array items: type: string min_trade_eth: type: number only_action: type: string enum: - buy - sell - both sizing_mode: type: string enum: - fixed - proportional - percent_source sizing_amount: type: number delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string nullable: true is_active: type: boolean responses: '200': description: Updated. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscription: type: object properties: id: type: integer name: type: string nullable: true source_wallets: type: array items: type: string min_trade_eth: type: number only_action: type: string enum: - buy - sell - both sizing_mode: type: string enum: - fixed - proportional - percent_source sizing_amount: type: number delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time source_wallets_tracked: $ref: '#/components/schemas/RhcCopytradeTrackedWallets' source_wallets_untracked: $ref: '#/components/schemas/RhcCopytradeUntrackedWallets' operational_state: $ref: '#/components/schemas/RhcCopytradeOperationalState' source_admission: $ref: '#/components/schemas/RhcCopytradeSourceAdmission' monitoring_reasons: $ref: '#/components/schemas/RhcCopytradeMonitoringReasons' warnings: $ref: '#/components/schemas/RhcCopytradeRuleWarnings' warnings: $ref: '#/components/schemas/RhcCopytradeRuleWarnings' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body or id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: patchRhcCopytradeSubscriptionsById x-operation-id-source: derived delete: tags: - Robinhood Chain summary: Delete an RHC copy-trade rule (PRO+) description: 'Permanently delete a Robinhood Chain copy-trade rule you own, addressed by the numeric `id` path param. Its stored signal history is deleted with it and no further `rhc:copytrade:signal` events fire for it. To stop it temporarily instead, PATCH `is_active: false`. 404 if the id doesn''t exist or isn''t yours.' parameters: - name: id in: path required: true schema: type: integer responses: '200': description: 'Deleted — { chain, deleted: true }.' content: application/json: schema: type: object properties: chain: type: string enum: - robinhood deleted: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: deleteRhcCopytradeSubscriptionsById x-operation-id-source: derived /rhc/copytrade/signals: get: tags: - Robinhood Chain summary: RHC copy-trade fire history (PRO+) description: Catch-up path for a consumer that missed a webhook or was disconnected from the WebSocket channel. Retained 7 days. parameters: - name: subscription_id in: query schema: type: integer description: Scope to one of your rules. 404 if you do not own it. - name: since in: query schema: type: string format: date-time - name: limit in: query schema: type: integer minimum: 1 maximum: 500 default: 50 responses: '200': description: OK — { chain, signals[], count }. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood signals: type: array items: type: object properties: id: type: integer subscription_id: type: integer fired_at: type: string format: date-time source_wallet: type: string description: Lowercase 0x wallet whose trade matched the rule. action: type: string enum: - buy - sell token_address: type: string token_symbol: type: string nullable: true token_name: type: string nullable: true source_eth_amount: type: number description: Size of the source wallet's trade, in ETH. suggested_eth_amount: type: number nullable: true description: Sized amount per the rule's sizing_mode/sizing_amount. price_usd: type: number nullable: true dex: type: string nullable: true tx_hash: type: string delivered: type: boolean description: True once the signal was actually written to one of your live sockets or accepted by your webhook. A frame that was only queued for a socket still running a replay and then dropped (queue overflow or a 4008 close) is NOT delivered and records delivery_error 'ws_replay_dropped'. delivered_at: type: string format: date-time nullable: true count: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid limit, since, or subscription_id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: subscription_id not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcCopytradeSignals x-operation-id-source: derived /rhc/price-alerts: get: tags: - Robinhood Chain summary: List RHC price alerts (PRO+) description: 'List every Robinhood Chain market-cap price alert you own, active and paused, newest first. Each alert carries its token, the baseline market cap captured at creation, the `drop_pct` / `recovery_pct` thresholds, its current `status` (watching, then dipped, then recovered), the dip low, delivery config and expiry. Alerts are evaluated as trades land (event-driven off the chain trade feed, a few seconds of latency), with periodic table polls as a safety net. The quota counts active alerts only and is separate from Solana: PRO 5, ULTRA 25, BUSINESS 125.' responses: '200': description: OK — { chain, alerts[] }. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood alerts: type: array items: type: object properties: id: type: integer name: type: string nullable: true token_address: type: string token_symbol: type: string nullable: true baseline_mc_usd: type: number description: Market cap captured at rule creation — the baseline drop_pct is measured against. drop_pct: type: number recovery_pct: type: number nullable: true status: type: string enum: - watching - dipped - recovered - expired description: '`expired` = the rule outlived its window and was deactivated (terminal, like `recovered`).' dip_low_mc_usd: type: number nullable: true description: Lowest MC seen while dipped; ratchets down. dip_fired_at: type: string format: date-time nullable: true delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean expires_at: type: string format: date-time nullable: true created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcPriceAlerts x-operation-id-source: derived post: tags: - Robinhood Chain summary: Create an RHC price alert (PRO+) description: 'Market-cap drop alert with an optional recovery leg, baselined against the token''s market cap **at creation**. One-shot state machine: `watching → dipped → recovered`; `dip_low` ratchets down while dipped; terminal on the dip when no `recovery_pct` is set. ⚠️ **Latency differs from the Solana price alerts.** Solana alerts are evaluated inside a live in-memory price loop every 250 ms. RHC alerts are **event-driven**: each trade on the chain''s trade feed (`rhc:dex_trade`) is checked against the alerted token set, with price-table polls (every 5 s while the feed is degraded or a trade carried no market cap, 60 s otherwise) and a trade-tape replay after a feed outage as safety nets. Latency is a few seconds (the chain trade flush is about 2 s), not sub-second. Every create response carries an `evaluation` block restating this. Do not size a strategy on the Solana figure. `token_address`, `drop_pct` and `recovery_pct` are immutable after creation.' requestBody: required: true content: application/json: schema: type: object required: - token_address - drop_pct properties: name: type: string maxLength: 64 token_address: type: string description: Lowercase 0x token address, must be tracked with a market cap drop_pct: type: number minimum: 0.01 maximum: 99.99 recovery_pct: type: number minimum: 0.01 maximum: 1000 description: Omit for a dip-only, terminal alert delivery_mode: type: string enum: - webhook - websocket - both default: webhook webhook_url: type: string format: uri responses: '200': description: Created — includes one-time webhook_secret and an `evaluation` block describing how the alert is evaluated. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood alert: type: object properties: id: type: integer name: type: string nullable: true token_address: type: string token_symbol: type: string nullable: true baseline_mc_usd: type: number drop_pct: type: number recovery_pct: type: number nullable: true status: type: string enum: - watching - dipped - recovered - expired description: '`expired` = the rule outlived its window and was deactivated (terminal, like `recovered`).' dip_low_mc_usd: type: number nullable: true dip_fired_at: type: string format: date-time nullable: true delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean expires_at: type: string format: date-time nullable: true created_at: type: string format: date-time updated_at: type: string format: date-time webhook_secret: type: string nullable: true description: One-time HMAC secret — only present when webhook delivery is configured. evaluation: type: object properties: mode: type: string enum: - event_driven - polled description: '`event_driven` since 2026-09-15 (`polled` before).' trigger: type: string example: rhc:dex_trade interval_seconds: type: integer example: 5 description: 'Kept for compatibility: the fast fallback table-poll interval.' fallback_poll_seconds: type: object properties: fast: type: integer example: 5 slow: type: integer example: 60 note: type: string note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body, or token not tracked / has no market cap to baseline against. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '409': description: RHC price alert limit reached for the tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: postRhcPriceAlerts x-operation-id-source: derived /rhc/price-alerts/{id}: get: tags: - Robinhood Chain summary: Get one RHC price alert (PRO+) description: Fetch one Robinhood Chain price alert you own, addressed by the numeric `id` path param. Returns its thresholds, current `status`, the dip low and when the dip fired, delivery config, `is_active` and expiry. The fired dip / recovery events are listed at /rhc/price-alerts/events. 404 if the id doesn't exist or isn't yours. parameters: - name: id in: path required: true schema: type: integer responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood alert: type: object properties: id: type: integer name: type: string nullable: true token_address: type: string token_symbol: type: string nullable: true baseline_mc_usd: type: number drop_pct: type: number recovery_pct: type: number nullable: true status: type: string enum: - watching - dipped - recovered - expired description: '`expired` = the rule outlived its window and was deactivated (terminal, like `recovered`).' dip_low_mc_usd: type: number nullable: true dip_fired_at: type: string format: date-time nullable: true delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean expires_at: type: string format: date-time nullable: true created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcPriceAlertsById x-operation-id-source: derived patch: tags: - Robinhood Chain summary: Update an RHC price alert (PRO+) description: Only `name`, `delivery_mode`, `webhook_url` and `is_active` are mutable — changing a threshold mid-flight would make the alert's recorded events uninterpretable. parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: type: object properties: name: type: string nullable: true delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string nullable: true is_active: type: boolean responses: '200': description: Updated. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood alert: type: object properties: id: type: integer name: type: string nullable: true token_address: type: string token_symbol: type: string nullable: true baseline_mc_usd: type: number drop_pct: type: number recovery_pct: type: number nullable: true status: type: string enum: - watching - dipped - recovered - expired description: '`expired` = the rule outlived its window and was deactivated (terminal, like `recovered`).' dip_low_mc_usd: type: number nullable: true dip_fired_at: type: string format: date-time nullable: true delivery_mode: type: string enum: - webhook - websocket - both webhook_url: type: string format: uri nullable: true is_active: type: boolean expires_at: type: string format: date-time nullable: true created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body or id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: patchRhcPriceAlertsById x-operation-id-source: derived delete: tags: - Robinhood Chain summary: Delete an RHC price alert (PRO+) description: 'Permanently delete a Robinhood Chain price alert you own, addressed by the numeric `id` path param, together with its dip and recovery event history. To stop it temporarily instead, PATCH `is_active: false`. Deleting an active alert frees one slot of your active-alert quota. 404 if the id doesn''t exist or isn''t yours.' parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Deleted. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood deleted: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: deleteRhcPriceAlertsById x-operation-id-source: derived /rhc/price-alerts/events: get: tags: - Robinhood Chain summary: RHC price-alert fire history (PRO+) description: Dip and recovery events for your RHC alerts. Retained 30 days. parameters: - name: alert_id in: query schema: type: integer - name: event_type in: query schema: type: string enum: - dip - recovery - name: since in: query schema: type: string format: date-time - name: limit in: query schema: type: integer minimum: 1 maximum: 500 default: 50 responses: '200': description: OK — { chain, events[], count }. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood events: type: array items: type: object properties: id: type: integer alert_id: type: integer event_type: type: string enum: - dip - recovery fired_at: type: string format: date-time token_address: type: string baseline_mc_usd: type: number nullable: true current_mc_usd: type: number nullable: true drop_pct_actual: type: number nullable: true dip_low_mc_usd: type: number nullable: true recovery_pct_actual: type: number nullable: true delivered: type: boolean description: True once the signal was actually written to one of your live sockets or accepted by your webhook. A frame that was only queued for a socket still running a replay and then dropped (queue overflow or a 4008 close) is NOT delivered and records delivery_error 'ws_replay_dropped'. delivered_at: type: string format: date-time nullable: true count: type: integer headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid parameter. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: alert_id not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcPriceAlertsEvents x-operation-id-source: derived /rhc/kol/coordination/alerts: get: tags: - Robinhood Chain summary: List RHC coordination rules (PRO+) description: 'List every Robinhood Chain KOL coordination rule you own, active and paused, newest first. A rule fires when at least `min_kols` tracked KOLs buy the same token within `window_minutes` and the coordination score reaches `min_score`, optionally bounded by a market-cap range; `cooldown_min` and `score_jump_break` decide when the same token may fire again. The quota counts every rule, paused ones included, and is separate from Solana: PRO 5, ULTRA 20, BUSINESS 100.' responses: '200': description: OK — { chain, rules[] }. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood rules: type: array items: type: object properties: id: type: string format: uuid name: type: string nullable: true min_kols: type: integer window_minutes: type: integer min_score: type: integer cooldown_min: type: integer score_jump_break: type: integer min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcKolCoordinationAlerts x-operation-id-source: derived post: tags: - Robinhood Chain summary: Create an RHC coordination rule (PRO+) description: 'Fires when `min_kols` distinct tracked KOLs buy the same Robinhood Chain token inside `window_minutes` and the cluster scores at least `min_score`. `cooldown_min` suppresses repeats per (rule, token); `score_jump_break` is an **early exit from that cooldown** when the score climbs by at least that many points (the re-fire is flagged `is_rearm`). An unknown market cap is **dropped** by the MC band, never treated as inside it. **Scoring** uses the same v1 scorer as the Solana coordination alerts, so the number is comparable — with two differences recorded per-signal in `score_inputs`: `quality` is real (from the RHC KOL win-rate matview) while `earliness` is **defaulted**, because RHC has no early-entry measure. `density` is 1.0 by construction inside a rule''s own window, so live scores start at 30.' requestBody: required: true content: application/json: schema: type: object properties: name: type: string maxLength: 64 min_kols: type: integer minimum: 2 maximum: 50 default: 3 window_minutes: type: integer minimum: 1 maximum: 60 default: 15 min_score: type: integer minimum: 0 maximum: 100 default: 0 cooldown_min: type: integer minimum: 1 maximum: 1440 default: 30 score_jump_break: type: integer minimum: 0 maximum: 100 default: 20 min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both default: websocket webhook_url: type: string format: uri responses: '200': description: Created — includes one-time webhook_secret and a `scoring` block. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood rule: type: object properties: id: type: string format: uuid name: type: string nullable: true min_kols: type: integer window_minutes: type: integer min_score: type: integer cooldown_min: type: integer score_jump_break: type: integer min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time webhook_secret: type: string nullable: true description: One-time HMAC secret — only present when webhook delivery is configured. scoring: type: object properties: score_version: type: string example: v1 quality: type: string description: Real component, from mv_rhc_kol_scores winrate_7d. earliness: type: string description: Defaulted — RHC has no early-entry equivalent. note: type: string note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body or MC band. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '409': description: RHC coordination rule limit reached for the tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: postRhcKolCoordinationAlerts x-operation-id-source: derived /rhc/kol/coordination/alerts/{id}: get: tags: - Robinhood Chain summary: Get one RHC coordination rule (PRO+) description: Fetch one Robinhood Chain KOL coordination rule you own, addressed by the `id` path param (UUID). Returns its KOL count, time window, score, cooldown and market-cap thresholds, delivery config (webhook, websocket or both) and `is_active` state. 400 for a malformed UUID, 404 if the id doesn't exist or isn't yours. parameters: - name: id in: path required: true schema: type: string format: uuid responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood rule: type: object properties: id: type: string format: uuid name: type: string nullable: true min_kols: type: integer window_minutes: type: integer min_score: type: integer cooldown_min: type: integer score_jump_break: type: integer min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcKolCoordinationAlertsById x-operation-id-source: derived patch: tags: - Robinhood Chain summary: Update an RHC coordination rule (PRO+) description: Partial update of a Robinhood Chain KOL coordination rule you own, addressed by the `id` path param (UUID). Every field accepted by POST is patchable, plus `is_active` to pause or resume the rule. A paused rule still counts toward your rule quota. 400 for a malformed UUID or an invalid body, 404 if the id doesn't exist or isn't yours. parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object properties: name: type: string nullable: true min_kols: type: integer window_minutes: type: integer min_score: type: integer cooldown_min: type: integer score_jump_break: type: integer min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string nullable: true is_active: type: boolean responses: '200': description: Updated. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood rule: type: object properties: id: type: string format: uuid name: type: string nullable: true min_kols: type: integer window_minutes: type: integer min_score: type: integer cooldown_min: type: integer score_jump_break: type: integer min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body or id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: patchRhcKolCoordinationAlertsById x-operation-id-source: derived delete: tags: - Robinhood Chain summary: Delete an RHC coordination rule (PRO+) description: Permanently delete a Robinhood Chain KOL coordination rule you own, addressed by the `id` path param (UUID). Its fire history and cooldown state are deleted with it and its per-rule pushes stop. Deleting frees a quota slot; pausing does not. 400 for a malformed UUID, 404 if the id doesn't exist or isn't yours. parameters: - name: id in: path required: true schema: type: string format: uuid responses: '200': description: Deleted. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood deleted: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: deleteRhcKolCoordinationAlertsById x-operation-id-source: derived /rhc/kol/first-touches/subscriptions: get: tags: - Robinhood Chain summary: List RHC first-touch subscriptions (ULTRA+) description: 'List every Robinhood Chain first-touch subscription you own, active and paused, newest first. A subscription fires when a tracked KOL is the first to buy a token, filtered by KOL, minimum first-buy size in ETH, KOL win rate, trading strategy and market-cap range, and delivers per rule to a webhook, the WebSocket or both. ULTRA and BUSINESS only; the unfiltered broadcast is on WS channel `rhc:kol:first_touches` for PRO+. The quota counts every subscription, paused ones included, and is separate from Solana: ULTRA 10, BUSINESS 50.' responses: '200': description: OK — { chain, subscriptions[] }. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscriptions: type: array items: type: object properties: id: type: string format: uuid name: type: string nullable: true filters: type: object properties: kol: type: string nullable: true description: Lowercase 0x EVM address min_first_buy_eth: type: number nullable: true min_kol_winrate: type: number nullable: true strategy: type: string nullable: true enum: - scalper - day_trader - swing - inactive - unscored min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: ULTRA x-badges: - name: ULTRA position: after color: '#b45309' operationId: getRhcKolFirstTouchesSubscriptions x-operation-id-source: derived post: tags: - Robinhood Chain summary: Create an RHC first-touch subscription (ULTRA+) description: 'Push the moment a token receives its **first** buy from a tracked KOL — the earliest signal available. A second KOL buying the same token produces nothing; dedup is structural (one first-touch row per token, ever). **Filters are `.strict()`** — an unknown key is a 400, not a silently ignored filter. ⚠️ There is deliberately **no `min_scout_tier` / `min_n_touches`** as on Solana: RHC has no scout scoring, and a filter that silently matched nothing would be worse than its absence. `min_kol_winrate` and `strategy` are the quality gates instead. An unknown market cap is dropped by the MC band, never passed.' requestBody: required: true content: application/json: schema: type: object properties: name: type: string maxLength: 64 filters: type: object additionalProperties: false properties: kol: type: string description: Lowercase 0x EVM address min_first_buy_eth: type: number minimum: 0 min_kol_winrate: type: number minimum: 0 maximum: 1 description: Win-rate on CLOSED positions. A KOL who has never sold is unscored and is dropped, not treated as a loser. strategy: type: string enum: - scalper - day_trader - swing - inactive - unscored min_mc_usd: type: number max_mc_usd: type: number delivery_mode: type: string enum: - websocket - webhook - both default: websocket webhook_url: type: string format: uri responses: '200': description: Created — includes one-time webhook_secret. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscription: type: object properties: id: type: string format: uuid name: type: string nullable: true filters: type: object properties: kol: type: string nullable: true min_first_buy_eth: type: number nullable: true min_kol_winrate: type: number nullable: true strategy: type: string nullable: true enum: - scalper - day_trader - swing - inactive - unscored min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time webhook_secret: type: string nullable: true description: One-time HMAC secret — only present when webhook delivery is configured. note: type: string headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body, unknown filter key, or MC band inverted. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '409': description: RHC first-touch subscription limit reached for the tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/AuthBackendUnavailable' x-madeonsol-tier: ULTRA x-badges: - name: ULTRA position: after color: '#b45309' operationId: postRhcKolFirstTouchesSubscriptions x-operation-id-source: derived /rhc/kol/first-touches/subscriptions/{id}: get: tags: - Robinhood Chain summary: Get one RHC first-touch subscription (ULTRA+) description: Fetch one Robinhood Chain first-touch subscription you own, addressed by the `id` path param (UUID). Returns its filters (KOL, minimum first-buy ETH, KOL win rate, strategy, market-cap range), delivery config and `is_active` state. ULTRA and BUSINESS only. 400 for a malformed UUID, 404 if the id doesn't exist or isn't yours. parameters: - name: id in: path required: true schema: type: string format: uuid responses: '200': description: OK. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscription: type: object properties: id: type: string format: uuid name: type: string nullable: true filters: type: object properties: kol: type: string nullable: true min_first_buy_eth: type: number nullable: true min_kol_winrate: type: number nullable: true strategy: type: string nullable: true enum: - scalper - day_trader - swing - inactive - unscored min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: ULTRA x-badges: - name: ULTRA position: after color: '#b45309' operationId: getRhcKolFirstTouchesSubscriptionsById x-operation-id-source: derived patch: tags: - Robinhood Chain summary: Update an RHC first-touch subscription (ULTRA+) description: '`filters` is a whole-object replace, not a merge — merging would make removing a filter impossible to express.' parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object properties: name: type: string nullable: true filters: type: object delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string nullable: true is_active: type: boolean responses: '200': description: Updated. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood subscription: type: object properties: id: type: string format: uuid name: type: string nullable: true filters: type: object properties: kol: type: string nullable: true min_first_buy_eth: type: number nullable: true min_kol_winrate: type: number nullable: true strategy: type: string nullable: true enum: - scalper - day_trader - swing - inactive - unscored min_mc_usd: type: number nullable: true max_mc_usd: type: number nullable: true delivery_mode: type: string enum: - websocket - webhook - both webhook_url: type: string format: uri nullable: true is_active: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid body or id. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: ULTRA x-badges: - name: ULTRA position: after color: '#b45309' operationId: patchRhcKolFirstTouchesSubscriptionsById x-operation-id-source: derived delete: tags: - Robinhood Chain summary: Delete an RHC first-touch subscription (ULTRA+) description: Permanently delete a Robinhood Chain first-touch subscription you own, addressed by the `id` path param (UUID). Its delivery history is deleted with it and its per-rule pushes stop. Deleting frees a quota slot; pausing does not. ULTRA and BUSINESS only. 400 for a malformed UUID, 404 if the id doesn't exist or isn't yours. parameters: - name: id in: path required: true schema: type: string format: uuid responses: '200': description: Deleted. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood deleted: type: boolean headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/TierForbidden' '404': description: Not found. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: ULTRA x-badges: - name: ULTRA position: after color: '#b45309' operationId: deleteRhcKolFirstTouchesSubscriptionsById x-operation-id-source: derived /rhc/wallet-tracker/summary: get: tags: - Robinhood Chain summary: Activity summary across your tracked Robinhood Chain wallets (PRO+) description: 'Per-wallet buy/sell/volume rollup over the chosen period. **Sourced from `rhc_trades` directly, not from a capture log.** The Solana tracker needs a per-subscriber event log because Solana trades are only recorded for wallets somebody asked for; on RHC every swap is already persisted with its trader. Two consequences: a wallet added today reports its **full history** in the period rather than only what happens after you subscribe, and these numbers agree with `/rhc/wallet/{address}` by construction. Tier: **PRO+**.' parameters: - name: period in: query schema: type: string enum: - 24h - 7d - 30d default: 7d - name: wallet in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Restrict to one watched wallet. responses: '200': description: 'OK. `stats_unavailable: true` means the rollup failed and the zeroes are not measurements.' content: application/json: schema: type: object properties: chain: type: string enum: - robinhood period: type: string interval: type: string stats_unavailable: type: boolean wallets: type: array items: type: object properties: wallet_address: type: string label: type: string nullable: true added_at: type: string format: date-time stats: type: object properties: trades: type: integer buys: type: integer sells: type: integer buy_eth: type: number sell_eth: type: number net_eth: type: number tokens_traded: type: integer last_trade_at: type: string format: date-time nullable: true headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletTrackerSummary x-operation-id-source: derived /rhc/wallet-tracker/trades: get: tags: - Robinhood Chain summary: Merged trade feed across your tracked Robinhood Chain wallets (PRO+) description: 'Every trade by every wallet on your RHC watchlist, newest first, each row labelled with the watchlist label. The cursor (`next_before`) is an opaque keyset matching the rest of the RHC tree rather than the Solana tracker''s integer epoch. A `wallet` filter must name a wallet already on your watchlist — otherwise this would be an unmetered alias for arbitrary wallet lookup. Tier: **PRO+**. **Where the rows come from** (*added 2026-08-29*): closed months older than the newest three move from Postgres to a Parquet archive; pages are split at `history.postgres_from` (ISO) — rows at/after it from Postgres, older rows from the archive reader, same ordering and `before` cursor. `history.archive_used`, `archive_months`, `archive_available` (`null` = not configured) and `truncated` (older history requested but the archive did not answer — retry rather than treating `has_more:false` as the end) mirror `/tokens/{mint}/trades`. Header `X-Read-Source`: `core`, `core+archive` or `archive`.' parameters: - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 - name: before in: query schema: type: string description: Opaque cursor from next_before; a bare ISO block_time is also accepted for backward compatibility (loses intra-second position). - name: wallet in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ description: Must be on your watchlist; otherwise 404. - name: action in: query schema: type: string enum: - buy - sell - name: token in: query schema: type: string pattern: ^0x[0-9a-fA-F]{40}$ responses: '200': description: OK. `next_before` is the opaque pagination cursor — pass it back as `before`; `has_more` says whether another page exists. content: application/json: schema: type: object properties: chain: type: string enum: - robinhood trades: type: array items: type: object count: type: integer has_more: type: boolean description: True when another page exists beyond this one. next_before: type: string nullable: true description: Opaque (block_time, id) keyset cursor for the next page; null when has_more is false. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' X-Data-Delay: $ref: '#/components/headers/XDataDelay' X-MadeOnSol-Quota-Warning: $ref: '#/components/headers/XMadeOnSolQuotaWarning' '400': description: Invalid query parameters. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '401': $ref: '#/components/responses/Unauthorized' '403': description: Requires Pro or Ultra tier. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: The `wallet` filter names an address that is not on your watchlist. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-madeonsol-tier: PRO x-badges: - name: PRO position: after color: '#1d4ed8' operationId: getRhcWalletTrackerTrades x-operation-id-source: derived components: headers: XRateLimitReset: description: When the window resets, as a Unix epoch in SECONDS (next 00:00 UTC for the daily quota; about 60 s ahead for a per-minute bucket). schema: type: integer example: 1791158400 XRateLimitRemaining: description: Calls left in that window. `0` on a quota 429. schema: type: integer minimum: 0 example: 9412 XDataDelay: description: 'Free-tier only: the feed in this body is delayed by this many seconds (same value as the body''s `delay_seconds`). Absent on real-time responses.' schema: type: integer minimum: 1 example: 300 XRateLimitLimit: description: 'Size of the rate-limit window this call was counted against: the daily quota for your tier on data endpoints, the per-minute bucket on `/stream/token` (10) and `/stream/sessions` (30), the hourly allowance for the public demo key. Sent once the key has been authenticated and rate-limited, so it is absent on authentication-stage errors.' schema: type: integer minimum: 0 example: 10000 XMadeOnSolQuotaWarning: description: 'Free-tier only, past about 70 % of the daily quota: a human-readable usage line with an upgrade link.' schema: type: string example: '150/200 used - upgrade for 50x higher limits: https://madeonsol.com/checkout?tier=PRO' XRequestId: description: Unique id of this response. On responses built after authentication it is also the `request_id` of the audit-log row for the call, so quote it in a support request. Present on every response of the keyed API. required: true schema: type: string format: uuid example: 3f6c1d2e-8a4b-4f7e-9c21-5b0d7e6a9f13 XRateLimitUsed: description: Calls used in that window (`limit − remaining`). schema: type: integer minimum: 0 example: 588 RetryAfter: description: Seconds to wait before retrying (RFC 9110 delay-seconds, at least 1). Sent on every 429 (quota, concurrency, authentication-failure) and every 503; when the body carries `retry_after_seconds` it is the same value. required: true schema: type: integer minimum: 1 example: 10 schemas: DemoKeyNotAllowedError: type: object description: 403 for the public demo key (`msk_demo_…`) outside its three-endpoint allow-list. `endpoint_tier` is the endpoint's real minimum plan (null when unknown). required: - error - message - allowed_endpoints properties: error: type: string enum: - demo_key_endpoint_not_allowed message: type: string endpoint_tier: type: string nullable: true enum: - FREE - PRO - ULTRA - BUSINESS - ENTERPRISE - null allowed_endpoints: type: array items: type: string signup_url: type: string format: uri upgrade_url: type: string format: uri description: Only when the endpoint's tier can be bought at /checkout. RhcCopytradeTrackedWallets: type: array items: type: string nullable: true description: 'DEPRECATED 2026-10-04 (kept, still filled): subset of source_wallets in the tracked KOL set (kol_evm_wallets, the set behind /rhc/kol/wallets). KOL enrichment only once source_admission is any_wallet; under the legacy kol_only engine only these can produce a signal. null when the reference read failed.' ConcurrencyLimitError: type: object description: '429 from the heavy-query limiter: too many heavy requests in flight for this key (`concurrency`) or for the whole server (`capacity`). Clears as soon as in-flight requests finish.' required: - error - error_kind - retry_after_seconds properties: error: type: string error_kind: type: string enum: - concurrency - capacity retry_after_seconds: type: number max_concurrent: type: integer support: type: string _rid: type: string RhcCopytradeMonitoringReasons: type: array items: type: string description: 'Present only with operational_state monitoring_unavailable: the infrastructure reasons (e.g. dex_stream_stale, trade_stream_stale, source_producer_stale, map_stale, bus_disconnected, engine_state_stale). Added 2026-10-04.' TierRequiredError: type: object description: 403 when the key's tier is below the endpoint's (or a parameter's) gate. `required_tier` matches the operation's `x-madeonsol-tier` or `x-madeonsol-feature-tiers`. ENTERPRISE gates return `contact` instead of `upgrade`. required: - error - message - your_tier - required_tier properties: error: type: string enum: - tier_required message: type: string feature: type: string your_tier: type: string enum: - BASIC - PRO - ULTRA - BUSINESS - ENTERPRISE required_tier: type: string enum: - PRO - ULTRA - BUSINESS - ENTERPRISE upgrade: type: object description: The plan that lifts this limit, with price and a checkout link. properties: tier: type: string enum: - PRO - ULTRA - BUSINESS - ENTERPRISE price_eur_per_month: type: number price_usdc_per_month: type: number daily_limit: type: integer burst_limit: type: integer pitch: type: string url: type: string upgrade_url: type: string format: uri reactivate: type: boolean description: Present (true) when the key's paid subscription has just lapsed and `tier` is the plan it held. prior_tier: type: string enum: - PRO - ULTRA - BUSINESS contact: type: object properties: url: type: string contact_url: type: string pitch: type: string support: type: string _rid: type: string RhcCopytradeUntrackedWallets: type: array items: type: string nullable: true description: 'DEPRECATED 2026-10-04 (kept, still filled): subset of source_wallets NOT in the tracked KOL set. Under source_admission any_wallet they fire like any other wallet; under the legacy kol_only engine they never produce a signal. null when the reference read failed.' RhcCopytradeSourceAdmission: type: string enum: - kol_only - any_wallet description: 'Which trades the RUNNING copy-trade engine admits (shared by the Solana and Robinhood Chain rules). any_wallet: a qualifying trade by any source wallet, KOL or not (Robinhood Chain: the ERC-4337 userOp sender on bundled transactions; Solana: the same effective-trader rule as KOL attribution). kol_only: only tracked KOL wallets (kol_evm_wallets / active kol_wallets), legacy. Absent when the engine state could not be read (legacy semantics). Added 2026-10-04.' ServiceUnavailableError: type: object description: '503: a temporary capacity or maintenance condition (e.g. a Postgres statement timeout during a partition move, or the API-key lookup itself being unavailable). Retry after `Retry-After` seconds.' required: - error properties: error: type: string code: type: string description: Machine-readable code where one exists, e.g. `auth_backend_unavailable`. error_kind: type: string description: e.g. `statement_timeout`, `auth_backend` retry_after_seconds: type: number retryable: type: boolean support: type: string _rid: type: string RhcCopytradeRuleWarnings: type: array description: Present only when something needs attention (the key is omitted otherwise, never null). Additive — status codes and existing fields never change. Emitted only under source_admission kol_only (legacy); under any_wallet an untracked wallet is not a problem and no warning is attached. items: type: object required: - code - message properties: code: type: string enum: - untracked_source_wallets - source_wallet_tracking_unavailable message: type: string RhcHolderGrowthWindow: type: object nullable: true description: One holder-growth window on /rhc/tokens/{address}/holders. Pools and burn addresses are excluded from every count. properties: cutoff_block: type: integer nullable: true description: Lowest block observed at-or-after now()−window (resolved from our trade ingest, ~10 blocks/s). entered: type: integer nullable: true description: Addresses whose first Transfer of this token landed at-or-after cutoff_block (any current balance). entered_still_holding: type: integer nullable: true description: entered ∩ balance > 0. exited: type: integer nullable: true description: Pre-existing holders whose last Transfer in the window left them at zero. net: type: integer nullable: true description: entered_still_holding − exited ≈ change in holder_count over the window. RhcTokenRiskSummary: type: object nullable: true description: 'Precomputed risk summary for a Robinhood Chain token, from the same engine as `/rhc/tokens/{address}/risk` (proxy resolution, capability scan, and a live router sell-simulation). **`null` means NOT ASSESSED, not safe.** The sweep covers tokens with liquidity on a ~24h rotation, so a brand-new or illiquid token has no row yet. These values are a SNAPSHOT — always read `checked_at`. Sellability can change the moment an owner flips a setting, which is why `/rhc/tokens/{address}/risk` is computed live and never served from this cache. Use this to triage a feed; use the live endpoint before acting on a single token.' properties: sellable: type: string nullable: true enum: - 'yes' - 'no' - unknown description: '`no` means a sell was simulated through the router and REVERTED — bought-but-cannot-sell.' upgradeable: type: boolean nullable: true description: Token is a proxy whose implementation can be swapped (EIP-1967 / beacon / legacy). EIP-1167 minimal proxies are NOT upgradeable — the target is baked into immutable code. score: type: integer nullable: true description: 0–100, conservative. Absence of evidence is not evidence of safety. checked_at: type: string format: date-time description: When this assessment was computed. RhcCopytradeOperationalState: type: string enum: - eligible - monitoring_pending - monitoring_unavailable - source_capacity_unavailable - no_tracked_sources - unknown description: 'Whether the rule can fire at all, separate from is_active (the customer switch). Under source_admission any_wallet (2026-10-04) every valid source wallet is followed, KOL or not: eligible; monitoring_pending = the rule changed after the engine''s last rule load (live within seconds); monitoring_unavailable = the engine or the trade stream is not reporting, and it fires nothing until it is (see monitoring_reasons); source_capacity_unavailable = the engine''s source-wallet cap is reached. Legacy (source_admission kol_only or absent): no_tracked_sources = none of source_wallets is a tracked KOL wallet (kol_evm_wallets on Robinhood Chain, active kol_wallets on Solana), so the rule cannot fire; unknown = the tracking read failed.' RateLimitError: type: object description: '429 when a quota is exhausted: the daily quota, the per-minute burst, or a free-tier network/key-rotation cap. `datasets` is added on `daily` only.' required: - error - error_kind - message - tier - limit - resets_at properties: error: type: string enum: - rate_limit_exceeded error_kind: type: string enum: - daily - burst - ip_cap - ip_rotation message: type: string tier: type: string enum: - BASIC - PRO - ULTRA - BUSINESS - ENTERPRISE limit: type: integer resets_at: type: string format: date-time upgrade: type: object description: The plan that lifts this limit, with price and a checkout link. properties: tier: type: string enum: - PRO - ULTRA - BUSINESS - ENTERPRISE price_eur_per_month: type: number price_usdc_per_month: type: number daily_limit: type: integer burst_limit: type: integer pitch: type: string url: type: string upgrade_url: type: string format: uri reactivate: type: boolean description: Present (true) when the key's paid subscription has just lapsed and `tier` is the plan it held. prior_tier: type: string enum: - PRO - ULTRA - BUSINESS datasets: type: object properties: pitch: type: string url: type: string format: uri Error: type: object description: Generic error envelope. `error` is always present (SDKs match on it). Errors returned after authentication also carry `_rid` and, on paid tiers, `support`; authentication-stage errors (missing/invalid key, origin) carry neither. properties: error: type: string description: Error message or machine code (e.g. `tier_required`, `rate_limit_exceeded`). Never changed once shipped. message: type: string description: Human-readable explanation, when `error` is a machine code. code: type: string description: Machine-readable sub-code on some errors (e.g. `invalid_query`, `invalid_wallet`, `origin_not_allowed`). error_kind: type: string description: Machine-readable category on some errors (e.g. `statement_timeout`, `concurrency`, `daily`). detail: type: string description: Extra human-readable context. hint: type: string retry_after_seconds: type: number description: When present on a 429/503, the same value is sent as the `Retry-After` header. signup_url: type: string format: uri description: 'On the missing-key / bad-format 401: where to get a free key.' docs_url: type: string format: uri support: type: string description: 'Paid tiers, errors after authentication: priority support contact.' _rid: type: string description: Request ID — include when reporting issues required: - error responses: ServiceUnavailable: description: '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.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/ServiceUnavailableError' examples: statement_timeout: summary: Statement timeout value: error: Query timed out — this dataset is under load or being maintained. Retry shortly. error_kind: statement_timeout retry_after_seconds: 10 _rid: eyJ1IjoiZXhhbXBsZSIsInQiOjE3OTEwMDAwMDAwMDAsImgiOiIwMDAwMDAwMCJ9 auth_backend: summary: API-key lookup unavailable value: error: Authentication temporarily unavailable — please retry. code: auth_backend_unavailable error_kind: auth_backend retryable: true retry_after_seconds: 5 TierForbidden: description: 'Forbidden. One of: the key''s tier is below this endpoint''s or parameter''s gate (`tier_required` with an `upgrade` block); the public demo key used outside its allow-list (`demo_key_endpoint_not_allowed`); an invalid or revoked key; an origin-restricted key called from a disallowed origin (`code` `origin_not_allowed` / `origin_required`). `X-RateLimit-*` headers are present only on `tier_required`.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: anyOf: - $ref: '#/components/schemas/TierRequiredError' - $ref: '#/components/schemas/DemoKeyNotAllowedError' - $ref: '#/components/schemas/Error' examples: tier_required: summary: Tier below the gate value: error: tier_required message: This endpoint requires ULTRA tier — you're on PRO. feature: This endpoint your_tier: PRO required_tier: ULTRA upgrade: tier: ULTRA price_eur_per_month: 131 price_usdc_per_month: 149 daily_limit: 100000 burst_limit: 600 pitch: … url: https://madeonsol.com/pricing upgrade_url: https://madeonsol.com/checkout?tier=ULTRA support: 'Priority support: info@madeonsol.com' _rid: eyJ1IjoiZXhhbXBsZSIsInQiOjE3OTEwMDAwMDAwMDAsImgiOiIwMDAwMDAwMCJ9 demo_key: summary: Demo key outside its allow-list value: error: demo_key_endpoint_not_allowed message: The public demo key works on /kol/feed, /deployer-hunter/alerts, and /alpha/leaderboard only. This endpoint requires the PRO plan or higher; a free API key will not unlock it. See https://madeonsol.com/pricing. endpoint_tier: PRO allowed_endpoints: - /api/v1/kol/feed - /api/v1/deployer-hunter/alerts - /api/v1/alpha/leaderboard signup_url: https://madeonsol.com/developer upgrade_url: https://madeonsol.com/checkout?tier=PRO revoked_key: summary: Invalid or revoked key value: error: Invalid or revoked API key InternalError: description: 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. headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' content: application/json: schema: $ref: '#/components/schemas/Error' examples: route: summary: Route error value: error: Internal server error _rid: eyJ1IjoiZXhhbXBsZSIsInQiOjE3OTEwMDAwMDAwMDAsImgiOiIwMDAwMDAwMCJ9 RateLimited: description: 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-*`). headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-RateLimit-Limit: $ref: '#/components/headers/XRateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/XRateLimitRemaining' X-RateLimit-Used: $ref: '#/components/headers/XRateLimitUsed' X-RateLimit-Reset: $ref: '#/components/headers/XRateLimitReset' Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: anyOf: - $ref: '#/components/schemas/RateLimitError' - $ref: '#/components/schemas/ConcurrencyLimitError' - $ref: '#/components/schemas/Error' examples: daily: summary: Daily quota exhausted value: error: rate_limit_exceeded error_kind: daily message: Daily rate limit exceeded — 200/day for BASIC tier. Resets at midnight UTC. tier: BASIC limit: 200 resets_at: '2026-10-05T00:00:00.000Z' upgrade: tier: PRO price_eur_per_month: 43 price_usdc_per_month: 49 daily_limit: 10000 burst_limit: 300 pitch: … url: https://madeonsol.com/pricing upgrade_url: https://madeonsol.com/checkout?tier=PRO datasets: pitch: … url: https://madeonsol.com/datasets concurrency: summary: Too many heavy queries in flight value: error: Too many concurrent heavy queries. Up to 8 of these endpoints may be in flight at once per key — retry in a moment, or lower your request concurrency. error_kind: concurrency retry_after_seconds: 2 max_concurrent: 8 _rid: eyJ1IjoiZXhhbXBsZSIsInQiOjE3OTEwMDAwMDAwMDAsImgiOiIwMDAwMDAwMCJ9 auth_failures: summary: Per-IP authentication-failure block value: error: Too many authentication failures from this IP. Retry in 60s. retry_after_seconds: 42 AuthBackendUnavailable: description: 'The API-key or subscription lookup could not be answered (authentication stage). Retryable and not your fault: it is never counted as a failed authentication. Honour `Retry-After`; no `X-RateLimit-*`, no `_rid`.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/ServiceUnavailableError' examples: auth_backend: summary: API-key lookup unavailable value: error: Authentication temporarily unavailable — please retry. code: auth_backend_unavailable error_kind: auth_backend retryable: true retry_after_seconds: 5 Unauthorized: description: 'Missing or invalid API key, or an expired free-tier key. Authentication-stage error: no `X-RateLimit-*` headers, no `_rid`.' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' content: application/json: schema: $ref: '#/components/schemas/Error' examples: missing_key: summary: No Bearer key value: error: 'Missing authentication — use API key (Authorization: Bearer msk_...)' hint: Get a free API key — 200 calls/day, no payment signup_url: https://madeonsol.com/developer docs_url: https://madeonsol.com/api-docs bad_format: summary: Malformed key value: error: Invalid API key format hint: Get a free API key — 200 calls/day, no payment signup_url: https://madeonsol.com/developer docs_url: https://madeonsol.com/api-docs parameters: Limit: name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 50 securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: msk_... description: Get a free API key at https://madeonsol.com/developer x-madeonsol-tiers: - tier: FREE plan: BASIC name: Free price_eur_monthly: 0 price_eur_annual: 0 price_usd_monthly: 0 daily_limit: 200 burst_limit: 60 url: https://madeonsol.com/developer - tier: PRO plan: PRO name: Pro price_eur_monthly: 43 price_eur_annual: 430 price_usd_monthly: 49 daily_limit: 10000 burst_limit: 300 url: https://madeonsol.com/checkout?tier=PRO - tier: ULTRA plan: ULTRA name: Ultra price_eur_monthly: 131 price_eur_annual: 1310 price_usd_monthly: 149 daily_limit: 100000 burst_limit: 600 url: https://madeonsol.com/checkout?tier=ULTRA - tier: BUSINESS plan: BUSINESS name: Business price_eur_monthly: 400 price_eur_annual: 4000 price_usd_monthly: 456 daily_limit: 500000 burst_limit: 3000 url: https://madeonsol.com/checkout?tier=BUSINESS - tier: ENTERPRISE plan: ENTERPRISE name: Enterprise price_eur_monthly: null price_eur_annual: null price_usd_monthly: null daily_limit: null burst_limit: null url: https://madeonsol.com/pricing#enterprise