Positions
Onchain V2 (legacy)
Positions (All)
Query every position on Polymarket. Filter by wallet, market, status, or minimum size. Full history with cursor pagination.
GET
Positions
Search and filter all Polymarket positions across every wallet. Each position is enriched with market metadata and includes realized P&L, average entry price, and current size. Sourced directly from onchain settlement data.Documentation Index
Fetch the complete documentation index at: https://docs.polynode.dev/llms.txt
Use this file to discover all available pages before exploring further.
Request
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
wallet | string | No | Filter by wallet address |
market_slug | string | No | Filter by market slug (e.g. will-zohran-mamdani-win-the-2025-nyc-mayoral-election) |
condition_id | string | No | Filter by condition ID (0x-prefixed, 64 hex chars) |
token_id | string | No | Filter by outcome token ID |
status | string | No | open (size > 0), closed (size = 0), or all (default) |
min_size | number | No | Minimum position size in shares |
limit | integer | No | Results per page (1-500, default 100) |
order | string | No | Sort direction: desc (default, most recent first) or asc. When wallet is set, results are ordered by the wallet’s most recent on-chain activity per position. Otherwise, ordered by position ID. |
pagination_key | string | No | Cursor from a previous response to fetch the next page. Not used for wallet queries (see Pagination). |
Identifying markets
market_slug— human-readable URL slug from Polymarket. Returns positions for all outcomes.condition_id— unique condition identifier. Returns positions for all outcomes.token_id— specific outcome token. Returns positions for only that outcome.
Response
Position fields
| Field | Type | Description |
|---|---|---|
wallet | string | Wallet address holding the position |
token_id | string | Outcome token ID |
size | number | Current position size in shares. 0 means the position is fully exited. |
avg_price | number | Average entry price (0 to 1) |
realized_pnl | number | Realized profit/loss in USD. Reflects gains/losses from closed portions of the position and from onchain redemptions of resolved markets. Stays 0 for resolved-but-not-yet-redeemed positions; check redeemable to detect those. |
unrealized_pnl | number | Unrealized profit/loss in USD on the remaining open shares. For resolved markets, uses the final settlement price (1.0 for winners, 0.0 for losers). For live markets, uses the current market price. Returns 0 when size = 0. Byte-identical to Polymarket’s cashPnl field for any position covered by both. |
current_price | number | null | Price used to compute unrealized_pnl. 1.0 or 0.0 for resolved markets (derived deterministically from on-chain payoutNumerators), the live market price for active markets, and null when size = 0 or no price is available. |
market_status | string | One of: "live" (market still trading), "resolved-win" (market resolved, this outcome won), "resolved-loss" (market resolved, this outcome lost), or "closed" (position fully exited, size = 0). A fifth value "resolved-unknown" may appear briefly for very old markets while resolution data is catching up. Never "live" when resolved_at is set. |
won | boolean | undefined | Present only on resolved-win / resolved-loss rows. true when this outcome won, false when it lost. Derived from on-chain payouts. |
winning_outcome_index | number | undefined | Present only on resolved rows. Numeric index of the outcome that won (0 or 1 for binary markets). Pair with outcome_index to know whether this row is the winning side. |
outcome_index | number | undefined | Numeric index of this row’s outcome within the market’s outcomes array (0 or 1 for binary markets). Stable across the API regardless of how the UI labels the outcome (Yes/No, team names, etc.). Use this for cross-row joins instead of parsing outcome strings. |
total_bought | number | Total amount bought in USD over the lifetime of the position. |
initial_value | number | undefined | Cost basis in USD of the currently held shares (size × cost_per_share). Use this if you need the basis number that matches Polymarket cashPnl and what users see in the Polymarket UI. |
redeemable | boolean | undefined | true when the market has resolved and the user can call redeem on the CTF contract to claim payout (or accept loss). Useful for detecting “resolved-but-not-redeemed” positions: filter market_status = "resolved-loss" AND redeemable = true for unclaimed losses, or market_status = "resolved-win" AND redeemable = true for unclaimed wins. |
opposite_asset | string | undefined | Token ID of the OPPOSITE outcome on the same market (the binary counterpart). Useful for fetching the matching position on the other side without re-resolving the condition. |
market | string | Market question text |
market_slug | string | Market URL slug |
outcome | string | Outcome label (e.g. “Yes”, “No”) |
condition_id | string | Market condition ID |
image | string | null | Market image URL. null for some delisted or niche markets. |
event_slug | string | null | Parent event slug, distinct from the per-row market slug. For multi-market events (NBA games with several lines, election markets with several candidates, FIFA World Cup with one market per team), this is the parent the markets share. For single-market events, equals the market slug. null when event metadata is not yet known. |
last_activity | number | undefined | Unix timestamp of the wallet’s most recent fill on this position. Present only when querying by wallet. Positions with no fill history (e.g. acquired purely via split/merge/redemption) omit this field and sort to the end. |
last_trade_at | number | null | Unix seconds. Latest fill on this token across V1 + V2 exchanges. Same data as last_activity but always present (null instead of omitted) for consistent shape. Use either; last_trade_at is preferred for new integrations. |
closed_at | number | null | Unix seconds. Latest moment this wallet redeemed any outcome of the market for collateral. null when the wallet has not redeemed (open positions, positions sold to zero pre-resolution, or wins held but not yet redeemed). |
resolved_at | number | null | Unix seconds. Moment the market was resolved on-chain (when payouts became redeemable). null for markets that resolved before polynode began tracking, or for markets that have not yet resolved. Recent markets are fully covered. |
Pagination fields
| Field | Type | Description |
|---|---|---|
count | number | Number of positions in this response |
pagination.limit | number | Requested page size |
pagination.has_more | boolean | true if more results exist beyond this page |
pagination.pagination_key | string | Pass this as pagination_key in the next request to get the next page |
Examples
All positions for a wallet
Open positions only
Usestatus=open to get only positions with a non-zero size.
Who holds a market
Usemarket_slug to see all wallets with positions on a specific market.
Large positions
Usemin_size to find positions above a threshold.
Combined filters
Filter by wallet, market, and status at once.Pagination
Wallet queries return every position for the wallet in a single response (up to 500), sorted by most recent on-chain activity. No pagination needed — requestlimit=500 and read all results. has_more is always false and no cursor is returned. Wallets with more than 500 lifetime positions are capped at 500.
Non-wallet queries (filtering by market_slug, condition_id, token_id, or min_size alone) use cursor-based pagination for iterating through large result sets.
Error responses
| Status | Response | Condition |
|---|---|---|
| 400 | {"error": "market_slug not found"} | Invalid or unknown market_slug |
| 400 | {"error": "condition_id not found"} | Invalid or unknown condition_id |
| 401 | {"error": "API key required. Pass via ?key= or x-api-key header."} | Missing API key |
| 403 | {"error": "V2 endpoints require a paid plan. See polynode.dev/pricing for details."} | Free tier key |
| 429 | {"error": "Rate limited. N req/s for your tier.", "retryAfterMs": ...} | Rate limited |
Notes
- Position data is sourced from onchain settlement records. Every position that was ever opened on Polymarket is included.
- The
realized_pnlfield reflects actual profit/loss from closed portions of the position, including onchain redemptions of resolved markets. For open positions, it reflects any partial closes. - The
unrealized_pnlfield shows the paper profit/loss on the remaining open shares. For resolved markets, this uses the final settlement price (0 for losers). For active markets, the current market price is used. market_statuslets clients distinguish live-tradable positions from positions on resolved markets that the wallet never redeemed. Resolved-and-never-redeemed positions still havesize > 0and will show the correct terminalunrealized_pnl.- Market metadata (
market,market_slug,outcome,condition_id,image) is enriched from our index. Very old or delisted markets may not have metadata. - When querying by
wallet, the sort key is the timestamp of the most recent fill for each position, not the position’s close date. A position bought months ago and held to resolution (closed only via redemption) will sort by its original buy date.
Verifying parity with Polymarket
Per-position fields on this endpoint match Polymarket’sdata-api.polymarket.com/positions byte-for-byte. Anyone can verify directly with the standalone Node script below — no internal access required.
Field map
| polynode field | Polymarket field |
|---|---|
token_id | asset |
condition_id | conditionId |
size | size |
avg_price | avgPrice |
realized_pnl | realizedPnl |
unrealized_pnl | cashPnl |
current_price | curPrice |
outcome | outcome |
Self-test script (Node 18+, no dependencies)
What this proves
If you trust Polymarket’s positions page, you can trust ours — they’re computing the same thing from the same on-chain events. Use this script as ongoing regression coverage in your own integration if PnL accuracy is critical to your product.Query Parameters
Filter by wallet address
Filter by market slug
Filter by condition ID
Filter by outcome token ID
Filter by position status
Available options:
open, closed, all Minimum position size in shares
Results per page (1-500, default 100)
Required range:
1 <= x <= 500Sort direction
Available options:
desc, asc Cursor from a previous response to fetch the next page
Response
Position results with pagination

