Products
Datacenter proxies from $19/mo Rotating proxies from $49/mo ISP proxies from $33/mo Dedicated proxies from $3.50/mo UDP proxies from $5/mo Try proxies
Use cases
Data & scraping AI services Social media & messaging E-commerce & finance Media & entertainment Marketing & ads Automation & tools All use cases →
Pricing
Full pricing table All 20 locations Money-back guarantee
Resources
Blog Proxy API MCP server Setup guides FAQ For business About us Affiliate program
English
English Русский
← PapaProxy.net Blog

How to read Polymarket positions and activity by wallet

Polymarket splits its API across three hosts, and wallet positions live on only one of them. The Data API takes an address and returns what that wallet holds — at 150 requests per 10 seconds, counted per IP.

API & data August 8, 2026 4 min read Alex Young Alex Young Technical specialist
Key takeawaysWallet positions live only on data-api.polymarket.com; Gamma serves market metadata and the CLOB serves books, prices and your own authenticated ledger.
  • Wallet positions live only on data-api.polymarket.com; Gamma serves market metadata and the CLOB serves books, prices and your own authenticated ledger.
  • Query the account's User Profile Address, which depends on the account type — EOA, POLY_PROXY, GNOSIS_SAFE or POLY_1271; for a plain EOA the funder is the EOA itself. The wrong address returns an empty array rather than an error.
  • /positions defaults to sizeThreshold=1.0 and limit=100 (max 500, offset up to 10,000) — set the threshold to 0, page through offset, and read outcomeIndex alongside size.
  • /activity accepts twelve types, not six: DEPOSIT, WITHDRAWAL, YIELD, MAKER_REBATE, TAKER_REBATE and REFERRAL_REWARD join the trading ones, deposits and withdrawals need excludeDepositsWithdrawals=false, start/end are epoch seconds, and offset past 5,000 is rejected with a 400.
  • Limits are IP-based: /positions and /closed-positions allow 150 req/10s, /trades 200, and the Data API overall 1,000. Documentation describes queueing, but our August 2026 test found immediate 429s without gradual slowdown.
  • Reading is fully public; L1/L2 authentication — with the signature type and funder address matched to the account type — is needed only for trading and for your own ledger.

This summary was created with AI.

Where the Data API lives

The base URL is https://data-api.polymarket.com, separate from Gamma (markets and events) and from the CLOB (order books and trading). The mental model that saves the most time: Gamma tells you what exists, the CLOB tells you what it costs, and the Data API tells you who is holding it.

The data-api positions endpoint is a plain GET that needs no key, no signature and no account — the Data API documents its routes as public:

Text
GET https://data-api.polymarket.com/positions?user=0x...&sizeThreshold=50&limit=500

The user positions endpoint takes user as its only required parameter and layers useful filters on top. market accepts one or more condition IDs as a comma-separated list, eventId does the same for events and is mutually exclusive with market. sizeThreshold sets the minimum position size to include and defaults to 1.0, which quietly hides dust — set it to 0 if you need everything. redeemable and mergeable narrow the response to positions in those states, and pagination runs on limit (default 100, maximum 500) plus offset (maximum 10,000). Sorting is available through sortBy — CURRENT, INITIAL, TOKENS, CASHPNL, PERCENTPNL, TITLE, RESOLVING, PRICE or AVGPRICE, defaulting to TOKENS — with sortDirection as ASC or DESC.

A positions endpoint example returns objects with proxyWallet, conditionId, asset, size, avgPrice, initialValue, currentValue, cashPnl, percentPnl, realizedPnl, curPrice, redeemable, mergeable, negativeRisk, plus market context — title, slug, outcome, outcomeIndex, oppositeOutcome, endDate.

Two fields deserve attention before you build on them. The user parameter is documented as a User Profile Address, and which address that is depends on the account type: Polymarket supports EOA accounts alongside POLY_PROXY, GNOSIS_SAFE and POLY_1271 signature types, and for a plain EOA the funder is the EOA itself. So "always query the proxy" is the wrong rule — the right one is to query the address that holds the position for that account type, which is also what the response echoes back in proxyWallet. Querying a signing key that isn't the profile address returns an empty array rather than an error, so log which address you asked for. And outcomeIndex matters as much as size: the same market has a Yes and a No side, so a position is only meaningful together with the outcome it belongs to.

