> ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further. # Orderbook > Reading the orderbook, prices, spreads, and midpoints The orderbook is a public endpoint — no authentication required. You can read prices and liquidity using the SDK or REST API directly. ```typescript TypeScript theme={null} import { ClobClient } from "@polymarket/clob-client-v2"; const client = new ClobClient({ host: "https://clob.polymarket.com", chain: 137 }); ``` ```python Python theme={null} from py_clob_client_v2 import ClobClient client = ClobClient("https://clob.polymarket.com", chain_id=137) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::{Client, Config}; let client = Client::new("https://clob.polymarket.com", Config::default())?; ``` ```bash REST theme={null} # Base URL for all orderbook endpoints https://clob.polymarket.com ``` *** ## Get the Orderbook Fetch the full orderbook for a token, including all resting bid and ask levels: ```typescript TypeScript theme={null} const book = await client.getOrderBook("TOKEN_ID"); console.log("Best bid:", book.bids[0]); console.log("Best ask:", book.asks[0]); console.log("Tick size:", book.tick_size); ``` ```python Python theme={null} book = client.get_order_book("TOKEN_ID") print("Best bid:", book["bids"][0]) print("Best ask:", book["asks"][0]) print("Tick size:", book["tick_size"]) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::request::OrderBookSummaryRequest; let token_id = "TOKEN_ID".parse()?; let request = OrderBookSummaryRequest::builder().token_id(token_id).build(); let book = client.order_book(&request).await?; println!("Best bid: {:?}", book.bids[0]); println!("Best ask: {:?}", book.asks[0]); println!("Tick size: {:?}", book.tick_size); ``` ```bash REST theme={null} curl "https://clob.polymarket.com/book?token_id=TOKEN_ID" ``` ### Response ```json theme={null} { "market": "0xbd31dc8a...", "asset_id": "52114319501245...", "timestamp": "2023-10-21T08:00:00Z", "bids": [ { "price": "0.48", "size": "1000" }, { "price": "0.47", "size": "2500" } ], "asks": [ { "price": "0.52", "size": "800" }, { "price": "0.53", "size": "1500" } ], "min_order_size": "5", "tick_size": "0.01", "neg_risk": false, "hash": "0xabc123..." } ``` | Field | Description | | ---------------- | --------------------------------------------------- | | `market` | Condition ID of the market | | `asset_id` | Token ID | | `bids` | Buy orders sorted by price (highest first) | | `asks` | Sell orders sorted by price (lowest first) | | `tick_size` | Minimum price increment for this market | | `min_order_size` | Minimum order size for this market | | `neg_risk` | Whether this is a multi-outcome (neg risk) market | | `hash` | Hash of the orderbook state — use to detect changes | *** ## Prices Get the best available price for buying or selling a token: ```typescript TypeScript theme={null} const buyPrice = await client.getPrice("TOKEN_ID", "BUY"); console.log("Best ask:", buyPrice.price); // Price you'd pay to buy const sellPrice = await client.getPrice("TOKEN_ID", "SELL"); console.log("Best bid:", sellPrice.price); // Price you'd receive to sell ``` ```python Python theme={null} buy_price = client.get_price("TOKEN_ID", "BUY") print("Best ask:", buy_price["price"]) sell_price = client.get_price("TOKEN_ID", "SELL") print("Best bid:", sell_price["price"]) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::{Side, request::PriceRequest}; let token_id = "TOKEN_ID".parse()?; let buy_req = PriceRequest::builder().token_id(token_id).side(Side::Buy).build(); let buy_price = client.price(&buy_req).await?; println!("Best ask: {}", buy_price.price); let sell_req = PriceRequest::builder().token_id(token_id).side(Side::Sell).build(); let sell_price = client.price(&sell_req).await?; println!("Best bid: {}", sell_price.price); ``` ```bash REST theme={null} # Best price for buying (lowest ask) curl "https://clob.polymarket.com/price?token_id=TOKEN_ID&side=BUY" # Best price for selling (highest bid) curl "https://clob.polymarket.com/price?token_id=TOKEN_ID&side=SELL" ``` *** ## Midpoints The midpoint is the average of the best bid and best ask. This is the price displayed on Polymarket as the market's implied probability. ```typescript TypeScript theme={null} const midpoint = await client.getMidpoint("TOKEN_ID"); console.log("Midpoint:", midpoint.mid); // e.g., "0.50" ``` ```python Python theme={null} midpoint = client.get_midpoint("TOKEN_ID") print("Midpoint:", midpoint["mid"]) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::request::MidpointRequest; let token_id = "TOKEN_ID".parse()?; let request = MidpointRequest::builder().token_id(token_id).build(); let midpoint = client.midpoint(&request).await?; println!("Midpoint: {}", midpoint.mid); ``` ```bash REST theme={null} curl "https://clob.polymarket.com/midpoint?token_id=TOKEN_ID" ``` If the bid-ask spread is wider than \$0.10, Polymarket displays the last traded price instead of the midpoint. *** ## Spreads The spread is the difference between the best ask and the best bid. Tighter spreads indicate more liquid markets. ```typescript TypeScript theme={null} const spread = await client.getSpread("TOKEN_ID"); console.log("Spread:", spread.spread); // e.g., "0.04" ``` ```python Python theme={null} spread = client.get_spread("TOKEN_ID") print("Spread:", spread["spread"]) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::request::SpreadRequest; let token_id = "TOKEN_ID".parse()?; let request = SpreadRequest::builder().token_id(token_id).build(); let spread = client.spread(&request).await?; println!("Spread: {}", spread.spread); ``` ```bash REST theme={null} # Spreads use POST for batch requests curl -X POST "https://clob.polymarket.com/spreads" \ -H "Content-Type: application/json" \ -d '[{"token_id": "TOKEN_ID"}]' ``` *** ## Price History Fetch historical price data for a token over various time intervals: ```typescript TypeScript theme={null} import { PriceHistoryInterval } from "@polymarket/clob-client-v2"; const history = await client.getPricesHistory({ market: "TOKEN_ID", // Note: this param is named "market" but takes a token ID interval: PriceHistoryInterval.ONE_DAY, fidelity: 60, // Data points every 60 minutes }); // Each entry: { t: timestamp, p: price } history.forEach((point) => { console.log(`${new Date(point.t * 1000).toISOString()}: ${point.p}`); }); ``` ```python Python theme={null} history = client.get_prices_history( market="TOKEN_ID", # Note: this param is named "market" but takes a token ID interval="1d", fidelity=60, # Data points every 60 minutes ) for point in history: print(f"{point['t']}: {point['p']}") ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::{Interval, TimeRange, request::PriceHistoryRequest}; let token_id = "TOKEN_ID".parse()?; let request = PriceHistoryRequest::builder() .market(token_id) // Note: this param is named "market" but takes a token ID .time_range(TimeRange::Interval { interval: Interval::OneDay }) .fidelity(60) // Data points every 60 minutes .build(); let history = client.price_history(&request).await?; for point in &history.history { println!("{}: {}", point.t, point.p); } ``` ```bash REST theme={null} # By interval (relative to now) curl "https://clob.polymarket.com/prices-history?market=TOKEN_ID&interval=1d&fidelity=60" # By timestamp range curl "https://clob.polymarket.com/prices-history?market=TOKEN_ID&startTs=1697875200&endTs=1697961600" ``` | Interval | Description | | -------- | ------------------ | | `1h` | Last hour | | `6h` | Last 6 hours | | `1d` | Last day | | `1w` | Last week | | `1m` | Last month | | `max` | All available data | `interval` is relative to the current time. Use `startTs` / `endTs` for absolute time ranges. They are mutually exclusive — don't combine them. *** ## Estimate Fill Price Calculate the effective price you'd pay for a market order of a given size, accounting for orderbook depth: ```typescript TypeScript theme={null} import { Side, OrderType } from "@polymarket/clob-client-v2"; // What price would I pay to buy $500 worth? const price = await client.calculateMarketPrice( "TOKEN_ID", Side.BUY, 500, // dollar amount OrderType.FOK, ); console.log("Estimated fill price:", price); ``` ```python Python theme={null} from py_clob_client_v2 import OrderType price = client.calculate_market_price( token_id="TOKEN_ID", side="BUY", amount=500, order_type=OrderType.FOK, ) print("Estimated fill price:", price) ``` ```rust Rust theme={null} // The Rust SDK handles market price calculation automatically // inside the market_order() builder when no price is specified. // It walks the orderbook to determine the fill price for you. let order = client .market_order() .token_id("TOKEN_ID".parse()?) .amount(Amount::usdc(dec!(500))?) .side(Side::Buy) .order_type(OrderType::FOK) .build() .await?; // Price auto-calculated from orderbook depth ``` This walks the orderbook to estimate slippage. Useful for sizing market orders before submitting them. *** ## Batch Requests All orderbook queries have batch variants for fetching data across multiple tokens in a single request (up to 500 tokens): | Single | Batch | REST | | --------------------- | ----------------------- | ----------------- | | `getOrderBook()` | `getOrderBooks()` | `POST /books` | | `getPrice()` | `getPrices()` | `POST /prices` | | `getMidpoint()` | `getMidpoints()` | `POST /midpoints` | | `getSpread()` | `getSpreads()` | `POST /spreads` | | `getLastTradePrice()` | `getLastTradesPrices()` | — | `BookParams` for batch orderbook requests accepts a `token_id` and an optional `side` parameter to filter by bid or ask side. ```typescript TypeScript theme={null} import { Side } from "@polymarket/clob-client-v2"; // Fetch prices for multiple tokens const prices = await client.getPrices([ { token_id: "TOKEN_A", side: Side.BUY }, { token_id: "TOKEN_B", side: Side.BUY }, ]); // Returns: { "TOKEN_A": { "BUY": "0.52" }, "TOKEN_B": { "BUY": "0.74" } } ``` ```python Python theme={null} prices = client.get_prices([ {"token_id": "TOKEN_A", "side": "BUY"}, {"token_id": "TOKEN_B", "side": "BUY"}, ]) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::{Side, request::PriceRequest}; let token_a = "TOKEN_A".parse()?; let token_b = "TOKEN_B".parse()?; let requests = vec![ PriceRequest::builder().token_id(token_a).side(Side::Buy).build(), PriceRequest::builder().token_id(token_b).side(Side::Buy).build(), ]; let prices = client.prices(&requests).await?; ``` ```bash REST theme={null} curl -X POST "https://clob.polymarket.com/prices" \ -H "Content-Type: application/json" \ -d '[ {"token_id": "TOKEN_A", "side": "BUY"}, {"token_id": "TOKEN_B", "side": "BUY"} ]' ``` *** ## Last Trade Price Get the price and side of the most recent trade for a token: ```typescript TypeScript theme={null} const lastTrade = await client.getLastTradePrice("TOKEN_ID"); console.log(lastTrade.price, lastTrade.side); // e.g., "0.52", "BUY" ``` ```python Python theme={null} last_trade = client.get_last_trade_price("TOKEN_ID") print(last_trade["price"], last_trade["side"]) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::request::LastTradePriceRequest; let token_id = "TOKEN_ID".parse()?; let request = LastTradePriceRequest::builder().token_id(token_id).build(); let last_trade = client.last_trade_price(&request).await?; println!("{} {:?}", last_trade.price, last_trade.side); ``` *** ## Real-Time Updates For live orderbook data, use the WebSocket API instead of polling. The `market` channel streams orderbook changes, price updates, and trade events in real time. ### Connecting ```typescript theme={null} const ws = new WebSocket( "wss://ws-subscriptions-clob.polymarket.com/ws/market", ); ws.onopen = () => { ws.send( JSON.stringify({ type: "market", assets_ids: ["TOKEN_ID"], custom_feature_enabled: true, // enables best_bid_ask, new_market, market_resolved events }), ); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); switch (data.event_type) { case "book": // full orderbook snapshot case "price_change": // individual price level update case "last_trade_price": // new trade executed case "tick_size_change": // market tick size changed case "best_bid_ask": // top-of-book update (requires custom_feature_enabled) case "new_market": // new market created (requires custom_feature_enabled) case "market_resolved": // market resolved (requires custom_feature_enabled) } }; ``` ### Dynamic Subscribe and Unsubscribe After connecting, you can change your subscriptions without reconnecting: ```typescript theme={null} // Subscribe to additional tokens ws.send( JSON.stringify({ assets_ids: ["NEW_TOKEN_ID"], operation: "subscribe", }), ); // Unsubscribe from tokens ws.send( JSON.stringify({ assets_ids: ["OLD_TOKEN_ID"], operation: "unsubscribe", }), ); ``` ### Event Types | Event | Trigger | Key Fields | | ------------------ | -------------------------------------------- | ---------------------------------------------------------------------- | | `book` | On subscribe + when a trade affects the book | `bids[]`, `asks[]`, `hash`, `timestamp` | | `price_change` | New order placed or order cancelled | `price_changes[]` with `price`, `size`, `side`, `best_bid`, `best_ask` | | `last_trade_price` | Trade executed | `price`, `side`, `size`, `fee_rate_bps` | | `tick_size_change` | Price hits >0.96 or \< 0.04 | `old_tick_size`, `new_tick_size` | | `best_bid_ask` | Top-of-book changes | `best_bid`, `best_ask`, `spread` | | `new_market` | Market created | `question`, `assets_ids`, `outcomes` | | `market_resolved` | Market resolved | `winning_asset_id`, `winning_outcome` | `best_bid_ask`, `new_market`, and `market_resolved` require `custom_feature_enabled: true` in your subscription message. The `tick_size_change` event is critical for trading bots. If the tick size changes and you continue using the old tick size, your orders will be rejected. *** ## Next Steps Create and submit orders using the orderbook data Find token IDs for markets you want to trade