> ## 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. # Create Order > Build, sign, and submit orders All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book. The SDK handles EIP-712 signing and submission for you. If you prefer the REST API directly, see [Authentication](/api-reference/authentication) for constructing the required headers and the [API Reference](/api-reference/introduction) for full endpoint documentation including the raw order object fields and request/response schemas. *** ## Order Types | Type | Behavior | Use Case | | ------- | -------------------------------------------------------------------- | ------------------------------- | | **GTC** | Good-Til-Cancelled — rests on the book until filled or cancelled | Default for limit orders | | **GTD** | Good-Til-Date — active until a specified expiration time | Auto-expire before known events | | **FOK** | Fill-Or-Kill — must fill immediately and entirely, or cancel | All-or-nothing market orders | | **FAK** | Fill-And-Kill — fills what's available immediately, cancels the rest | Partial-fill market orders | * **GTC** and **GTD** are limit order types — they rest on the book at your specified price. * **FOK** and **FAK** are market order types — they execute against resting liquidity immediately. * **BUY**: specify the dollar amount you want to spend * **SELL**: specify the number of shares you want to sell *** ## Limit Orders The simplest way to place a limit order — create, sign, and submit in one call: ```typescript TypeScript theme={null} import { ClobClient, Side, OrderType } from "@polymarket/clob-client-v2"; const response = await client.createAndPostOrder( { tokenID: "TOKEN_ID", price: 0.5, size: 10, side: Side.BUY, }, { tickSize: "0.01", negRisk: false, }, OrderType.GTC, ); console.log("Order ID:", response.orderID); console.log("Status:", response.status); ``` ```python Python theme={null} from py_clob_client_v2 import OrderArgs, OrderType, PartialCreateOrderOptions from py_clob_client_v2.order_builder.constants import BUY response = client.create_and_post_order( OrderArgs( token_id="TOKEN_ID", price=0.50, size=10, side=BUY, ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False), order_type=OrderType.GTC ) print("Order ID:", response["orderID"]) print("Status:", response["status"]) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::Side; use polymarket_client_sdk_v2::types::dec; let token_id = "TOKEN_ID".parse()?; let order = client .limit_order() .token_id(token_id) .price(dec!(0.50)) .size(dec!(10)) .side(Side::Buy) .build() .await?; let signed = client.sign(&signer, order).await?; let response = client.post_order(signed).await?; println!("Order ID: {}", response.order_id); println!("Status: {:?}", response.status); ``` ### Two-Step Sign Then Submit For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic: ```typescript TypeScript theme={null} // Step 1: Create and sign locally const signedOrder = await client.createOrder( { tokenID: "TOKEN_ID", price: 0.5, size: 10, side: Side.BUY, }, { tickSize: "0.01", negRisk: false }, ); // Step 2: Submit to the CLOB const response = await client.postOrder(signedOrder, OrderType.GTC); ``` ```python Python theme={null} # Step 1: Create and sign locally signed_order = client.create_order( OrderArgs( token_id="TOKEN_ID", price=0.50, size=10, side=BUY, ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False) ) # Step 2: Submit to the CLOB response = client.post_order(signed_order, OrderType.GTC) ``` ```rust Rust theme={null} // Step 1: Create order (auto-fetches tick size, neg risk, fee rate) let order = client .limit_order() .token_id("TOKEN_ID".parse()?) .price(dec!(0.50)) .size(dec!(10)) .side(Side::Buy) .build() .await?; // Step 2: Sign and submit separately let signed = client.sign(&signer, order).await?; let response = client.post_order(signed).await?; ``` *** ## GTD Orders GTD orders auto-expire at a specified time. Useful for quoting around known events. ```typescript TypeScript theme={null} // Expire in 1 hour (+ 60s security threshold buffer) const expiration = Math.floor(Date.now() / 1000) + 60 + 3600; const response = await client.createAndPostOrder( { tokenID: "TOKEN_ID", price: 0.5, size: 10, side: Side.BUY, expiration, }, { tickSize: "0.01", negRisk: false }, OrderType.GTD, ); ``` ```python Python theme={null} import time # Expire in 1 hour (+ 60s security threshold buffer) expiration = int(time.time()) + 60 + 3600 response = client.create_and_post_order( OrderArgs( token_id="TOKEN_ID", price=0.50, size=10, side=BUY, expiration=expiration, ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False), order_type=OrderType.GTD ) ``` ```rust Rust theme={null} use chrono::{TimeDelta, Utc}; use polymarket_client_sdk_v2::clob::types::OrderType; let order = client .limit_order() .token_id("TOKEN_ID".parse()?) .price(dec!(0.50)) .size(dec!(10)) .side(Side::Buy) .order_type(OrderType::GTD) .expiration(Utc::now() + TimeDelta::minutes(1) + TimeDelta::hours(1)) .build() .await?; let signed = client.sign(&signer, order).await?; let response = client.post_order(signed).await?; ``` GTD orders expire one minute before their stated expiration as a security threshold. To set an effective lifetime of N seconds, use `now + 60 + N`. In addition, the expiration must be at least three minutes in the future — orders expiring sooner are rejected — so the minimum effective lifetime is about two minutes. *** ## Market Orders Market orders execute immediately against resting liquidity using FOK or FAK types: ```typescript TypeScript theme={null} import { Side, OrderType } from "@polymarket/clob-client-v2"; // FOK BUY: spend exactly $100 or cancel entirely const buyOrder = await client.createMarketOrder( { tokenID: "TOKEN_ID", side: Side.BUY, amount: 100, // dollar amount price: 0.5, // worst-price limit (slippage protection) }, { tickSize: "0.01", negRisk: false }, ); await client.postOrder(buyOrder, OrderType.FOK); // FOK SELL: sell exactly 200 shares or cancel entirely const sellOrder = await client.createMarketOrder( { tokenID: "TOKEN_ID", side: Side.SELL, amount: 200, // number of shares price: 0.45, // worst-price limit (slippage protection) }, { tickSize: "0.01", negRisk: false }, ); await client.postOrder(sellOrder, OrderType.FOK); ``` ```python Python theme={null} from py_clob_client_v2.order_builder.constants import BUY, SELL from py_clob_client_v2 import MarketOrderArgs, OrderType, PartialCreateOrderOptions # FOK BUY: spend exactly $100 or cancel entirely buy_order = client.create_market_order( order_args=MarketOrderArgs( token_id="TOKEN_ID", side=BUY, amount=100, # dollar amount price=0.50, # worst-price limit (slippage protection) ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False), ) client.post_order(buy_order, OrderType.FOK) # FOK SELL: sell exactly 200 shares or cancel entirely sell_order = client.create_market_order( order_args=MarketOrderArgs( token_id="TOKEN_ID", side=SELL, amount=200, # number of shares price=0.45, # worst-price limit (slippage protection) ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False), ) client.post_order(sell_order, OrderType.FOK) ``` ```rust Rust theme={null} use polymarket_client_sdk_v2::clob::types::{Amount, OrderType, Side}; let token_id = "TOKEN_ID".parse()?; // FOK BUY: spend exactly $100 or cancel entirely let buy = client .market_order() .token_id(token_id) .amount(Amount::usdc(dec!(100))?) .price(dec!(0.50)) // worst-price limit (slippage protection) .side(Side::Buy) .order_type(OrderType::FOK) .build() .await?; let signed = client.sign(&signer, buy).await?; client.post_order(signed).await?; // FOK SELL: sell exactly 200 shares or cancel entirely let sell = client .market_order() .token_id(token_id) .amount(Amount::shares(dec!(200))?) .price(dec!(0.45)) // worst-price limit (slippage protection) .side(Side::Sell) .order_type(OrderType::FOK) .build() .await?; let signed = client.sign(&signer, sell).await?; client.post_order(signed).await?; ``` * **FOK** — fill entirely or cancel the whole order * **FAK** — fill what's available, cancel the rest The `price` field on market orders acts as a **worst-price limit** (slippage protection), not a target execution price. ### One-Step Market Order For convenience, `createAndPostMarketOrder` handles creation, signing, and submission in one call: ```typescript TypeScript theme={null} const response = await client.createAndPostMarketOrder( { tokenID: "TOKEN_ID", side: Side.BUY, amount: 100, price: 0.5, }, { tickSize: "0.01", negRisk: false }, OrderType.FOK, ); ``` ```python Python theme={null} from py_clob_client_v2 import MarketOrderArgs, OrderType, PartialCreateOrderOptions from py_clob_client_v2.order_builder.constants import BUY response = client.create_and_post_market_order( order_args=MarketOrderArgs( token_id="TOKEN_ID", side=BUY, amount=100, price=0.50, ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False), order_type=OrderType.FOK, ) ``` ```rust Rust theme={null} let order = client .market_order() .token_id("TOKEN_ID".parse()?) .amount(Amount::usdc(dec!(100))?) .price(dec!(0.50)) .side(Side::Buy) .order_type(OrderType::FOK) .build() .await?; let signed = client.sign(&signer, order).await?; let response = client.post_order(signed).await?; ``` *** ## Post-Only Orders Post-only orders guarantee you're always the maker. If the order would match immediately (cross the spread), it's rejected instead of executed. ```typescript TypeScript theme={null} const response = await client.postOrder(signedOrder, OrderType.GTC, true); ``` ```python Python theme={null} response = client.post_order(signed_order, OrderType.GTC, post_only=True) ``` ```rust Rust theme={null} let order = client .limit_order() .token_id("TOKEN_ID".parse()?) .price(dec!(0.50)) .size(dec!(10)) .side(Side::Buy) .post_only(true) .build() .await?; let signed = client.sign(&signer, order).await?; let response = client.post_order(signed).await?; ``` * Only works with **GTC** and **GTD** order types * Rejected if combined with FOK or FAK *** ## Batch Orders Place up to **15 orders** in a single request: ```typescript TypeScript theme={null} import { OrderType, Side, PostOrdersArgs } from "@polymarket/clob-client-v2"; const orders: PostOrdersArgs[] = [ { order: await client.createOrder( { tokenID: "TOKEN_ID", price: 0.48, side: Side.BUY, size: 500, }, { tickSize: "0.01", negRisk: false }, ), orderType: OrderType.GTC, }, { order: await client.createOrder( { tokenID: "TOKEN_ID", price: 0.52, side: Side.SELL, size: 500, }, { tickSize: "0.01", negRisk: false }, ), orderType: OrderType.GTC, }, ]; const response = await client.postOrders(orders); ``` ```python Python theme={null} from py_clob_client_v2 import OrderArgs, OrderType, PostOrdersV2Args, PartialCreateOrderOptions from py_clob_client_v2.order_builder.constants import BUY, SELL response = client.post_orders([ PostOrdersV2Args( order=client.create_order(OrderArgs( price=0.48, size=500, side=BUY, token_id="TOKEN_ID", ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False)), orderType=OrderType.GTC, ), PostOrdersV2Args( order=client.create_order(OrderArgs( price=0.52, size=500, side=SELL, token_id="TOKEN_ID", ), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False)), orderType=OrderType.GTC, ), ]) ``` ```rust Rust theme={null} let token_id = "TOKEN_ID".parse()?; let bid = client .limit_order() .token_id(token_id) .price(dec!(0.48)) .size(dec!(500)) .side(Side::Buy) .build() .await?; let ask = client .limit_order() .token_id(token_id) .price(dec!(0.52)) .size(dec!(500)) .side(Side::Sell) .build() .await?; let signed_bid = client.sign(&signer, bid).await?; let signed_ask = client.sign(&signer, ask).await?; let response = client.post_orders(vec![signed_bid, signed_ask]).await?; ``` *** ## Order Options Every order requires two market-specific options: `tickSize` and `negRisk`. For details on signature types (`0` = EOA, `1` = POLY\_PROXY, `2` = GNOSIS\_SAFE, `3` = POLY\_1271 deposit wallet), see [Authentication](/api-reference/authentication#signature-types-and-funder). ### Tick Sizes Your order price must conform to the market's tick size, or the order is rejected. | Tick Size | Precision | Example Prices | | --------- | ----------- | ---------------------- | | `0.1` | 1 decimal | 0.1, 0.2, 0.5 | | `0.01` | 2 decimals | 0.01, 0.50, 0.99 | | `0.001` | 3 decimals | 0.001, 0.500, 0.999 | | `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 | | `0.0025` | 0.25¢ steps | 0.0025, 0.5000, 0.9975 | The `0.0025` (0.25¢) tick size applies only to World Cup *to advance*, *moneyline*, *spreads*, and *totals* markets. Always fetch the market's tick size before quoting rather than assuming a value. ```typescript TypeScript theme={null} const tickSize = await client.getTickSize("TOKEN_ID"); ``` ```python Python theme={null} tick_size = client.get_tick_size("TOKEN_ID") ``` ```rust Rust theme={null} let token_id = "TOKEN_ID".parse()?; let tick_size = client.tick_size(token_id).await?; ``` ### Negative Risk Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets. ```typescript TypeScript theme={null} const isNegRisk = await client.getNegRisk("TOKEN_ID"); ``` ```python Python theme={null} is_neg_risk = client.get_neg_risk("TOKEN_ID") ``` ```rust Rust theme={null} let token_id = "TOKEN_ID".parse()?; let is_neg_risk = client.neg_risk(token_id).await?; ``` Both values are also available on the market object: `minimum_tick_size` and `neg_risk`. In Rust, the order builder auto-fetches both — you don't need to look them up manually. *** ## Prerequisites Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens: * **BUY orders**: pUSD allowance >= spending amount * **SELL orders**: conditional token allowance >= selling amount Order size is limited by your available balance minus amounts reserved by existing open orders: $$ \text{maxOrderSize} = \text{balance} - \sum(\text{openOrderSize} - \text{filledAmount}) $$ Orders are continuously monitored for validity — balances and allowances are tracked in real time. Any maker caught intentionally abusing these checks will be blacklisted. ### Sports Markets Sports markets have additional behaviors: * Outstanding limit orders are **automatically cancelled** once the game begins, clearing the entire order book at the official start time * Marketable orders have a **1-second placement delay** before matching * Game start times can shift — monitor your orders closely, as they may not be cleared if the start time changes unexpectedly *** ## Response A successful order placement returns: ```json theme={null} { "success": true, "errorMsg": "", "orderID": "0xabc123...", "takingAmount": "", "makingAmount": "", "status": "live", "transactionsHashes": [], "tradeIDs": [] } ``` ### Statuses | Status | Description | | ----------- | ------------------------------------------------------------- | | `live` | Order resting on the book | | `matched` | Order matched immediately with a resting order | | `delayed` | Marketable order accepted into an asynchronous matching delay | | `unmatched` | Marketable but failed to delay — placement still successful | Selected crypto and finance up/down markets apply a 250 ms taker delay to marketable orders. To check a specific market, call `GET https://clob.polymarket.com/clob-markets/{condition_id}` or SDK `getClobMarketInfo(conditionID)` and look for `itode: true`. The API waits for this short hold and returns the final order result, so these orders usually return `matched`, `live`, or `unmatched` rather than `delayed`. Orders cannot be canceled while they are pending in the delay window. ### Error Messages | Error | Description | | ---------------------------------- | ----------------------------------------------- | | `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size | | `INVALID_ORDER_MIN_SIZE` | Order size below the minimum threshold | | `INVALID_ORDER_DUPLICATED` | Identical order already placed | | `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Insufficient balance or allowance | | `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past | | `INVALID_POST_ONLY_ORDER_TYPE` | Post-only used with FOK/FAK | | `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book | | `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled | | `INVALID_ORDER_ERROR` | System error inserting the order | | `EXECUTION_ERROR` | System error executing the trade | | `ORDER_DELAYED` | Order match delayed due to market conditions | | `DELAYING_ORDER_ERROR` | System error while delaying the order | | `MARKET_NOT_READY` | Market not yet accepting orders | *** ## Heartbeat The heartbeat endpoint maintains session liveness. If a valid heartbeat is not received within **10 seconds** (with a 5-second buffer), **all open orders are cancelled**. ```typescript TypeScript theme={null} let heartbeatId = ""; setInterval(async () => { const resp = await client.postHeartbeat(heartbeatId); heartbeatId = resp.heartbeat_id; }, 5000); ``` ```python Python theme={null} import time heartbeat_id = "" while True: resp = client.post_heartbeat(heartbeat_id) heartbeat_id = resp["heartbeat_id"] time.sleep(5) ``` ```rust Rust theme={null} // With the `heartbeats` feature, the Rust SDK can auto-send heartbeats // in a background task — no manual loop needed: Client::start_heartbeats(&mut client)?; // ... your trading logic ... client.stop_heartbeats().await?; // Or send manually: let resp = client.post_heartbeat(None).await?; // None for first call let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?; ``` * Include the most recent `heartbeat_id` in each request. Use an empty string for the first request. * If you send an expired ID, the server responds with `400` and the correct ID. Update and retry. *** ## Next Steps Cancel single, multiple, or all open orders Attribute orders to your builder account for volume credit