Overview

Polymarket’s REST and WebSocket APIs handle real-time trading, order placement, and market discovery. But a significant layer of on-chain data sits outside those APIs entirely: token balances, CTF (Conditional Token Framework) operations, historical open interest, and wallet-level profit and loss.

That data lives in five specialized subgraphs hosted by Goldsky, each indexing a different slice of Polymarket’s on-chain activity on Polygon. You query them using standard GraphQL POST requests – no API key required, no authentication, no rate limit headers to manage.

This guide covers all five subgraphs, the entities they expose, common query patterns, pagination strategies, and the Bitquery alternative for when you need analytics-grade queries or real-time streaming.

Prerequisites: Basic familiarity with GraphQL syntax and HTTP POST requests. Experience with the Polymarket REST API is helpful but not required.


Subgraph Reference

Polymarket splits its on-chain data across five purpose-built subgraphs. Each one indexes a specific domain of activity from the Polymarket smart contracts on Polygon.

SubgraphDataKey Entities
PositionsUser token balancesUserBalance, Condition, Market
OrdersOrder book and trade eventsOrderFilled, OrderMatched, GlobalStats
ActivitySplits, merges, redemptionsSplit, Merge, Redemption, NegRiskEvent
Open InterestPer-market and global OIMarketCondition, GlobalOI
PNLUser position P&LUserPNL, Position

All five subgraphs share the same query method: send a POST request with a JSON body containing your GraphQL query to the Goldsky-hosted endpoint. The orders subgraph endpoint, for example, looks like this:

https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/orderbook-subgraph/0.0.1/gn

Each subgraph has its own endpoint URL following the same pattern, with the subgraph name and version in the path.

Positions Subgraph

The Positions subgraph indexes user token balances across all Polymarket markets. Every time a wallet holds outcome tokens (YES or NO shares), this subgraph tracks the balance. Key entities include UserBalance (the core record linking a user address to a token balance), Condition (the on-chain condition representing a market outcome), and Market (the parent market structure).

Use this subgraph when you need to know what a specific wallet holds, aggregate positions across markets, or build portfolio-tracking tools.

Orders Subgraph

The Orders subgraph captures every order book event that settles on-chain. OrderFilled records individual fill events with maker, taker, asset IDs, and amounts. OrderMatched provides a higher-level view of matched orders. GlobalStats aggregates platform-wide trading metrics like total volume and number of trades.

This is your go-to subgraph for historical trade analysis, volume tracking, and building trade feeds.

Activity Subgraph

The Activity subgraph tracks CTF (Conditional Token Framework) operations that happen outside the order book. Split events occur when a user splits collateral into outcome tokens. Merge events record the reverse – combining outcome tokens back into collateral. Redemption events capture users redeeming winning tokens after market resolution. NegRiskEvent entities track operations specific to Polymarket’s negative-risk market type.

This subgraph is essential for understanding the full lifecycle of positions beyond simple trading.

Open Interest Subgraph

The Open Interest subgraph provides both per-market and global open interest data. MarketCondition entities track OI for individual market conditions, while GlobalOI provides platform-wide totals. Open interest reflects the total value of outstanding positions in a market and is a key indicator of market depth and participant commitment.

PNL Subgraph

The PNL subgraph calculates realized and unrealized profit and loss at the wallet level. UserPNL entities aggregate P&L across a user’s positions, while Position entities break it down by individual market. This subgraph handles the math of tracking cost basis, realized gains from trades and redemptions, and unrealized gains on open positions.


Common Queries

The following queries demonstrate the most frequently used patterns across the subgraphs. Replace placeholder values (wallet addresses, condition IDs) with real data from your application.

Get User Positions by Wallet

Query the Positions subgraph to retrieve all token balances for a specific wallet address. This returns every outcome token the wallet currently holds or has held.

{
  userBalances(where: { user: "0xYOUR_WALLET_ADDRESS" }) {
    id
    balance
    netBalance
    condition {
      id
      questionId
    }
  }
}

The balance field shows the raw token balance, while netBalance accounts for any pending operations. The condition relationship links each balance to the specific market outcome it represents, with questionId mapping to the Polymarket market.

Get Recent Trades

Query the Orders subgraph to fetch the most recent trade events. This returns fills in reverse chronological order.

{
  orderFilleds(first: 100, orderBy: timestamp, orderDirection: desc) {
    id
    maker
    taker
    makerAssetId
    takerAssetId
    makerAmountFilled
    takerAmountFilled
    timestamp
  }
}

The makerAssetId and takerAssetId fields identify which outcome tokens were exchanged. The makerAmountFilled and takerAmountFilled fields indicate the amounts on each side of the trade. Use the timestamp field for time-series analysis.

Get Market Open Interest

Query the Open Interest subgraph to retrieve open interest for a specific market condition.

{
  marketConditions(where: { conditionId: "CONDITION_ID" }) {
    id
    openInterest
    conditionId
  }
}

The conditionId corresponds to the on-chain condition identifier for a market. You can obtain condition IDs from the Gamma API or the Positions subgraph.

Querying in Python

Here is a complete Python example that queries the Orders subgraph for recent trades and prints the results.

import requests

SUBGRAPH_URL = "https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/orderbook-subgraph/0.0.1/gn"

