Who Holds a Polymarket Market?
Pull open Polymarket positions across every wallet in a market with one Data API call. Shares from on-chain balances, live marks, honest nulls, cursor pagination up to 1,000 rows.
You used to answer "who holds this market?" one wallet at a time. Now one signed call returns every open position Bravado indexes for that market. GET /v2/polymarket/positions pages up to 1,000 rows per request. Shares come from on-chain balances. Marks are live. Unknown values stay null.
This post shows what the endpoint returns, where the numbers come from, and a real snapshot of the 2026 House control market as of 12:15 PM ET on Nov 2, 2026.
What does market-wide positions return?
The same position model that powers GET /trader-analytics/positions is available across every indexed wallet. On the Polymarket surface the venue is fixed, so you do not pass a venue parameter.
One request can answer three questions:
What does this wallet hold? Pass
wallet.Who holds this market or token? Pass
market_id,condition_id, ortoken_id.What changed since I last looked? Pass
updated_after(unix ms) and follow the cursor.
A request must be bounded. You need at least one of those filters. A bare status=open returns 400 with "code": "unbounded_scan".
Each row includes the wallet, market and token ids, outcome label, shares, average entry, cost basis, live price and value, realized and unrealized PnL, status, and mark metadata. Money and share fields are exact decimal strings with 6 places. Parse them with a decimal type.
You can narrow further with status, time or block ranges, and min_position_value. Page size is 1 to 1,000. Follow next_cursor until it is null.
Where do the numbers come from?
Four rules matter when you read a row.
Shares. On Polymarket, shares come from on-chain balanceOf state on Polygon. The row marks that with open_value_source: "book". Amounts are computed from integer micro-units, then returned as 6-decimal strings.
Money fields. Prices, values, cost basis, and PnL are exact decimal strings. They are not floating-point guesses.
Cost basis. Cost basis comes only from recorded lots. If there is no lot record, cost_basis and avg_entry_price are null. Bravado does not estimate them. Unknown is never written as "0.000000".
Live marks. Marks are computed on every request. They are not cached on the position. The order is:
Resolution payout, if the market has resolved.
A fresh quote.
The last real trade.
Unknown.
If none of those exists, mark_source is unknown and current_price, current_value, and unrealized_pnl are null. Unknown is never reported as 0.
One more honesty rule: when open_value_source is unknown_book_unseeded, Bravado has not indexed that wallet's on-chain balances yet. In that case shares, cost fields, current_value, and unrealized_pnl are all null. The row is a placeholder, not a guess.

Text version: mark order is resolution → quote → trade → unknown. Cost basis is lot-only or null. Unseeded books return null shares and value, never estimates.
What did the House market look like?
Here is one real call against the 2026 House control market. The numbers below are from signed GET /v2/polymarket/positions responses served at about 12:15 PM ET on Nov 2, 2026. They are one snapshot. They are not a typical day and not live as of this post.
Market id:
562802Condition id:
0xd5d9fc47718bd553592d126b1fa5e87183d27f3936975b0c04cc0f2dec1f1bb4Filter:
status=open, six pages atlimit=1000
At that moment the market had:
Metric | Value |
|---|---|
Open positions | 5,253 |
Unique wallets | 5,167 |
Live marked value | $12.49M |
Yes open positions | 4,584 at 0.945 |
No open positions | 669 at 0.055 |
Top 10 wallets | 37.7% of marked value |
The largest single position was 1.25M Yes shares. Average entry was 0.9396. Marked value was $1.18M. Four Yes positions were not yet seeded on our side. Those rows returned null shares and value instead of a guessed number.

Text version: 5,253 open positions across 5,167 wallets; $12.49M marked live; Yes 4,584 at 0.945; No 669 at 0.055; top 10 wallets 37.7%.

Text version: largest Yes position 0xfea3…d227, 1.25M shares, avg 0.9396, value $1.18M. Next Yes rows: $945K, $760K, $409K, $306K. Two No positions appear in the top 10, including one with null average entry because no lot was recorded.

Text version: 4,584 Yes positions marked at 0.945; 669 No positions marked at 0.055. Seeded Yes shares 12.485M; seeded No shares 12.507M.
Client-side ranking matters. The API order for a market query is by token then wallet, not by value. Sort locally if you need the largest holders.
How do you query it?
Three common patterns:
Question | Filters |
|---|---|
What does this wallet hold? |
|
Who holds this market? |
|
What changed in a market? |
|
Docs also allow updated_after on its own for a global state sync. For day-to-day market monitoring, pair it with condition_id, market_id, or token_id.

Text version: wallet → holdings for one address. market_id / condition_id / token_id → every holder. updated_after + market filter → incremental changes. Page with cursor up to 1,000 rows.
Example: the three largest open positions above $250,000 in the House market. Replace the signature headers with a fresh HMAC for each request. See the request signing examples.
Use the documented parameter min_position_value, not min_value. Follow next_cursor for more pages. The response includes served_at (when the live marks were read) and unpriced_positions (open rows with an unknown mark in the span this page covered).
The Polymarket /v2/polymarket/* surface uses a Data API credential with the analytics.read scope. You can try the call in Console. Full field reference: GET /positions.
Why use Bravado?
Bravado is prediction market infrastructure. The Data API gives you licensed Polymarket analytics from on-chain settlement, not a scraped UI.
For positions today:
Market-wide holders. One call for every indexed wallet in a market, token, or change window.
Honest unknowns. Null when cost or mark is unknown. No silent zeros.
Live marks. Resolution, quote, then trade, computed on each request.
Same model, two mounts.
/v2/polymarket/positionsand/trader-analytics/positionsshare filters, fields, and pagination. The positions page is the integer-exact source of record.Console. Sign a request and inspect the JSON without wiring your app first.
Related reading:
Conclusion
If you need the holders of a market, query the market once. Do not loop wallets.
Use
condition_id,market_id, ortoken_idfor the full open book of holders.Use
walletwhen the question is about one address.Use
updated_afterwith a market filter to keep a local copy current.Trust nulls. A missing cost or mark is better than a made-up zero.
Start at the positions docs or try it in Console.
Read more blogs
Trading insights, market analysis, and strategies for Polymarket prediction markets.