Python
import requests

DATA = "https://data-api.polymarket.com"
PAGE = 500                                    # documented maximum

def positions(profile_address, min_size=0):
    out, offset = [], 0
    while offset <= 10000:                    # documented offset ceiling
        r = requests.get(f"{DATA}/positions",
                         params={"user": profile_address, "sizeThreshold": min_size,
                                 "limit": PAGE, "offset": offset,
                                 "sortBy": "CURRENT", "sortDirection": "DESC"},
                         timeout=10)
        r.raise_for_status()
        page = r.json()
        out.extend(page)
        if len(page) < PAGE:                  # short page means this was the last one
            break
        offset += PAGE
    return out

for p in positions("0x0000000000000000000000000000000000000000")[:5]:
    print(f"{p['title'][:45]:<45} {p['outcome']:<4} "
          f"size={p['size']:>10.2f} value=${p['currentValue']:>10.2f} pnl=${p['cashPnl']:>9.2f}")

What to look at: sizeThreshold=0 overrides the default of 1.0, so dust isn't filtered out silently, and the loop pages through offset instead of stopping at the first 500 — a wallet with a wide book would otherwise be truncated without any error. The loop stops on a short page and refuses to walk past the documented offset ceiling of 10,000, which is the real limit on how deep this endpoint goes. The call returns an empty list for a wallet with nothing open — the same shape you'd get from querying an address that isn't the account's profile address.

Getting the list of wallets

Positions are useless without knowing whose positions to read, and that's what the leaderboard surface is for. The Data API exposes a leaderboard of top traders ranked by profit or volume over a time window, alongside a builder leaderboard covering apps that route order flow through Polymarket's builder programme. The leaderboard API documentation is thinner than the rest of the surface, and shapes here have moved more than once — check the current response against your parser rather than trusting a field list copied from a blog post, this one included.

The operational pattern is the same as on any venue with this pairing: rankings move slowly, positions move constantly. Fetch the leaderboard on a slow schedule, cache the wallet list, and spend your request budget on the position calls that actually change. If you need a portfolio total rather than a position breakdown, /value returns the aggregate value for a wallet in one call — considerably cheaper than pulling every position and summing it yourself.

Reading trades and activity

Positions tell you where a wallet stands now; the activity endpoint tells you how it got there. GET /activity?user=0x... returns on-chain activity ordered by timestamp, newest first, and its type filter accepts twelve values: TRADE, SPLIT, MERGE, REDEEM, REWARD, CONVERSION, DEPOSIT, WITHDRAWAL, YIELD, MAKER_REBATE, TAKER_REBATE and REFERRAL_REWARD. That list is worth reading twice, because only the first of them is a trade: splits and merges move between complementary outcome tokens, redemptions settle resolved markets, rebates and yield are income rather than activity, and treating all of them as trades will inflate any volume metric you build.

Three parameters catch people out. start and end are expressed in seconds, not milliseconds — the opposite convention from most exchange APIs. Deposits and withdrawals are excluded by default: excludeDepositsWithdrawals defaults to true and that default wins even when you name DEPOSIT or WITHDRAWAL in type, so you must pass false explicitly to see them. And history is windowed by default — omitting start or passing 0 gives roughly the last three years, while passing a positive epoch such as 1 reaches full history. side filters BUY or SELL but applies only to trades, so combining it with a REDEEM filter returns nothing.

Pagination here behaves differently from /positions, and the difference matters. The offset ceiling is 5,000, and requests past it are rejected with a 400 rather than silently clamped; to read deeper you page inside start/end windows, each of which carries its own offset budget. Ordering is stable in both directions, so pages compose without gaps or repeats. Sorting runs on sortBy with TIMESTAMP, TOKENS or CASH.