query = """
{
  orderFilleds(first: 10, orderBy: timestamp, orderDirection: desc) {
    id
    maker
    taker
    makerAmountFilled
    timestamp
  }
}
"""

response = requests.post(SUBGRAPH_URL, json={"query": query})
data = response.json()["data"]
for trade in data["orderFilleds"]:
    print(f"Trade {trade['id']}: {trade['makerAmountFilled']} at {trade['timestamp']}")

The same pattern works for any subgraph – change the URL and the query to match the subgraph you need. No authentication headers are required. Error handling should check for response.status_code and the presence of an errors key in the JSON response.


Pagination

GraphQL subgraphs enforce result limits on queries. The default maximum per request is typically 1,000 entities. For larger datasets, you need pagination.

Skip-based pagination uses the first and skip parameters. This is simpler but becomes slow for large offsets because the subgraph must still process all skipped records:

{
  orderFilleds(first: 1000, skip: 2000, orderBy: timestamp, orderDirection: desc) {
    id
    timestamp
  }
}

Cursor-based pagination with id_gt is more efficient for iterating through large result sets. After each batch, pass the last id you received to fetch the next page:

{
  orderFilleds(first: 1000, where: { id_gt: "LAST_ID" }, orderBy: id) {
    id
    timestamp
    makerAmountFilled
  }
}

For production systems processing large amounts of historical data, cursor-based pagination is strongly recommended. It avoids the performance penalty of skip-based pagination and handles new records being added between queries more gracefully.

Tip: When paginating, always include orderBy: id to ensure deterministic ordering. If you order by timestamp, records with identical timestamps may appear inconsistently across pages.


Bitquery Alternative

Bitquery provides a third-party GraphQL API that covers Polymarket trading data from a different angle. Where the native subgraphs give you raw on-chain events, Bitquery offers analytics-level queries with built-in aggregations, filtering, and enrichment.

Bitquery’s Polymarket coverage includes:

  • Trades – Individual trade records with token metadata and USD values.
  • Settlements – Market resolution events and payouts.
  • Market lifecycle – Creation, trading, and settlement phases.
  • Wallet analytics – Aggregated activity per wallet across markets.

Bitquery also offers Kafka streaming for real-time data, which can serve as an alternative to Polymarket’s native WebSocket API for on-chain events.

Key differences from native subgraphs:

  • Requires an API access token (free tier available).
  • Provides pre-computed aggregations that would require multiple subgraph queries.
  • Covers data across multiple chains and protocols, not just Polymarket.
  • Kafka streaming adds a real-time dimension not available from subgraphs alone.

Use Bitquery when you need cross-market analytics, pre-built aggregations, or real-time streaming of on-chain events. Use the native subgraphs when you need the most granular, lowest-latency access to specific on-chain data.

Bitquery Polymarket API


When to Use Subgraph vs REST APIs

Polymarket’s data ecosystem spans REST APIs, WebSockets, and on-chain subgraphs. Each tool serves a different purpose. Choosing the right one depends on what data you need and how you intend to use it.

Use CaseBest Tool
Real-time prices and orderbookREST API or WebSocket
Order placement and tradingREST API (CLOB)
Market discovery and searchGamma API (REST)
User token balances (on-chain)Positions subgraph
Historical trade eventsOrders subgraph
CTF operations (split/merge/redeem)Activity subgraph
Open interest trackingOpen Interest subgraph
Wallet-level P&LPNL subgraph
Cross-market analyticsBitquery

General rule: If you need to take action (place orders, cancel orders), use the REST API. If you need to read on-chain state or historical on-chain events, use the subgraphs. If you need pre-computed analytics or real-time event streaming, consider Bitquery.

The subgraphs and REST APIs are complementary. A typical trading bot might use the REST API for order execution, WebSockets for real-time price feeds, the Positions subgraph for portfolio tracking, and the PNL subgraph for performance reporting.


FAQ

What data is available in the Polymarket subgraphs?

Five subgraphs cover: Positions (user token balances), Orders (order book and trade events), Activity (splits, merges, redemptions), Open Interest (per-market and global OI), and PNL (user position profit/loss). All provide on-chain data not available through REST APIs.

How do I query the Polymarket subgraph?

Send a POST request with a GraphQL query to the Goldsky-hosted endpoint. For example, the orders subgraph endpoint is https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/orderbook-subgraph/0.0.1/gn. Use standard GraphQL query syntax. No API key or authentication is required.

When should I use the subgraph instead of the REST API?

Use the subgraph for on-chain data like token balances, CTF operations (splits/merges/redemptions), historical open interest, and wallet-level P&L. Use REST APIs for real-time trading, order placement, and current market data. The two are complementary – most production systems use both.

What is the Bitquery alternative for Polymarket data?

Bitquery provides a GraphQL API for Polymarket trading data including trades, settlements, market lifecycle, and wallet analytics. It also offers Kafka streaming for real-time data. It requires an API access token. It is useful as a complementary data source or when you need analytics-level queries that would require multiple subgraph requests to assemble.


See Also


This guide is maintained by AgentBets.ai. Found an error or API change we missed? Let us know on Twitter.

Not financial advice. Built for builders.