Polymarket Data API: Trades, Positions and Wallet Activity

The Short Answer
Polymarket's current Data API v2 exposes public, wallet-attributed data through GET /v2/trades, GET /v2/positions and GET /v2/activity. New integrations should use v2, follow pagination.next_cursor and expect snake-case fields inside a shared { data, pagination } envelope. Predictefy adds a normalized public trade tape, hosted Polymarket positions and wallet intelligence behind the same authenticated SDK used for other venues. It does not pretend that a trade feed is the same as Polymarket's broader split, merge and redeem activity feed.
Key Takeaways
- Use Polymarket Data API v2 for new builds. The original routes keep working, so an existing integration can migrate one call site at a time.
/v2/tradescan serve a global, market, event or user-filtered feed./v2/positionsrequires at least auserorconditionanchor and covers open, redeemable and closed positions./v2/activityis wallet-anchored and includes more than trades, such as splits, merges and redemptions.- Predictefy separates outcome trades, wallet-attributed trades and public account positions into explicit capability-qualified surfaces.
- A public wallet feed is not proof of identity, intent or future performance.
What is the Polymarket Data API?
The Data API is Polymarket's analytics and account-activity service at https://data-api.polymarket.com. It is separate from the Gamma API used for market discovery and the CLOB API used for live books and trading.
| Service | Primary job | Example host |
|---|---|---|
| Gamma API | Events, markets, metadata and token discovery | gamma-api.polymarket.com |
| CLOB API | Prices, order books, orders and private trading state | clob.polymarket.com |
| Data API | Trades, positions, wallet activity and analytics | data-api.polymarket.com |
Polymarket's current Data API migration guide says new integrations should start on v2. Version 2 replaces several unrelated response shapes with a shared envelope, changes response fields from camelCase to snake_case and replaces offset pagination with opaque cursors.
What changed in Data API v2?
| Concern | Legacy v1 | Current v2 |
|---|---|---|
| Response | Bare arrays or objects | { data, pagination } |
| Field casing | proxyWallet, conditionId | proxy_wallet, condition_id |
| Pagination | limit and offset | Opaque cursor |
| Position lifecycle | Separate open, closed and market routes | One route with status |
| Market selector | market | condition |
A cursor carries the seek position and page size. Some routes also bind sort settings into it. Follow the returned token instead of constructing one or reverting to offset arithmetic.
How do you fetch Polymarket trades?
The current endpoint is GET https://data-api.polymarket.com/v2/trades. Without a user it can serve a broader feed. Add user for one wallet, condition for up to 20 condition ids, or event_id for events.
curl -s \
"https://data-api.polymarket.com/v2/trades?user=0xYOUR_ACCOUNT_WALLET&limit=100"
Trade rows include fields such as condition_id, token_id, proxy_wallet, side, price, size, timestamp and transaction hash. The route defaults taker_only to true, which serves each fill once on its taker side. Set it to false only when maker rows are part of the analysis.
{
"data": [
{
"condition_id": "0x...",
"token_id": "123...",
"proxy_wallet": "0x...",
"side": "BUY",
"price": 0.61,
"size": 40,
"timestamp": 1789693200,
"transaction_hash": "0x..."
}
],
"pagination": {
"has_more": true,
"next_cursor": "opaque-token"
}
}
The official v2 trades reference also documents an important retention distinction: user-shaped requests accept explicit time bounds, while condition and event shapes use their documented fixed window and the bare feed uses a rolling window.
How do you fetch current and closed positions?
The unified route is GET /v2/positions. It requires at least one anchor:
userfor positions owned by one account wallet.conditionfor holders of one market.- Both values to narrow one wallet to one or more conditions.
# Open positions for one wallet
curl -s \
"https://data-api.polymarket.com/v2/positions?user=0xYOUR_ACCOUNT_WALLET&status=OPEN&limit=100"
# Redeemable positions
curl -s \
"https://data-api.polymarket.com/v2/positions?user=0xYOUR_ACCOUNT_WALLET&status=REDEEMABLE&limit=100"
# Closed positions
curl -s \
"https://data-api.polymarket.com/v2/positions?user=0xYOUR_ACCOUNT_WALLET&status=CLOSED&limit=100"
OPEN is the default and includes settled winners that still hold redeemable tokens. REDEEMABLE narrows that subset. Position rows can include current size, average price, current value, realized and unrealized PnL, redeemable and mergeable flags, market metadata and the token id. See Polymarket's current positions contract for the full schema.
Which wallet address should you query?
Use the address that owns the Polymarket account's positions. It may not be the external signer address. Current Polymarket accounts use a Deposit Wallet, while older accounts may use a Proxy Wallet or Safe Wallet. Copying an EOA signer into a Data API query can return an empty list even when the associated account wallet holds positions. On-chain indexers are the other route to this data, compared in Predictefy vs Bitquery.
This is a data-identity issue, not an API failure. Keep these concepts separate:
| Identifier | What it identifies |
|---|---|
| Signer address | The key that authorizes signatures |
| Account or proxy wallet | The wallet that holds positions and funds |
| Condition id | One binary market |
| Token id | One tradable outcome within that market |
How do you fetch complete wallet activity?
GET /v2/activity is broader than the trades route. It is user-anchored and can return trades, splits, merges, redemptions and other documented activity types.
curl -s \
"https://data-api.polymarket.com/v2/activity?user=0xYOUR_ACCOUNT_WALLET&limit=100"
Filter with type, condition, event_id, side and an epoch-second time window. The default order is newest first. The activity reference documents keyset ordering and notes that a returned cursor binds the direction under which it was created.
Use activity when the question is "what changed in this wallet?" Use trades when the question is "which fills happened?" A split, merge or redeem changes token inventory but is not a trade, so a trade-only ledger cannot fully reconcile a wallet.
How do you paginate safely?
async function collectPages(firstUrl) {
const rows = [];
let url = new URL(firstUrl);
while (url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Polymarket Data API returned ' + response.status);
}
const page = await response.json();
rows.push(...page.data);
const cursor = page.pagination?.next_cursor;
if (!cursor) break;
const next = new URL(firstUrl);
next.searchParams.set('cursor', cursor);
url = next;
}
return rows;
}
Keep stable filters such as the user or condition in the base URL unless the endpoint explicitly says the cursor carries them. Never decode, edit or manufacture an opaque cursor. Handle an empty data array as a successful zero-state, not automatically as an outage.
How does Predictefy expose Polymarket trades?
Predictefy has two deliberately different trade surfaces:
| Predictefy call | Question answered |
|---|---|
polymarket.fetchTrades({ outcomeId }) | What recently traded for this outcome? |
polymarket.fetchWalletTrades(wallet, options) | Which wallet-attributed trades are associated with this address? |
import Predictefy from '@predictefy/sdk';
const client = new Predictefy({
apiKey: process.env.PREDICTEFY_API_KEY,
});
const outcomeTape = await client.polymarket.fetchTrades({
outcomeId: process.env.POLYMARKET_OUTCOME_ID,
});
const walletTape = await client.polymarket.fetchWalletTrades(
process.env.POLYMARKET_ACCOUNT_WALLET,
{ limit: 50 },
);
console.log({
outcomeTrades: outcomeTape.length,
walletTrades: walletTape.length,
nextCursor: walletTape.nextCursor,
asOf: walletTape.meta?.asOf,
provenance: walletTape.meta?.provenance,
});
The normalized wallet rows expose venue, market and outcome ids, trade id, timestamp, wallet, side, price, amount and USD size where the source can prove them. Nullable values remain null rather than being guessed. Predictefy's Trader Intelligence reference states that unsupported wallet-history lanes return TRADERS_UNSUPPORTED instead of a fabricated empty history.
How do you read Polymarket positions through Predictefy?
Polymarket public positions are available through Predictefy's hosted account surface. Check capabilities first, then request the wallet's positions:
const capabilities = await client.account.fetchCapabilities({
venue: 'polymarket',
});
if (!capabilities.positions.served) {
throw new Error('Polymarket positions are not served');
}
const positions = await client.account.fetchPositions({
venue: 'polymarket',
accountId: process.env.POLYMARKET_ACCOUNT_WALLET,
limit: 100,
});
for (const position of positions) {
console.log({
marketId: position.marketId,
outcomeId: position.outcomeId,
side: position.side,
size: position.size,
markPrice: position.markPrice,
unrealizedPnl: position.unrealizedPnl,
asOf: position.asOf,
});
}
console.log({
nextCursor: positions.nextCursor,
asOf: positions.meta?.asOf,
provenance: positions.meta?.provenance,
});
The REST equivalent is:
curl -s \
"https://data.predictefy.com/v1/accounts/polymarket/ACCOUNT_WALLET/positions?limit=100" \
-H "Authorization: Bearer $PREDICTEFY_API_KEY"
The normalized row distinguishes venue marketId from canonicalMarketId, preserves the outcome and includes explicit provenance. Predictefy's portfolio guide warns that an unsupported resource is not the same as an empty account. Render unavailable as unavailable, not as zero positions.
When should you use Predictefy alongside the Data API?
Use Predictefy when the application needs one market, trade, wallet-intelligence or position model that holds across several venues, so the same code reaches Polymarket and the other fifteen without a branch per venue. Reach for Polymarket's Data API directly when you want the native Polymarket detail, including the full activity taxonomy of token splits, merges and redemptions.
Most production systems run both, and the split falls out cleanly by task:
| Use case | Best starting point |
|---|---|
| Render positions across several venues | Predictefy account surface |
| Read one normalized outcome tape | Predictefy fetchTrades |
| Compare wallet-attributed trades across supported venues | Predictefy Trader Intelligence |
| Reconcile every Polymarket wallet event | Polymarket /v2/activity |
| Analyze native Polymarket position fields | Polymarket /v2/positions |
What should you not infer from public wallet data?
- A wallet address does not prove a person's identity.
- A visible position does not disclose an off-platform hedge.
- A trade timestamp does not prove the trader's information source or intent.
- Historical profit does not make the next trade a recommendation.
- An empty response can mean no rows, a wrong account address or a filter mismatch. Check the contract before drawing a conclusion.
Preserve the raw identifiers, query window, cursor chain and retrieval time when using these feeds in research. That makes the result reproducible and prevents a later snapshot from being presented as the data originally observed.
Frequently Asked Questions
Does the Polymarket Data API require an API key?
The documented v2 examples for trades, positions and activity are public reads and send no authentication headers. Authentication is a separate concern for private CLOB state, order management, gasless wallet operations and trading. That split is worth knowing early, because it means you can build and test the entire read half of an integration before touching credentials.
Should a new integration use Data API v1 or v2?
Use v2 for new builds. It provides a shared response envelope, snake-case fields and cursor-based pagination. The original routes keep working, so an existing integration can migrate one call site at a time rather than rewriting everything at once. Polymarket documents that gradual path rather than forcing a cutover.
What is the difference between trades and activity?
The trades route returns fills. The activity route can also include splits, merges, redemptions and other wallet events. Use activity for inventory reconciliation and trades for execution analysis. Reading only trades and assuming it accounts for a wallet’s full position history is a common source of reconciliation errors.
Why does a wallet with positions return an empty result?
The query may be using the external signer instead of the account, deposit, proxy or Safe wallet that actually owns the positions. Confirm the account wallet address and filters before treating the result as zero holdings. This is the most common reason a wallet query comes back empty while the user can plainly see positions.
Can Predictefy read Polymarket positions and wallet trades?
Yes. The hosted account surface serves public Polymarket positions, and Trader Intelligence serves capability-qualified wallet-attributed trades. Read the capability response first, because a venue that does not publish something answers honestly rather than returning an empty list, and those two responses mean very different things downstream.