For fills specifically, /trades returns trades by wallet address with optional filters, and it carries its own tighter budget of 200 requests per 10 seconds. From the market side rather than the wallet side, the holders endpoint — GET /holders?market=... — returns the largest holders of a given market's outcome tokens, which is a direct way to discover new wallets worth watching without walking a leaderboard at all.

Positions on the other two APIs

A recurring search is for a positions endpoint on CLOB or a positions endpoint on Gamma, and the honest answer is that as of August 2026 neither is where wallet positions live. That isn't a gap in your reading — it's how the surface is divided.

The CLOB at https://clob.polymarket.com is the trading and market-data surface: order books through /book and /books, prices through /price, /midpoint and /prices-history, and your own ledger through /data/orders and /data/trades. Those last two are account-scoped and authenticated, so they show what you did, not what an arbitrary wallet holds. Gamma at https://gamma-api.polymarket.com is the metadata surface — events, markets, tags, search — and answers "what is this market and what are its condition IDs", which is exactly what you need to translate a conditionId from a positions response into a human-readable market.

So the practical shape of a tracker is three hosts doing three jobs: the Data API for wallet state, Gamma for market context, the CLOB for live prices. Each has its own rate-limit budget, which is a feature rather than a nuisance — enriching positions with market metadata draws on Gamma's allowance, not the one your position polling is spending.

Authenticating for account endpoints

Everything above is public. Authentication enters only when you place orders or read your own ledger, and it comes in two levels. L1 is a signature from your private key that creates or derives an API key; L2 is that API key, used as HMAC headers on subsequent requests. The step that trips people up is the pairing of signer and funder, because they are not always the same address: Polymarket supports several account types — a plain EOA alongside the POLY_PROXY, GNOSIS_SAFE and POLY_1271 signature types — and the client has to be told both which signature type applies and which address actually holds the funds. For an EOA account the funder is the EOA itself; for the proxy and Safe types it isn't. Get that pairing wrong and orders fail validation even though the key itself is valid.

Two things follow. First, nothing in a wallet-tracking pipeline needs credentials at all — if you're only reading positions, activity and trades by address, an unauthenticated client is the correct design. Second, when you do add trading, the API key endpoints carry their own limit of 100 requests per 10 seconds, and CLOB orders and cancellations are additionally governed by per-signer token-bucket limits that sit outside the IP-based numbers below.

Rate limits and what they mean for scale

Polymarket's limits are IP-based and enforced through Cloudflare on sliding windows rather than fixed ones. The documentation says excess requests are delayed and queued, but our August 2026 test found immediate 429 responses with no gradual slowdown. Monitor both latency and status codes, and maintain your own per-endpoint request counters instead of assuming one signal will always arrive first.

The documented Data API budgets:

Endpoint Limit
General 1,000 req / 10s
/positions 150 req / 10s
/closed-positions 150 req / 10s
/trades 200 req / 10s

For comparison, Gamma's general allowance is 4,000 per 10 seconds and the CLOB's is 9,000, with a global ceiling of 15,000 across everything.

One position call per wallet turns 150 per 10 seconds into arithmetic. Planning at about 70% of the limit to stay clear of throttling, one address supports roughly 105 wallet reads per 10-second cycle:

Wallets watched Refresh every 10s every 30s every 60s
100 1 1 1
500 5 2 1
1,000 10 4 2
5,000 48 16 8

These are budget calculations from the published limits, not measurements — treat them as a planning starting point and verify against your own traffic.

Before adding capacity, spend the software levers, because most trackers are wasteful in the same three ways. Batch by market instead of by wallet where you can: /holders answers "who holds this market" in one call, replacing dozens of per-wallet reads. Use /value when you need a portfolio total rather than every line item. And tier your polling — wallets with large live exposure deserve a short interval, dormant ones a long one, and a uniform timer spends most of its budget confirming that nothing changed.

Past those, the constraint is that the budget belongs to the IP address rather than the account, so a wide tracker either slows down or spreads across addresses. That's the part our proxies for crypto projects cover: dedicated IPv4 addresses, static for the full plan term, each subject to its own documented IP-based allowance — real-world scaling should still be verified under your target workload rather than assumed linear. Isolating workers also prevents one job's rate-limit response or backlog from slowing another's.