---
title: "Open positions on Robinhood Chain (PRO+)"
method: GET
path: "/rhc/wallet/{address}/positions"
tags: ["Robinhood Chain"]
---

# Open positions on Robinhood Chain (PRO+)

`GET /rhc/wallet/{address}/positions`

## Request

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

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 < balance < FIFO), `TRANSFERRED_OR_DISPOSED` (balance 0), `EXTERNAL_INFLOW` (balance > 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+**.

## Path parameters

- `address` string, required

## Response `200`

OK. Sorted by current value, then cost basis.

- object
  - `chain` 'robinhood'
  - `address` string
  - `window_days` integer
  - `summary` object
    - `open_positions` integer
    - `total_cost_basis_eth` number
    - `total_current_value_eth` number: Priced positions only.
    - `total_unrealized_eth` number: Against the cost basis of the priced subset only.
    - `unpriced_positions` integer
    - `holdings` object, nullable: 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.
      - `balance_source` 'rhc_node_multicall3'
      - `checked_at` string, date-time
      - `complete` boolean
      - `fifo_open_positions` integer
      - `held` integer
      - `partially_reduced` integer
      - `transferred_or_disposed` integer
      - `external_inflow` integer
      - `unverified` integer
      - `verified_value_eth` number: 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` integer
      - `cost_basis_held_eth` number: Cost basis of the FIFO-known portion still in the wallet.
      - `unrealized_known_eth` number: Unrealized PnL on the portion whose cost basis is known AND still held. External inflows never add trading profit.
      - `cost_basis_not_held_eth` number: Cost basis of FIFO lots no longer in the wallet (transferred out or disposed outside indexed swaps). Outcome unknown: neither realized nor unrealized.
  - `positions` object[]
    - `token_address` string
    - `token_symbol` string, nullable
    - `token_name` string, nullable
    - `launchpad` string, nullable
    - `is_graduated` boolean, nullable
    - `token_amount` number
    - `cost_basis_eth` number
    - `avg_entry_price_eth` number
    - `current_price_eth` number, nullable
    - `current_value_eth` number, nullable
    - `unrealized_eth` number, nullable
    - `unrealized_pct` number, nullable
    - `current_mc_usd` number, nullable
    - `liquidity_usd` number, nullable
    - `liquidity_basis` 'v4_virtual_ceiling' | 'measured': 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` integer
    - `realized_so_far_eth` number: Partial exits already taken on this token.
    - `first_buy_at` string, date-time, nullable
    - `last_buy_at` string, date-time, nullable
    - `fifo_unmatched_amount` number, nullable: DEX buys not matched by a DEX sell (same as token_amount). A trading position, not a balance.
    - `current_onchain_balance` number, nullable: balanceOf(wallet) / 10^decimals from our node. null = not proven (BALANCE_UNVERIFIED).
    - `holding_status` 'HELD' | 'PARTIALLY_REDUCED' | 'TRANSFERRED_OR_DISPOSED' | 'EXTERNAL_INFLOW' | 'BALANCE_UNVERIFIED'
    - `holding_unverified_reason` 'rpc_unavailable' | 'call_failed' | 'decimals_failed' | 'over_cap' | 'decimals_mismatch' | 'decimals_unknown', nullable
    - `held_known_amount` number, nullable: min(balance, FIFO): the held part whose cost basis is known.
    - `external_inflow_amount` number, nullable
    - `current_holding_value_eth` number, nullable: current_onchain_balance x current price. 0 when transferred out; null when unverified or unpriced.
    - `cost_basis_held_eth` number, nullable
    - `unrealized_known_eth` number, nullable: Unrealized on the known-cost, still-held portion only.
    - `cost_basis_not_held_eth` number, nullable: Cost basis of the FIFO portion no longer in the wallet. Outcome unknown.
  - `notes` object

## Other responses

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

---

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