---
title: "List current positions (positions-board feed)"
method: GET
path: "/api/v1/positions"
tags: ["Positions"]
---

# List current positions (positions-board feed)

`GET /api/v1/positions`

Returns the current positions-board feed backed by the wallet_positions mirror. Ordered by current_value_usd DESC with deterministic (wallet, condition_id, outcome_index) tiebreakers. Pre-reconcile rows (current_value_usd IS NULL) are excluded. Cursor-paginated. Every filter pushes into SQL.

## Query parameters

- `limit` integer
- `cursor` string
- `min_size` number
- `category` string
- `min_grade` 'S' | 'A' | 'B' | 'C' | 'D' | 'F'
- `side` 'yes' | 'no'

## Headers

- `If-None-Match` string

## Response `200`

Page of positions

- object
  - `object` 'list', required
  - `data` Position[], required
    - `id` string, required — Composite prefixed ID `pos_<wallet>:<condition_id>:<outcome_index>`.
    - `platform` 'polymarket' | 'kalshi', required — Provider discriminator. Slice 5 ships Polymarket only; the field stays in the response shape so Kalshi positions can land without a breaking change.
    - `wallet` string, required — Lowercased proxy wallet address.
    - `side` 'YES' | 'NO', required — Binary outcome side. Non-binary positions are not surfaced on V1.
    - `token_id` string, nullable — The Polymarket CLOB token id (ERC1155 asset id, decimal string) for this outcome; null when unavailable (e.g. Kalshi markets, unsynced markets).
    - `shares` number, required — Live share count from the wallet_positions mirror.
    - `avg_price` number, nullable — Volume-weighted entry price for this leg.
    - `current_value_usd` number, required — Current mark-to-market value in USD (always non-null on V1 — pre-reconcile rows are excluded).
    - `initial_value_usd` number, nullable
    - `cash_pnl` number, nullable — Unrealized P&L for the open position (Polymarket `cashPnl`).
    - `realized_pnl` number, nullable — Closed-leg P&L rolled up (Polymarket `realizedPnl`).
    - `last_reconciled_at` string, date-time, nullable — Max updated_at across mirror legs for this pair.
    - `freshness` 'fresh' | 'refreshing' | 'stale' | 'unknown', required — Backend-computed staleness bucket derived from last_reconciled_at.
    - `trader` object, required
      - `id` string, required — Prefixed ID (`trd_...`).
      - `address` string, required
      - `username` string, nullable
      - `grade` 'S' | 'A' | 'B' | 'C' | 'D' | 'F', nullable
      - `win_rate` number, nullable — Percentage 0-100.
      - `pnl` number, nullable
      - `markets` integer, nullable
      - `wallet_age_days` number, nullable
      - `is_new_wallet` boolean, required — Wallet is younger than the new-wallet threshold (30 days).
    - `market` object, required
      - `id` string, required — Prefixed ID (`mkt_...`).
      - `condition_id` string, required
      - `title` string, required
      - `slug` string, nullable
      - `event_slug` string, nullable
      - `category` string, nullable — Provider-backed market_canonical category.
      - `outcome_label` string, nullable — Provider-reported outcome label (e.g. team name for sports). Separate from `side` because provider labels can diverge from the binary Yes/No axis.
      - `end_date` string, date-time, nullable
  - `has_more` boolean, required
  - `next_cursor` string, nullable
  - `meta` ResponseMeta, required
    - `request_id` string, required — Unique request ID (req_ prefix).
    - `cached` boolean, required
    - `cache_age_s` integer, nullable — Cache age in seconds, null if not cached.

## Other responses

- `304` — Not Modified. Returned when If-None-Match matches the current payload.
- `400` — Invalid request parameter
- `401` — Missing or invalid API key
- `402` — Active Insider subscription required
- `403` — Account access denied
- `408` — Request exceeded the server's 30-second transport timeout. The timeout response has an empty body because it is generated before handler-level JSON error shaping.
- `423` — Account is locked
- `429` — Rate limit exceeded (100 req/min; batch endpoints also reserve 100 batch item units/min before execution)
- `503` — Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown

## Changes

- **2026-07-01** `1777a41bfb53` — 1 info
  - added the optional property `data/items/token_id` to the response with the `200` status
- **2026-06-01** `422bd4dc1611` — 63 warning, 3 info
  - added the new `account_locked` enum value to the `error/code` response property for the response status `400`
  - added the new `account_locked` enum value to the `error/code` response property for the response status `401`
  - added the new `account_locked` enum value to the `error/code` response property for the response status `402`
  - added the new `account_locked` enum value to the `error/code` response property for the response status `403`
  - …62 more
- **2026-05-07** `2907497f4ca3` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/0xinsider/apis/0xinsider-api/changes/api/v1/positions/get.md)

---

[API](https://skmtc.dev/0xinsider/apis/0xinsider-api.md) · [All operations](https://skmtc.dev/0xinsider/apis/0xinsider-api/llms.txt) · [OpenAPI document](https://skmtc.dev/0xinsider/apis/0xinsider-api/revisions/137fa0fd3297?raw)
