Update Polymarket docs - 2026-05-14
This commit is contained in:
@@ -1,391 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
# Cancel Order
|
||||
|
||||
> Cancel single, multiple, or all open orders
|
||||
|
||||
All cancel endpoints require [L2 authentication](/trading/overview#authentication). The response always includes `canceled` (list of cancelled order IDs) and `not_canceled` (map of order IDs to failure reasons).
|
||||
|
||||
***
|
||||
|
||||
## Cancel a Single Order
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const resp = await client.cancelOrder("0xb816482a...");
|
||||
console.log(resp);
|
||||
// { canceled: ["0xb816482a..."], not_canceled: {} }
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
resp = client.cancel(order_id="0xb816482a...")
|
||||
print(resp)
|
||||
# {"canceled": ["0xb816482a..."], "not_canceled": {}}
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.cancel_order("0xb816482a...").await?;
|
||||
println!("{:?}", resp);
|
||||
// CancelOrdersResponse { canceled: ["0xb816482a..."], not_canceled: {} }
|
||||
```
|
||||
|
||||
```bash REST theme={null}
|
||||
curl -X DELETE "https://clob.polymarket.com/order" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "POLY_ADDRESS: ..." \
|
||||
-H "POLY_SIGNATURE: ..." \
|
||||
-H "POLY_TIMESTAMP: ..." \
|
||||
-H "POLY_API_KEY: ..." \
|
||||
-H "POLY_PASSPHRASE: ..." \
|
||||
-d '{"orderID": "0xb816482a..."}'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Cancel Multiple Orders
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const resp = await client.cancelOrders(["0xb816482a...", "0xc927593b..."]);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
resp = client.cancel_orders([
|
||||
"0xb816482a...",
|
||||
"0xc927593b...",
|
||||
])
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.cancel_orders(&["0xb816482a...", "0xc927593b..."]).await?;
|
||||
```
|
||||
|
||||
```bash REST theme={null}
|
||||
curl -X DELETE "https://clob.polymarket.com/orders" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "POLY_ADDRESS: ..." \
|
||||
-H "POLY_SIGNATURE: ..." \
|
||||
-H "POLY_TIMESTAMP: ..." \
|
||||
-H "POLY_API_KEY: ..." \
|
||||
-H "POLY_PASSPHRASE: ..." \
|
||||
-d '["0xb816482a...", "0xc927593b..."]'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Cancel All Orders
|
||||
|
||||
Cancel every open order across all markets:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const resp = await client.cancelAll();
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
resp = client.cancel_all()
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.cancel_all_orders().await?;
|
||||
```
|
||||
|
||||
```bash REST theme={null}
|
||||
curl -X DELETE "https://clob.polymarket.com/cancel-all" \
|
||||
-H "POLY_ADDRESS: ..." \
|
||||
-H "POLY_SIGNATURE: ..." \
|
||||
-H "POLY_TIMESTAMP: ..." \
|
||||
-H "POLY_API_KEY: ..." \
|
||||
-H "POLY_PASSPHRASE: ..."
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Cancel by Market
|
||||
|
||||
Cancel all orders for a specific market, optionally filtered to a single token. Both `market` and `asset_id` are optional — omit both to cancel all orders.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const resp = await client.cancelMarketOrders({
|
||||
market: "0xbd31dc8a...", // optional: condition ID
|
||||
asset_id: "52114319501245...", // optional: specific token
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
resp = client.cancel_market_orders(
|
||||
market="0xbd31dc8a...",
|
||||
asset_id="52114319501245...", # optional
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::CancelMarketOrderRequest;
|
||||
|
||||
let request = CancelMarketOrderRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.asset_id("52114319501245...".parse()?)
|
||||
.build();
|
||||
let resp = client.cancel_market_orders(&request).await?;
|
||||
```
|
||||
|
||||
```bash REST theme={null}
|
||||
curl -X DELETE "https://clob.polymarket.com/cancel-market-orders" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "POLY_ADDRESS: ..." \
|
||||
-H "POLY_SIGNATURE: ..." \
|
||||
-H "POLY_TIMESTAMP: ..." \
|
||||
-H "POLY_API_KEY: ..." \
|
||||
-H "POLY_PASSPHRASE: ..." \
|
||||
-d '{"market": "0xbd31dc8a...", "asset_id": "52114319501245..."}'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Querying Orders
|
||||
|
||||
### Get a Single Order
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const order = await client.getOrder("0xb816482a...");
|
||||
console.log(order.status, order.size_matched);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
order = client.get_order("0xb816482a...")
|
||||
print(order["status"], order["size_matched"])
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let order = client.order("0xb816482a...").await?;
|
||||
println!("{:?} {}", order.status, order.size_matched);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Get Open Orders
|
||||
|
||||
Retrieve all open orders, optionally filtered by market or token:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All open orders
|
||||
const orders = await client.getOpenOrders();
|
||||
|
||||
// Filtered by market
|
||||
const marketOrders = await client.getOpenOrders({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// Filtered by token
|
||||
const tokenOrders = await client.getOpenOrders({
|
||||
asset_id: "52114319501245...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OpenOrderParams
|
||||
|
||||
# All open orders
|
||||
orders = client.get_orders()
|
||||
|
||||
# Filtered by market
|
||||
market_orders = client.get_orders(
|
||||
OpenOrderParams(market="0xbd31dc8a...")
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::OrdersRequest;
|
||||
|
||||
// All open orders
|
||||
let orders = client.orders(&OrdersRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = OrdersRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_orders = client.orders(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### OpenOrder Object
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | --------- | ------------------------------------------ |
|
||||
| `id` | string | Order ID |
|
||||
| `status` | string | Current order status |
|
||||
| `market` | string | Condition ID |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `original_size` | string | Size at placement |
|
||||
| `size_matched` | string | Amount filled |
|
||||
| `price` | string | Limit price |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `owner` | string | API key of the order owner |
|
||||
| `associate_trades` | string\[] | Trade IDs this order has been included in |
|
||||
| `expiration` | string | Unix expiration timestamp (`0` if none) |
|
||||
| `created_at` | string | Unix creation timestamp |
|
||||
|
||||
***
|
||||
|
||||
## Trade History
|
||||
|
||||
When an order is matched, it creates a trade. Trades progress through these statuses:
|
||||
|
||||
| Status | Terminal | Description |
|
||||
| ----------- | -------- | --------------------------------------- |
|
||||
| `MATCHED` | No | Matched and sent for onchain submission |
|
||||
| `MINED` | No | Mined on the chain, no finality yet |
|
||||
| `CONFIRMED` | Yes | Achieved finality — trade successful |
|
||||
| `RETRYING` | No | Transaction failed — being retried |
|
||||
| `FAILED` | Yes | Failed permanently |
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All trades
|
||||
const trades = await client.getTrades();
|
||||
|
||||
// Filtered by market
|
||||
const marketTrades = await client.getTrades({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import TradeParams
|
||||
|
||||
trades = client.get_trades()
|
||||
|
||||
market_trades = client.get_trades(
|
||||
TradeParams(market="0xbd31dc8a...")
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::TradesRequest;
|
||||
|
||||
// All trades
|
||||
let trades = client.trades(&TradesRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = TradesRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_trades = client.trades(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Additional filter parameters: `id`, `maker_address`, `asset_id`, `before`, `after`.
|
||||
|
||||
The Rust SDK uses cursor-based pagination via the `next_cursor` parameter:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const page = await client.getTradesPaginated({ market: "0xbd31dc8a..." });
|
||||
console.log(page.trades, page.count); // trades array + total count
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
page = client.get_trades_paginated(TradeParams(market="0xbd31dc8a..."))
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// First page
|
||||
let page = client.trades(&request, None).await?;
|
||||
println!("{} trades, cursor: {}", page.data.len(), page.next_cursor);
|
||||
|
||||
// Next page
|
||||
let page2 = client.trades(&request, Some(page.next_cursor)).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Trade Object
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | ------------- | ------------------------------------ |
|
||||
| `id` | string | Trade ID |
|
||||
| `taker_order_id` | string | Taker order hash |
|
||||
| `market` | string | Condition ID |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `size` | string | Trade size |
|
||||
| `price` | string | Execution price |
|
||||
| `fee_rate_bps` | string | Fee rate in basis points |
|
||||
| `status` | string | Trade status (see table above) |
|
||||
| `match_time` | string | Unix timestamp when matched |
|
||||
| `last_update` | string | Unix timestamp of last status change |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes") |
|
||||
| `maker_address` | string | Maker's funder address |
|
||||
| `owner` | string | API key of the trade owner |
|
||||
| `transaction_hash` | string | Onchain transaction hash |
|
||||
| `bucket_index` | number | Index for trade reconciliation |
|
||||
| `trader_side` | string | `TAKER` or `MAKER` |
|
||||
| `maker_orders` | MakerOrder\[] | Maker orders that filled this trade |
|
||||
|
||||
<Note>
|
||||
A single trade can be split across multiple onchain transactions due to gas
|
||||
limits. Use `bucket_index` and `match_time` to reconcile related transactions
|
||||
back to a single logical trade.
|
||||
</Note>
|
||||
|
||||
***
|
||||
|
||||
## Order Scoring
|
||||
|
||||
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Single order
|
||||
const scoring = await client.isOrderScoring({ orderId: "0x..." });
|
||||
|
||||
// Multiple orders
|
||||
const batch = await client.areOrdersScoring({
|
||||
orderIds: ["0x...", "0x..."],
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
|
||||
|
||||
scoring = client.is_order_scoring(
|
||||
OrderScoringParams(orderId="0x...")
|
||||
)
|
||||
|
||||
batch = client.are_orders_scoring(
|
||||
OrdersScoringParams(orderIds=["0x...", "0x..."])
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// Single order
|
||||
let scoring = client.is_order_scoring("0x...").await?;
|
||||
|
||||
// Multiple orders
|
||||
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
|
||||
Attribute orders to your builder account for volume credit
|
||||
</Card>
|
||||
|
||||
<Card title="Fees" icon="receipt" href="/trading/fees">
|
||||
Understand fee structures and maker rebates
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,544 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
# Overview
|
||||
|
||||
> Order types, tick sizes, and querying 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 underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client-v2) or [Python](https://github.com/Polymarket/py-clob-client-v2) SDK clients, which handle signing and submission for you.
|
||||
|
||||
<Info>
|
||||
If you prefer to use the REST API directly, you'll need to manage order
|
||||
signing yourself. See [Authentication](/api-reference/authentication) for details on
|
||||
constructing the required headers.
|
||||
</Info>
|
||||
|
||||
***
|
||||
|
||||
## Order Types
|
||||
|
||||
| Type | Behavior | Use Case |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
|
||||
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
|
||||
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
|
||||
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
|
||||
|
||||
* **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
|
||||
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
|
||||
|
||||
<Note>
|
||||
**GTD expiration**: There is a security threshold of one minute. If you need
|
||||
the order to expire in 90 seconds, the correct expiration value is `now + 1
|
||||
minute + 30 seconds`.
|
||||
</Note>
|
||||
|
||||
### Post-Only Orders
|
||||
|
||||
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
|
||||
|
||||
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
|
||||
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
|
||||
* Post-only can only be used with **GTC** and **GTD** order types.
|
||||
|
||||
***
|
||||
|
||||
## Tick Sizes
|
||||
|
||||
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
|
||||
|
||||
| Tick Size | Price 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 |
|
||||
|
||||
Retrieve the tick size for a market using the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const tickSize = await client.getTickSize(tokenID);
|
||||
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
tick_size = client.get_tick_size(token_id)
|
||||
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.tick_size(token_id).await?;
|
||||
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
You can also check the `minimum_tick_size` field on a market object returned
|
||||
by the [Markets API](/market-data/fetching-markets).
|
||||
</Tip>
|
||||
|
||||
***
|
||||
|
||||
## Negative Risk
|
||||
|
||||
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const response = await client.createAndPostOrder(
|
||||
{
|
||||
tokenID: "TOKEN_ID",
|
||||
price: 0.5,
|
||||
size: 10,
|
||||
side: Side.BUY,
|
||||
},
|
||||
{
|
||||
tickSize: "0.01",
|
||||
negRisk: true, // Required for multi-outcome markets
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderArgs, 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=True, # Required for multi-outcome markets
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
|
||||
// The order builder fetches neg_risk and uses the correct exchange contract.
|
||||
let order = client
|
||||
.limit_order()
|
||||
.token_id("TOKEN_ID".parse()?)
|
||||
.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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const isNegRisk = await client.getNegRisk(tokenID);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
is_neg_risk = client.get_neg_risk(token_id)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let is_neg_risk = client.neg_risk(token_id).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Allowances
|
||||
|
||||
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
|
||||
|
||||
* **Buying**: the funder must have set a **pUSD** allowance greater than or equal to the spending amount.
|
||||
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
|
||||
|
||||
This allows the Exchange contract to execute settlement according to your signed order instructions.
|
||||
|
||||
***
|
||||
|
||||
## Validity Checks
|
||||
|
||||
Orders are continually monitored to make sure they remain valid. This includes tracking:
|
||||
|
||||
* Underlying balances
|
||||
* Allowances
|
||||
|
||||
<Warning>
|
||||
Any maker caught intentionally abusing these checks will be blacklisted.
|
||||
</Warning>
|
||||
|
||||
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 pUSD in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
|
||||
|
||||
The max size you can place for an order is:
|
||||
|
||||
$$
|
||||
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
|
||||
$$
|
||||
|
||||
***
|
||||
|
||||
## Querying Orders
|
||||
|
||||
All query endpoints require [L2 authentication](/api-reference/authentication). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
|
||||
|
||||
### Get a Single Order
|
||||
|
||||
Retrieve details for a specific order by its ID:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const order = await client.getOrder("0xb816482a...");
|
||||
console.log(order);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
order = client.get_order("0xb816482a...")
|
||||
print(order)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let order = client.order("0xb816482a...").await?;
|
||||
println!("{order:?}");
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Get Open Orders
|
||||
|
||||
Retrieve your open orders, optionally filtered by market or asset:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All open orders
|
||||
const orders = await client.getOpenOrders();
|
||||
|
||||
// Filtered by market
|
||||
const marketOrders = await client.getOpenOrders({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// Filtered by asset
|
||||
const assetOrders = await client.getOpenOrders({
|
||||
asset_id: "52114319501245...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OpenOrderParams
|
||||
|
||||
# All open orders
|
||||
orders = client.get_orders()
|
||||
|
||||
# Filtered by market
|
||||
market_orders = client.get_orders(
|
||||
OpenOrderParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::OrdersRequest;
|
||||
|
||||
// All open orders
|
||||
let orders = client.orders(&OrdersRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = OrdersRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_orders = client.orders(&request, None).await?;
|
||||
|
||||
// Filtered by asset
|
||||
let request = OrdersRequest::builder()
|
||||
.asset_id("52114319501245...".parse()?)
|
||||
.build();
|
||||
let asset_orders = client.orders(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### OpenOrder Object
|
||||
|
||||
Each order returned contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | --------- | ------------------------------------------------------------ |
|
||||
| `id` | string | Order ID |
|
||||
| `status` | string | Current order status |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `original_size` | string | Original order size at placement |
|
||||
| `size_matched` | string | Amount that has been filled |
|
||||
| `price` | string | Limit price |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `owner` | string | API key of the order owner |
|
||||
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
|
||||
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
|
||||
| `created_at` | string | Unix timestamp when the order was created |
|
||||
|
||||
***
|
||||
|
||||
## Trade History
|
||||
|
||||
When an order is matched, it creates a trade. Trades go through the following statuses:
|
||||
|
||||
| Status | Terminal? | Description |
|
||||
| ----------- | --------- | -------------------------------------------------------------------- |
|
||||
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
|
||||
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
|
||||
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
|
||||
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
|
||||
| `FAILED` | Yes | Trade failed permanently and is not being retried |
|
||||
|
||||
### Trade Object
|
||||
|
||||
Each trade contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | ------ | ------------------------------------------------------------ |
|
||||
| `id` | string | Trade ID |
|
||||
| `taker_order_id` | string | Taker order ID (hash) |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `size` | string | Trade size |
|
||||
| `fee_rate_bps` | string | Fee rate in basis points |
|
||||
| `price` | string | Trade price |
|
||||
| `status` | string | Trade status (see table above) |
|
||||
| `match_time` | string | Unix timestamp when the trade was matched |
|
||||
| `last_update` | string | Unix timestamp of last status update |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `owner` | string | API key ID of the trade owner |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
|
||||
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
|
||||
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
|
||||
|
||||
### MakerOrder Fields
|
||||
|
||||
Each entry in the `maker_orders` array contains:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ---------------- | ------ | ---------------------------- |
|
||||
| `order_id` | string | Maker order ID (hash) |
|
||||
| `owner` | string | Maker's API key ID |
|
||||
| `maker_address` | string | Maker's funder address |
|
||||
| `matched_amount` | string | Amount matched in this trade |
|
||||
| `price` | string | Maker order price |
|
||||
| `fee_rate_bps` | string | Maker fee rate in bps |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `outcome` | string | Outcome name |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
|
||||
Retrieve your trades with the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All trades
|
||||
const trades = await client.getTrades();
|
||||
|
||||
// Filtered by market
|
||||
const marketTrades = await client.getTrades({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// With pagination
|
||||
const paginatedTrades = await client.getTradesPaginated({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import TradeParams
|
||||
|
||||
# All trades
|
||||
trades = client.get_trades()
|
||||
|
||||
# Filtered by market
|
||||
market_trades = client.get_trades(
|
||||
TradeParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::TradesRequest;
|
||||
|
||||
// All trades
|
||||
let trades = client.trades(&TradesRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = TradesRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_trades = client.trades(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Heartbeat
|
||||
|
||||
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Send heartbeats in a loop
|
||||
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, auto-send in background:
|
||||
Client::start_heartbeats(&mut client)?;
|
||||
|
||||
// Or manually:
|
||||
let resp = client.post_heartbeat(None).await?; // None for first call
|
||||
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
|
||||
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
|
||||
|
||||
***
|
||||
|
||||
## Order Scoring
|
||||
|
||||
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Single order
|
||||
const scoring = await client.isOrderScoring({ orderId: "0x..." });
|
||||
console.log(scoring); // { scoring: true }
|
||||
|
||||
// Multiple orders
|
||||
const batchScoring = await client.areOrdersScoring({
|
||||
orderIds: ["0x...", "0x..."],
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
|
||||
|
||||
# Single order
|
||||
scoring = client.is_order_scoring(
|
||||
OrderScoringParams(orderId="0x...")
|
||||
)
|
||||
|
||||
# Multiple orders
|
||||
batch_scoring = client.are_orders_scoring(
|
||||
OrdersScoringParams(orderIds=["0x...", "0x..."])
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// Single order
|
||||
let scoring = client.is_order_scoring("0x...").await?;
|
||||
println!("Scoring: {}", scoring.scoring);
|
||||
|
||||
// Multiple orders
|
||||
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Onchain Order Info
|
||||
|
||||
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
|
||||
|
||||
| Field | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `orderHash` | Unique hash for the filled order |
|
||||
| `maker` | The user who generated the order and source of funds |
|
||||
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
|
||||
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving pUSD for outcome tokens) |
|
||||
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving pUSD for outcome tokens) |
|
||||
| `makerAmountFilled` | Amount of the asset given out |
|
||||
| `takerAmountFilled` | Amount of the asset received |
|
||||
| `fee` | Fees paid by the order maker |
|
||||
|
||||
***
|
||||
|
||||
## Error Messages
|
||||
|
||||
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
|
||||
|
||||
| Error | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------ |
|
||||
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
|
||||
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
|
||||
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
|
||||
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
|
||||
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
|
||||
| `INVALID_ORDER_ERROR` | System error while inserting order |
|
||||
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
|
||||
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
|
||||
| `EXECUTION_ERROR` | System error while executing trade |
|
||||
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
|
||||
| `DELAYING_ORDER_ERROR` | System error while delaying order |
|
||||
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
|
||||
| `MARKET_NOT_READY` | Market is not yet accepting orders |
|
||||
|
||||
### Insert Statuses
|
||||
|
||||
When an order is successfully placed, the response includes a `status` field:
|
||||
|
||||
| Status | Description |
|
||||
| ----------- | -------------------------------------------------------------------- |
|
||||
| `matched` | Order placed and matched with a resting order |
|
||||
| `live` | Order placed and resting on the book |
|
||||
| `delayed` | Order is marketable but subject to a matching delay |
|
||||
| `unmatched` | Order is marketable but failed to delay — placement still successful |
|
||||
|
||||
***
|
||||
|
||||
## Security
|
||||
|
||||
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
|
||||
|
||||
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades.
|
||||
|
||||
***
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Create Order" icon="plus" href="/trading/orders/create">
|
||||
Build, sign, and submit orders
|
||||
</Card>
|
||||
|
||||
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
|
||||
Cancel single, multiple, or all orders
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,689 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
<Info>
|
||||
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.
|
||||
</Info>
|
||||
|
||||
***
|
||||
|
||||
## 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:
|
||||
|
||||
<CodeGroup>
|
||||
```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);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Two-Step Sign Then Submit
|
||||
|
||||
For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## GTD Orders
|
||||
|
||||
GTD orders auto-expire at a specified time. Useful for quoting around known events.
|
||||
|
||||
<CodeGroup>
|
||||
```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::hours(1))
|
||||
.build()
|
||||
.await?;
|
||||
let signed = client.sign(&signer, order).await?;
|
||||
let response = client.post_order(signed).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Note>
|
||||
There is a security threshold of one minute on GTD expiration. To set an
|
||||
effective lifetime of N seconds, use `now + 60 + N`. For example, for a
|
||||
30-second effective lifetime, set the expiration to `now + 60 + 30`.
|
||||
</Note>
|
||||
|
||||
***
|
||||
|
||||
## Market Orders
|
||||
|
||||
Market orders execute immediately against resting liquidity using FOK or FAK types:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* **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:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## 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.
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* 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:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## 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 |
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Negative Risk
|
||||
|
||||
Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets.
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
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.
|
||||
</Tip>
|
||||
|
||||
***
|
||||
|
||||
## 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})
|
||||
$$
|
||||
|
||||
<Warning>
|
||||
Orders are continuously monitored for validity — balances and allowances are
|
||||
tracked in real time. Any maker caught intentionally abusing these checks will
|
||||
be blacklisted.
|
||||
</Warning>
|
||||
|
||||
### 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 subject to a matching delay |
|
||||
| `unmatched` | Marketable but failed to delay — placement still successful |
|
||||
|
||||
### 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**.
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* 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
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Cancel Orders" icon="xmark" href="/trading/orders/cancel">
|
||||
Cancel single, multiple, or all open orders
|
||||
</Card>
|
||||
|
||||
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
|
||||
Attribute orders to your builder account for volume credit
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,689 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
<Info>
|
||||
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.
|
||||
</Info>
|
||||
|
||||
***
|
||||
|
||||
## 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:
|
||||
|
||||
<CodeGroup>
|
||||
```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);
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Two-Step Sign Then Submit
|
||||
|
||||
For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## GTD Orders
|
||||
|
||||
GTD orders auto-expire at a specified time. Useful for quoting around known events.
|
||||
|
||||
<CodeGroup>
|
||||
```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::hours(1))
|
||||
.build()
|
||||
.await?;
|
||||
let signed = client.sign(&signer, order).await?;
|
||||
let response = client.post_order(signed).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Note>
|
||||
There is a security threshold of one minute on GTD expiration. To set an
|
||||
effective lifetime of N seconds, use `now + 60 + N`. For example, for a
|
||||
30-second effective lifetime, set the expiration to `now + 60 + 30`.
|
||||
</Note>
|
||||
|
||||
***
|
||||
|
||||
## Market Orders
|
||||
|
||||
Market orders execute immediately against resting liquidity using FOK or FAK types:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* **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:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## 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.
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* 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:
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## 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 |
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Negative Risk
|
||||
|
||||
Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets.
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
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.
|
||||
</Tip>
|
||||
|
||||
***
|
||||
|
||||
## 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})
|
||||
$$
|
||||
|
||||
<Warning>
|
||||
Orders are continuously monitored for validity — balances and allowances are
|
||||
tracked in real time. Any maker caught intentionally abusing these checks will
|
||||
be blacklisted.
|
||||
</Warning>
|
||||
|
||||
### 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 subject to a matching delay |
|
||||
| `unmatched` | Marketable but failed to delay — placement still successful |
|
||||
|
||||
### 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**.
|
||||
|
||||
<CodeGroup>
|
||||
```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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* 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
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Cancel Orders" icon="xmark" href="/trading/orders/cancel">
|
||||
Cancel single, multiple, or all open orders
|
||||
</Card>
|
||||
|
||||
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
|
||||
Attribute orders to your builder account for volume credit
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,544 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
# Overview
|
||||
|
||||
> Order types, tick sizes, and querying 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 underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client-v2) or [Python](https://github.com/Polymarket/py-clob-client-v2) SDK clients, which handle signing and submission for you.
|
||||
|
||||
<Info>
|
||||
If you prefer to use the REST API directly, you'll need to manage order
|
||||
signing yourself. See [Authentication](/api-reference/authentication) for details on
|
||||
constructing the required headers.
|
||||
</Info>
|
||||
|
||||
***
|
||||
|
||||
## Order Types
|
||||
|
||||
| Type | Behavior | Use Case |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
|
||||
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
|
||||
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
|
||||
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
|
||||
|
||||
* **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
|
||||
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
|
||||
|
||||
<Note>
|
||||
**GTD expiration**: There is a security threshold of one minute. If you need
|
||||
the order to expire in 90 seconds, the correct expiration value is `now + 1
|
||||
minute + 30 seconds`.
|
||||
</Note>
|
||||
|
||||
### Post-Only Orders
|
||||
|
||||
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
|
||||
|
||||
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
|
||||
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
|
||||
* Post-only can only be used with **GTC** and **GTD** order types.
|
||||
|
||||
***
|
||||
|
||||
## Tick Sizes
|
||||
|
||||
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
|
||||
|
||||
| Tick Size | Price 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 |
|
||||
|
||||
Retrieve the tick size for a market using the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const tickSize = await client.getTickSize(tokenID);
|
||||
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
tick_size = client.get_tick_size(token_id)
|
||||
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.tick_size(token_id).await?;
|
||||
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
You can also check the `minimum_tick_size` field on a market object returned
|
||||
by the [Markets API](/market-data/fetching-markets).
|
||||
</Tip>
|
||||
|
||||
***
|
||||
|
||||
## Negative Risk
|
||||
|
||||
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const response = await client.createAndPostOrder(
|
||||
{
|
||||
tokenID: "TOKEN_ID",
|
||||
price: 0.5,
|
||||
size: 10,
|
||||
side: Side.BUY,
|
||||
},
|
||||
{
|
||||
tickSize: "0.01",
|
||||
negRisk: true, // Required for multi-outcome markets
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderArgs, 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=True, # Required for multi-outcome markets
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
|
||||
// The order builder fetches neg_risk and uses the correct exchange contract.
|
||||
let order = client
|
||||
.limit_order()
|
||||
.token_id("TOKEN_ID".parse()?)
|
||||
.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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const isNegRisk = await client.getNegRisk(tokenID);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
is_neg_risk = client.get_neg_risk(token_id)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let is_neg_risk = client.neg_risk(token_id).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Allowances
|
||||
|
||||
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
|
||||
|
||||
* **Buying**: the funder must have set a **pUSD** allowance greater than or equal to the spending amount.
|
||||
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
|
||||
|
||||
This allows the Exchange contract to execute settlement according to your signed order instructions.
|
||||
|
||||
***
|
||||
|
||||
## Validity Checks
|
||||
|
||||
Orders are continually monitored to make sure they remain valid. This includes tracking:
|
||||
|
||||
* Underlying balances
|
||||
* Allowances
|
||||
|
||||
<Warning>
|
||||
Any maker caught intentionally abusing these checks will be blacklisted.
|
||||
</Warning>
|
||||
|
||||
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 pUSD in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
|
||||
|
||||
The max size you can place for an order is:
|
||||
|
||||
$$
|
||||
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
|
||||
$$
|
||||
|
||||
***
|
||||
|
||||
## Querying Orders
|
||||
|
||||
All query endpoints require [L2 authentication](/api-reference/authentication). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
|
||||
|
||||
### Get a Single Order
|
||||
|
||||
Retrieve details for a specific order by its ID:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const order = await client.getOrder("0xb816482a...");
|
||||
console.log(order);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
order = client.get_order("0xb816482a...")
|
||||
print(order)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let order = client.order("0xb816482a...").await?;
|
||||
println!("{order:?}");
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Get Open Orders
|
||||
|
||||
Retrieve your open orders, optionally filtered by market or asset:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All open orders
|
||||
const orders = await client.getOpenOrders();
|
||||
|
||||
// Filtered by market
|
||||
const marketOrders = await client.getOpenOrders({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// Filtered by asset
|
||||
const assetOrders = await client.getOpenOrders({
|
||||
asset_id: "52114319501245...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OpenOrderParams
|
||||
|
||||
# All open orders
|
||||
orders = client.get_orders()
|
||||
|
||||
# Filtered by market
|
||||
market_orders = client.get_orders(
|
||||
OpenOrderParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::OrdersRequest;
|
||||
|
||||
// All open orders
|
||||
let orders = client.orders(&OrdersRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = OrdersRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_orders = client.orders(&request, None).await?;
|
||||
|
||||
// Filtered by asset
|
||||
let request = OrdersRequest::builder()
|
||||
.asset_id("52114319501245...".parse()?)
|
||||
.build();
|
||||
let asset_orders = client.orders(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### OpenOrder Object
|
||||
|
||||
Each order returned contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | --------- | ------------------------------------------------------------ |
|
||||
| `id` | string | Order ID |
|
||||
| `status` | string | Current order status |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `original_size` | string | Original order size at placement |
|
||||
| `size_matched` | string | Amount that has been filled |
|
||||
| `price` | string | Limit price |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `owner` | string | API key of the order owner |
|
||||
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
|
||||
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
|
||||
| `created_at` | string | Unix timestamp when the order was created |
|
||||
|
||||
***
|
||||
|
||||
## Trade History
|
||||
|
||||
When an order is matched, it creates a trade. Trades go through the following statuses:
|
||||
|
||||
| Status | Terminal? | Description |
|
||||
| ----------- | --------- | -------------------------------------------------------------------- |
|
||||
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
|
||||
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
|
||||
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
|
||||
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
|
||||
| `FAILED` | Yes | Trade failed permanently and is not being retried |
|
||||
|
||||
### Trade Object
|
||||
|
||||
Each trade contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | ------ | ------------------------------------------------------------ |
|
||||
| `id` | string | Trade ID |
|
||||
| `taker_order_id` | string | Taker order ID (hash) |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `size` | string | Trade size |
|
||||
| `fee_rate_bps` | string | Fee rate in basis points |
|
||||
| `price` | string | Trade price |
|
||||
| `status` | string | Trade status (see table above) |
|
||||
| `match_time` | string | Unix timestamp when the trade was matched |
|
||||
| `last_update` | string | Unix timestamp of last status update |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `owner` | string | API key ID of the trade owner |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
|
||||
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
|
||||
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
|
||||
|
||||
### MakerOrder Fields
|
||||
|
||||
Each entry in the `maker_orders` array contains:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ---------------- | ------ | ---------------------------- |
|
||||
| `order_id` | string | Maker order ID (hash) |
|
||||
| `owner` | string | Maker's API key ID |
|
||||
| `maker_address` | string | Maker's funder address |
|
||||
| `matched_amount` | string | Amount matched in this trade |
|
||||
| `price` | string | Maker order price |
|
||||
| `fee_rate_bps` | string | Maker fee rate in bps |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `outcome` | string | Outcome name |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
|
||||
Retrieve your trades with the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All trades
|
||||
const trades = await client.getTrades();
|
||||
|
||||
// Filtered by market
|
||||
const marketTrades = await client.getTrades({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// With pagination
|
||||
const paginatedTrades = await client.getTradesPaginated({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import TradeParams
|
||||
|
||||
# All trades
|
||||
trades = client.get_trades()
|
||||
|
||||
# Filtered by market
|
||||
market_trades = client.get_trades(
|
||||
TradeParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::TradesRequest;
|
||||
|
||||
// All trades
|
||||
let trades = client.trades(&TradesRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = TradesRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_trades = client.trades(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Heartbeat
|
||||
|
||||
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Send heartbeats in a loop
|
||||
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, auto-send in background:
|
||||
Client::start_heartbeats(&mut client)?;
|
||||
|
||||
// Or manually:
|
||||
let resp = client.post_heartbeat(None).await?; // None for first call
|
||||
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
|
||||
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
|
||||
|
||||
***
|
||||
|
||||
## Order Scoring
|
||||
|
||||
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Single order
|
||||
const scoring = await client.isOrderScoring({ orderId: "0x..." });
|
||||
console.log(scoring); // { scoring: true }
|
||||
|
||||
// Multiple orders
|
||||
const batchScoring = await client.areOrdersScoring({
|
||||
orderIds: ["0x...", "0x..."],
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
|
||||
|
||||
# Single order
|
||||
scoring = client.is_order_scoring(
|
||||
OrderScoringParams(orderId="0x...")
|
||||
)
|
||||
|
||||
# Multiple orders
|
||||
batch_scoring = client.are_orders_scoring(
|
||||
OrdersScoringParams(orderIds=["0x...", "0x..."])
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// Single order
|
||||
let scoring = client.is_order_scoring("0x...").await?;
|
||||
println!("Scoring: {}", scoring.scoring);
|
||||
|
||||
// Multiple orders
|
||||
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Onchain Order Info
|
||||
|
||||
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
|
||||
|
||||
| Field | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `orderHash` | Unique hash for the filled order |
|
||||
| `maker` | The user who generated the order and source of funds |
|
||||
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
|
||||
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving pUSD for outcome tokens) |
|
||||
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving pUSD for outcome tokens) |
|
||||
| `makerAmountFilled` | Amount of the asset given out |
|
||||
| `takerAmountFilled` | Amount of the asset received |
|
||||
| `fee` | Fees paid by the order maker |
|
||||
|
||||
***
|
||||
|
||||
## Error Messages
|
||||
|
||||
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
|
||||
|
||||
| Error | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------ |
|
||||
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
|
||||
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
|
||||
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
|
||||
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
|
||||
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
|
||||
| `INVALID_ORDER_ERROR` | System error while inserting order |
|
||||
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
|
||||
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
|
||||
| `EXECUTION_ERROR` | System error while executing trade |
|
||||
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
|
||||
| `DELAYING_ORDER_ERROR` | System error while delaying order |
|
||||
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
|
||||
| `MARKET_NOT_READY` | Market is not yet accepting orders |
|
||||
|
||||
### Insert Statuses
|
||||
|
||||
When an order is successfully placed, the response includes a `status` field:
|
||||
|
||||
| Status | Description |
|
||||
| ----------- | -------------------------------------------------------------------- |
|
||||
| `matched` | Order placed and matched with a resting order |
|
||||
| `live` | Order placed and resting on the book |
|
||||
| `delayed` | Order is marketable but subject to a matching delay |
|
||||
| `unmatched` | Order is marketable but failed to delay — placement still successful |
|
||||
|
||||
***
|
||||
|
||||
## Security
|
||||
|
||||
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
|
||||
|
||||
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades.
|
||||
|
||||
***
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Create Order" icon="plus" href="/trading/orders/create">
|
||||
Build, sign, and submit orders
|
||||
</Card>
|
||||
|
||||
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
|
||||
Cancel single, multiple, or all orders
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,544 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
# Overview
|
||||
|
||||
> Order types, tick sizes, and querying 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 underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client-v2) or [Python](https://github.com/Polymarket/py-clob-client-v2) SDK clients, which handle signing and submission for you.
|
||||
|
||||
<Info>
|
||||
If you prefer to use the REST API directly, you'll need to manage order
|
||||
signing yourself. See [Authentication](/api-reference/authentication) for details on
|
||||
constructing the required headers.
|
||||
</Info>
|
||||
|
||||
***
|
||||
|
||||
## Order Types
|
||||
|
||||
| Type | Behavior | Use Case |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
|
||||
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
|
||||
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
|
||||
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
|
||||
|
||||
* **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
|
||||
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
|
||||
|
||||
<Note>
|
||||
**GTD expiration**: There is a security threshold of one minute. If you need
|
||||
the order to expire in 90 seconds, the correct expiration value is `now + 1
|
||||
minute + 30 seconds`.
|
||||
</Note>
|
||||
|
||||
### Post-Only Orders
|
||||
|
||||
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
|
||||
|
||||
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
|
||||
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
|
||||
* Post-only can only be used with **GTC** and **GTD** order types.
|
||||
|
||||
***
|
||||
|
||||
## Tick Sizes
|
||||
|
||||
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
|
||||
|
||||
| Tick Size | Price 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 |
|
||||
|
||||
Retrieve the tick size for a market using the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const tickSize = await client.getTickSize(tokenID);
|
||||
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
tick_size = client.get_tick_size(token_id)
|
||||
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.tick_size(token_id).await?;
|
||||
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
You can also check the `minimum_tick_size` field on a market object returned
|
||||
by the [Markets API](/market-data/fetching-markets).
|
||||
</Tip>
|
||||
|
||||
***
|
||||
|
||||
## Negative Risk
|
||||
|
||||
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const response = await client.createAndPostOrder(
|
||||
{
|
||||
tokenID: "TOKEN_ID",
|
||||
price: 0.5,
|
||||
size: 10,
|
||||
side: Side.BUY,
|
||||
},
|
||||
{
|
||||
tickSize: "0.01",
|
||||
negRisk: true, // Required for multi-outcome markets
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderArgs, 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=True, # Required for multi-outcome markets
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
|
||||
// The order builder fetches neg_risk and uses the correct exchange contract.
|
||||
let order = client
|
||||
.limit_order()
|
||||
.token_id("TOKEN_ID".parse()?)
|
||||
.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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const isNegRisk = await client.getNegRisk(tokenID);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
is_neg_risk = client.get_neg_risk(token_id)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let is_neg_risk = client.neg_risk(token_id).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Allowances
|
||||
|
||||
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
|
||||
|
||||
* **Buying**: the funder must have set a **pUSD** allowance greater than or equal to the spending amount.
|
||||
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
|
||||
|
||||
This allows the Exchange contract to execute settlement according to your signed order instructions.
|
||||
|
||||
***
|
||||
|
||||
## Validity Checks
|
||||
|
||||
Orders are continually monitored to make sure they remain valid. This includes tracking:
|
||||
|
||||
* Underlying balances
|
||||
* Allowances
|
||||
|
||||
<Warning>
|
||||
Any maker caught intentionally abusing these checks will be blacklisted.
|
||||
</Warning>
|
||||
|
||||
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 pUSD in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
|
||||
|
||||
The max size you can place for an order is:
|
||||
|
||||
$$
|
||||
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
|
||||
$$
|
||||
|
||||
***
|
||||
|
||||
## Querying Orders
|
||||
|
||||
All query endpoints require [L2 authentication](/api-reference/authentication). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
|
||||
|
||||
### Get a Single Order
|
||||
|
||||
Retrieve details for a specific order by its ID:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const order = await client.getOrder("0xb816482a...");
|
||||
console.log(order);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
order = client.get_order("0xb816482a...")
|
||||
print(order)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let order = client.order("0xb816482a...").await?;
|
||||
println!("{order:?}");
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Get Open Orders
|
||||
|
||||
Retrieve your open orders, optionally filtered by market or asset:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All open orders
|
||||
const orders = await client.getOpenOrders();
|
||||
|
||||
// Filtered by market
|
||||
const marketOrders = await client.getOpenOrders({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// Filtered by asset
|
||||
const assetOrders = await client.getOpenOrders({
|
||||
asset_id: "52114319501245...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OpenOrderParams
|
||||
|
||||
# All open orders
|
||||
orders = client.get_orders()
|
||||
|
||||
# Filtered by market
|
||||
market_orders = client.get_orders(
|
||||
OpenOrderParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::OrdersRequest;
|
||||
|
||||
// All open orders
|
||||
let orders = client.orders(&OrdersRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = OrdersRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_orders = client.orders(&request, None).await?;
|
||||
|
||||
// Filtered by asset
|
||||
let request = OrdersRequest::builder()
|
||||
.asset_id("52114319501245...".parse()?)
|
||||
.build();
|
||||
let asset_orders = client.orders(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### OpenOrder Object
|
||||
|
||||
Each order returned contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | --------- | ------------------------------------------------------------ |
|
||||
| `id` | string | Order ID |
|
||||
| `status` | string | Current order status |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `original_size` | string | Original order size at placement |
|
||||
| `size_matched` | string | Amount that has been filled |
|
||||
| `price` | string | Limit price |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `owner` | string | API key of the order owner |
|
||||
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
|
||||
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
|
||||
| `created_at` | string | Unix timestamp when the order was created |
|
||||
|
||||
***
|
||||
|
||||
## Trade History
|
||||
|
||||
When an order is matched, it creates a trade. Trades go through the following statuses:
|
||||
|
||||
| Status | Terminal? | Description |
|
||||
| ----------- | --------- | -------------------------------------------------------------------- |
|
||||
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
|
||||
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
|
||||
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
|
||||
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
|
||||
| `FAILED` | Yes | Trade failed permanently and is not being retried |
|
||||
|
||||
### Trade Object
|
||||
|
||||
Each trade contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | ------ | ------------------------------------------------------------ |
|
||||
| `id` | string | Trade ID |
|
||||
| `taker_order_id` | string | Taker order ID (hash) |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `size` | string | Trade size |
|
||||
| `fee_rate_bps` | string | Fee rate in basis points |
|
||||
| `price` | string | Trade price |
|
||||
| `status` | string | Trade status (see table above) |
|
||||
| `match_time` | string | Unix timestamp when the trade was matched |
|
||||
| `last_update` | string | Unix timestamp of last status update |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `owner` | string | API key ID of the trade owner |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
|
||||
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
|
||||
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
|
||||
|
||||
### MakerOrder Fields
|
||||
|
||||
Each entry in the `maker_orders` array contains:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ---------------- | ------ | ---------------------------- |
|
||||
| `order_id` | string | Maker order ID (hash) |
|
||||
| `owner` | string | Maker's API key ID |
|
||||
| `maker_address` | string | Maker's funder address |
|
||||
| `matched_amount` | string | Amount matched in this trade |
|
||||
| `price` | string | Maker order price |
|
||||
| `fee_rate_bps` | string | Maker fee rate in bps |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `outcome` | string | Outcome name |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
|
||||
Retrieve your trades with the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All trades
|
||||
const trades = await client.getTrades();
|
||||
|
||||
// Filtered by market
|
||||
const marketTrades = await client.getTrades({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// With pagination
|
||||
const paginatedTrades = await client.getTradesPaginated({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import TradeParams
|
||||
|
||||
# All trades
|
||||
trades = client.get_trades()
|
||||
|
||||
# Filtered by market
|
||||
market_trades = client.get_trades(
|
||||
TradeParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::TradesRequest;
|
||||
|
||||
// All trades
|
||||
let trades = client.trades(&TradesRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = TradesRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_trades = client.trades(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Heartbeat
|
||||
|
||||
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Send heartbeats in a loop
|
||||
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, auto-send in background:
|
||||
Client::start_heartbeats(&mut client)?;
|
||||
|
||||
// Or manually:
|
||||
let resp = client.post_heartbeat(None).await?; // None for first call
|
||||
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
|
||||
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
|
||||
|
||||
***
|
||||
|
||||
## Order Scoring
|
||||
|
||||
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Single order
|
||||
const scoring = await client.isOrderScoring({ orderId: "0x..." });
|
||||
console.log(scoring); // { scoring: true }
|
||||
|
||||
// Multiple orders
|
||||
const batchScoring = await client.areOrdersScoring({
|
||||
orderIds: ["0x...", "0x..."],
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
|
||||
|
||||
# Single order
|
||||
scoring = client.is_order_scoring(
|
||||
OrderScoringParams(orderId="0x...")
|
||||
)
|
||||
|
||||
# Multiple orders
|
||||
batch_scoring = client.are_orders_scoring(
|
||||
OrdersScoringParams(orderIds=["0x...", "0x..."])
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// Single order
|
||||
let scoring = client.is_order_scoring("0x...").await?;
|
||||
println!("Scoring: {}", scoring.scoring);
|
||||
|
||||
// Multiple orders
|
||||
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Onchain Order Info
|
||||
|
||||
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
|
||||
|
||||
| Field | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `orderHash` | Unique hash for the filled order |
|
||||
| `maker` | The user who generated the order and source of funds |
|
||||
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
|
||||
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving pUSD for outcome tokens) |
|
||||
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving pUSD for outcome tokens) |
|
||||
| `makerAmountFilled` | Amount of the asset given out |
|
||||
| `takerAmountFilled` | Amount of the asset received |
|
||||
| `fee` | Fees paid by the order maker |
|
||||
|
||||
***
|
||||
|
||||
## Error Messages
|
||||
|
||||
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
|
||||
|
||||
| Error | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------ |
|
||||
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
|
||||
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
|
||||
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
|
||||
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
|
||||
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
|
||||
| `INVALID_ORDER_ERROR` | System error while inserting order |
|
||||
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
|
||||
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
|
||||
| `EXECUTION_ERROR` | System error while executing trade |
|
||||
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
|
||||
| `DELAYING_ORDER_ERROR` | System error while delaying order |
|
||||
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
|
||||
| `MARKET_NOT_READY` | Market is not yet accepting orders |
|
||||
|
||||
### Insert Statuses
|
||||
|
||||
When an order is successfully placed, the response includes a `status` field:
|
||||
|
||||
| Status | Description |
|
||||
| ----------- | -------------------------------------------------------------------- |
|
||||
| `matched` | Order placed and matched with a resting order |
|
||||
| `live` | Order placed and resting on the book |
|
||||
| `delayed` | Order is marketable but subject to a matching delay |
|
||||
| `unmatched` | Order is marketable but failed to delay — placement still successful |
|
||||
|
||||
***
|
||||
|
||||
## Security
|
||||
|
||||
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
|
||||
|
||||
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades.
|
||||
|
||||
***
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Create Order" icon="plus" href="/trading/orders/create">
|
||||
Build, sign, and submit orders
|
||||
</Card>
|
||||
|
||||
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
|
||||
Cancel single, multiple, or all orders
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,544 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
# Overview
|
||||
|
||||
> Order types, tick sizes, and querying 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 underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client-v2) or [Python](https://github.com/Polymarket/py-clob-client-v2) SDK clients, which handle signing and submission for you.
|
||||
|
||||
<Info>
|
||||
If you prefer to use the REST API directly, you'll need to manage order
|
||||
signing yourself. See [Authentication](/api-reference/authentication) for details on
|
||||
constructing the required headers.
|
||||
</Info>
|
||||
|
||||
***
|
||||
|
||||
## Order Types
|
||||
|
||||
| Type | Behavior | Use Case |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
|
||||
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
|
||||
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
|
||||
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
|
||||
|
||||
* **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
|
||||
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
|
||||
|
||||
<Note>
|
||||
**GTD expiration**: There is a security threshold of one minute. If you need
|
||||
the order to expire in 90 seconds, the correct expiration value is `now + 1
|
||||
minute + 30 seconds`.
|
||||
</Note>
|
||||
|
||||
### Post-Only Orders
|
||||
|
||||
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
|
||||
|
||||
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
|
||||
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
|
||||
* Post-only can only be used with **GTC** and **GTD** order types.
|
||||
|
||||
***
|
||||
|
||||
## Tick Sizes
|
||||
|
||||
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
|
||||
|
||||
| Tick Size | Price 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 |
|
||||
|
||||
Retrieve the tick size for a market using the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const tickSize = await client.getTickSize(tokenID);
|
||||
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
tick_size = client.get_tick_size(token_id)
|
||||
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.tick_size(token_id).await?;
|
||||
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
You can also check the `minimum_tick_size` field on a market object returned
|
||||
by the [Markets API](/market-data/fetching-markets).
|
||||
</Tip>
|
||||
|
||||
***
|
||||
|
||||
## Negative Risk
|
||||
|
||||
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const response = await client.createAndPostOrder(
|
||||
{
|
||||
tokenID: "TOKEN_ID",
|
||||
price: 0.5,
|
||||
size: 10,
|
||||
side: Side.BUY,
|
||||
},
|
||||
{
|
||||
tickSize: "0.01",
|
||||
negRisk: true, // Required for multi-outcome markets
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderArgs, 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=True, # Required for multi-outcome markets
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
|
||||
// The order builder fetches neg_risk and uses the correct exchange contract.
|
||||
let order = client
|
||||
.limit_order()
|
||||
.token_id("TOKEN_ID".parse()?)
|
||||
.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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const isNegRisk = await client.getNegRisk(tokenID);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
is_neg_risk = client.get_neg_risk(token_id)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let is_neg_risk = client.neg_risk(token_id).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Allowances
|
||||
|
||||
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
|
||||
|
||||
* **Buying**: the funder must have set a **pUSD** allowance greater than or equal to the spending amount.
|
||||
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
|
||||
|
||||
This allows the Exchange contract to execute settlement according to your signed order instructions.
|
||||
|
||||
***
|
||||
|
||||
## Validity Checks
|
||||
|
||||
Orders are continually monitored to make sure they remain valid. This includes tracking:
|
||||
|
||||
* Underlying balances
|
||||
* Allowances
|
||||
|
||||
<Warning>
|
||||
Any maker caught intentionally abusing these checks will be blacklisted.
|
||||
</Warning>
|
||||
|
||||
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 pUSD in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
|
||||
|
||||
The max size you can place for an order is:
|
||||
|
||||
$$
|
||||
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
|
||||
$$
|
||||
|
||||
***
|
||||
|
||||
## Querying Orders
|
||||
|
||||
All query endpoints require [L2 authentication](/api-reference/authentication). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
|
||||
|
||||
### Get a Single Order
|
||||
|
||||
Retrieve details for a specific order by its ID:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const order = await client.getOrder("0xb816482a...");
|
||||
console.log(order);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
order = client.get_order("0xb816482a...")
|
||||
print(order)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let order = client.order("0xb816482a...").await?;
|
||||
println!("{order:?}");
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Get Open Orders
|
||||
|
||||
Retrieve your open orders, optionally filtered by market or asset:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All open orders
|
||||
const orders = await client.getOpenOrders();
|
||||
|
||||
// Filtered by market
|
||||
const marketOrders = await client.getOpenOrders({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// Filtered by asset
|
||||
const assetOrders = await client.getOpenOrders({
|
||||
asset_id: "52114319501245...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OpenOrderParams
|
||||
|
||||
# All open orders
|
||||
orders = client.get_orders()
|
||||
|
||||
# Filtered by market
|
||||
market_orders = client.get_orders(
|
||||
OpenOrderParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::OrdersRequest;
|
||||
|
||||
// All open orders
|
||||
let orders = client.orders(&OrdersRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = OrdersRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_orders = client.orders(&request, None).await?;
|
||||
|
||||
// Filtered by asset
|
||||
let request = OrdersRequest::builder()
|
||||
.asset_id("52114319501245...".parse()?)
|
||||
.build();
|
||||
let asset_orders = client.orders(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### OpenOrder Object
|
||||
|
||||
Each order returned contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | --------- | ------------------------------------------------------------ |
|
||||
| `id` | string | Order ID |
|
||||
| `status` | string | Current order status |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `original_size` | string | Original order size at placement |
|
||||
| `size_matched` | string | Amount that has been filled |
|
||||
| `price` | string | Limit price |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `owner` | string | API key of the order owner |
|
||||
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
|
||||
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
|
||||
| `created_at` | string | Unix timestamp when the order was created |
|
||||
|
||||
***
|
||||
|
||||
## Trade History
|
||||
|
||||
When an order is matched, it creates a trade. Trades go through the following statuses:
|
||||
|
||||
| Status | Terminal? | Description |
|
||||
| ----------- | --------- | -------------------------------------------------------------------- |
|
||||
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
|
||||
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
|
||||
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
|
||||
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
|
||||
| `FAILED` | Yes | Trade failed permanently and is not being retried |
|
||||
|
||||
### Trade Object
|
||||
|
||||
Each trade contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | ------ | ------------------------------------------------------------ |
|
||||
| `id` | string | Trade ID |
|
||||
| `taker_order_id` | string | Taker order ID (hash) |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `size` | string | Trade size |
|
||||
| `fee_rate_bps` | string | Fee rate in basis points |
|
||||
| `price` | string | Trade price |
|
||||
| `status` | string | Trade status (see table above) |
|
||||
| `match_time` | string | Unix timestamp when the trade was matched |
|
||||
| `last_update` | string | Unix timestamp of last status update |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `owner` | string | API key ID of the trade owner |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
|
||||
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
|
||||
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
|
||||
|
||||
### MakerOrder Fields
|
||||
|
||||
Each entry in the `maker_orders` array contains:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ---------------- | ------ | ---------------------------- |
|
||||
| `order_id` | string | Maker order ID (hash) |
|
||||
| `owner` | string | Maker's API key ID |
|
||||
| `maker_address` | string | Maker's funder address |
|
||||
| `matched_amount` | string | Amount matched in this trade |
|
||||
| `price` | string | Maker order price |
|
||||
| `fee_rate_bps` | string | Maker fee rate in bps |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `outcome` | string | Outcome name |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
|
||||
Retrieve your trades with the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All trades
|
||||
const trades = await client.getTrades();
|
||||
|
||||
// Filtered by market
|
||||
const marketTrades = await client.getTrades({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// With pagination
|
||||
const paginatedTrades = await client.getTradesPaginated({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import TradeParams
|
||||
|
||||
# All trades
|
||||
trades = client.get_trades()
|
||||
|
||||
# Filtered by market
|
||||
market_trades = client.get_trades(
|
||||
TradeParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::TradesRequest;
|
||||
|
||||
// All trades
|
||||
let trades = client.trades(&TradesRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = TradesRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_trades = client.trades(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Heartbeat
|
||||
|
||||
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Send heartbeats in a loop
|
||||
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, auto-send in background:
|
||||
Client::start_heartbeats(&mut client)?;
|
||||
|
||||
// Or manually:
|
||||
let resp = client.post_heartbeat(None).await?; // None for first call
|
||||
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
|
||||
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
|
||||
|
||||
***
|
||||
|
||||
## Order Scoring
|
||||
|
||||
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Single order
|
||||
const scoring = await client.isOrderScoring({ orderId: "0x..." });
|
||||
console.log(scoring); // { scoring: true }
|
||||
|
||||
// Multiple orders
|
||||
const batchScoring = await client.areOrdersScoring({
|
||||
orderIds: ["0x...", "0x..."],
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
|
||||
|
||||
# Single order
|
||||
scoring = client.is_order_scoring(
|
||||
OrderScoringParams(orderId="0x...")
|
||||
)
|
||||
|
||||
# Multiple orders
|
||||
batch_scoring = client.are_orders_scoring(
|
||||
OrdersScoringParams(orderIds=["0x...", "0x..."])
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// Single order
|
||||
let scoring = client.is_order_scoring("0x...").await?;
|
||||
println!("Scoring: {}", scoring.scoring);
|
||||
|
||||
// Multiple orders
|
||||
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Onchain Order Info
|
||||
|
||||
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
|
||||
|
||||
| Field | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `orderHash` | Unique hash for the filled order |
|
||||
| `maker` | The user who generated the order and source of funds |
|
||||
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
|
||||
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving pUSD for outcome tokens) |
|
||||
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving pUSD for outcome tokens) |
|
||||
| `makerAmountFilled` | Amount of the asset given out |
|
||||
| `takerAmountFilled` | Amount of the asset received |
|
||||
| `fee` | Fees paid by the order maker |
|
||||
|
||||
***
|
||||
|
||||
## Error Messages
|
||||
|
||||
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
|
||||
|
||||
| Error | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------ |
|
||||
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
|
||||
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
|
||||
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
|
||||
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
|
||||
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
|
||||
| `INVALID_ORDER_ERROR` | System error while inserting order |
|
||||
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
|
||||
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
|
||||
| `EXECUTION_ERROR` | System error while executing trade |
|
||||
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
|
||||
| `DELAYING_ORDER_ERROR` | System error while delaying order |
|
||||
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
|
||||
| `MARKET_NOT_READY` | Market is not yet accepting orders |
|
||||
|
||||
### Insert Statuses
|
||||
|
||||
When an order is successfully placed, the response includes a `status` field:
|
||||
|
||||
| Status | Description |
|
||||
| ----------- | -------------------------------------------------------------------- |
|
||||
| `matched` | Order placed and matched with a resting order |
|
||||
| `live` | Order placed and resting on the book |
|
||||
| `delayed` | Order is marketable but subject to a matching delay |
|
||||
| `unmatched` | Order is marketable but failed to delay — placement still successful |
|
||||
|
||||
***
|
||||
|
||||
## Security
|
||||
|
||||
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
|
||||
|
||||
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades.
|
||||
|
||||
***
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Create Order" icon="plus" href="/trading/orders/create">
|
||||
Build, sign, and submit orders
|
||||
</Card>
|
||||
|
||||
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
|
||||
Cancel single, multiple, or all orders
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,544 +0,0 @@
|
||||
> ## 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.
|
||||
|
||||
# Overview
|
||||
|
||||
> Order types, tick sizes, and querying 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 underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client-v2) or [Python](https://github.com/Polymarket/py-clob-client-v2) SDK clients, which handle signing and submission for you.
|
||||
|
||||
<Info>
|
||||
If you prefer to use the REST API directly, you'll need to manage order
|
||||
signing yourself. See [Authentication](/api-reference/authentication) for details on
|
||||
constructing the required headers.
|
||||
</Info>
|
||||
|
||||
***
|
||||
|
||||
## Order Types
|
||||
|
||||
| Type | Behavior | Use Case |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
|
||||
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
|
||||
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
|
||||
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
|
||||
|
||||
* **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
|
||||
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
|
||||
|
||||
<Note>
|
||||
**GTD expiration**: There is a security threshold of one minute. If you need
|
||||
the order to expire in 90 seconds, the correct expiration value is `now + 1
|
||||
minute + 30 seconds`.
|
||||
</Note>
|
||||
|
||||
### Post-Only Orders
|
||||
|
||||
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
|
||||
|
||||
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
|
||||
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
|
||||
* Post-only can only be used with **GTC** and **GTD** order types.
|
||||
|
||||
***
|
||||
|
||||
## Tick Sizes
|
||||
|
||||
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
|
||||
|
||||
| Tick Size | Price 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 |
|
||||
|
||||
Retrieve the tick size for a market using the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const tickSize = await client.getTickSize(tokenID);
|
||||
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
tick_size = client.get_tick_size(token_id)
|
||||
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let resp = client.tick_size(token_id).await?;
|
||||
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
You can also check the `minimum_tick_size` field on a market object returned
|
||||
by the [Markets API](/market-data/fetching-markets).
|
||||
</Tip>
|
||||
|
||||
***
|
||||
|
||||
## Negative Risk
|
||||
|
||||
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const response = await client.createAndPostOrder(
|
||||
{
|
||||
tokenID: "TOKEN_ID",
|
||||
price: 0.5,
|
||||
size: 10,
|
||||
side: Side.BUY,
|
||||
},
|
||||
{
|
||||
tickSize: "0.01",
|
||||
negRisk: true, // Required for multi-outcome markets
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderArgs, 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=True, # Required for multi-outcome markets
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
|
||||
// The order builder fetches neg_risk and uses the correct exchange contract.
|
||||
let order = client
|
||||
.limit_order()
|
||||
.token_id("TOKEN_ID".parse()?)
|
||||
.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?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const isNegRisk = await client.getNegRisk(tokenID);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
is_neg_risk = client.get_neg_risk(token_id)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let is_neg_risk = client.neg_risk(token_id).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Allowances
|
||||
|
||||
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
|
||||
|
||||
* **Buying**: the funder must have set a **pUSD** allowance greater than or equal to the spending amount.
|
||||
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
|
||||
|
||||
This allows the Exchange contract to execute settlement according to your signed order instructions.
|
||||
|
||||
***
|
||||
|
||||
## Validity Checks
|
||||
|
||||
Orders are continually monitored to make sure they remain valid. This includes tracking:
|
||||
|
||||
* Underlying balances
|
||||
* Allowances
|
||||
|
||||
<Warning>
|
||||
Any maker caught intentionally abusing these checks will be blacklisted.
|
||||
</Warning>
|
||||
|
||||
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 pUSD in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
|
||||
|
||||
The max size you can place for an order is:
|
||||
|
||||
$$
|
||||
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
|
||||
$$
|
||||
|
||||
***
|
||||
|
||||
## Querying Orders
|
||||
|
||||
All query endpoints require [L2 authentication](/api-reference/authentication). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
|
||||
|
||||
### Get a Single Order
|
||||
|
||||
Retrieve details for a specific order by its ID:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
const order = await client.getOrder("0xb816482a...");
|
||||
console.log(order);
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
order = client.get_order("0xb816482a...")
|
||||
print(order)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
let order = client.order("0xb816482a...").await?;
|
||||
println!("{order:?}");
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Get Open Orders
|
||||
|
||||
Retrieve your open orders, optionally filtered by market or asset:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All open orders
|
||||
const orders = await client.getOpenOrders();
|
||||
|
||||
// Filtered by market
|
||||
const marketOrders = await client.getOpenOrders({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// Filtered by asset
|
||||
const assetOrders = await client.getOpenOrders({
|
||||
asset_id: "52114319501245...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OpenOrderParams
|
||||
|
||||
# All open orders
|
||||
orders = client.get_orders()
|
||||
|
||||
# Filtered by market
|
||||
market_orders = client.get_orders(
|
||||
OpenOrderParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::OrdersRequest;
|
||||
|
||||
// All open orders
|
||||
let orders = client.orders(&OrdersRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = OrdersRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_orders = client.orders(&request, None).await?;
|
||||
|
||||
// Filtered by asset
|
||||
let request = OrdersRequest::builder()
|
||||
.asset_id("52114319501245...".parse()?)
|
||||
.build();
|
||||
let asset_orders = client.orders(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### OpenOrder Object
|
||||
|
||||
Each order returned contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | --------- | ------------------------------------------------------------ |
|
||||
| `id` | string | Order ID |
|
||||
| `status` | string | Current order status |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `original_size` | string | Original order size at placement |
|
||||
| `size_matched` | string | Amount that has been filled |
|
||||
| `price` | string | Limit price |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `owner` | string | API key of the order owner |
|
||||
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
|
||||
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
|
||||
| `created_at` | string | Unix timestamp when the order was created |
|
||||
|
||||
***
|
||||
|
||||
## Trade History
|
||||
|
||||
When an order is matched, it creates a trade. Trades go through the following statuses:
|
||||
|
||||
| Status | Terminal? | Description |
|
||||
| ----------- | --------- | -------------------------------------------------------------------- |
|
||||
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
|
||||
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
|
||||
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
|
||||
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
|
||||
| `FAILED` | Yes | Trade failed permanently and is not being retried |
|
||||
|
||||
### Trade Object
|
||||
|
||||
Each trade contains these fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------------ | ------ | ------------------------------------------------------------ |
|
||||
| `id` | string | Trade ID |
|
||||
| `taker_order_id` | string | Taker order ID (hash) |
|
||||
| `market` | string | Market ID (condition ID) |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
| `size` | string | Trade size |
|
||||
| `fee_rate_bps` | string | Fee rate in basis points |
|
||||
| `price` | string | Trade price |
|
||||
| `status` | string | Trade status (see table above) |
|
||||
| `match_time` | string | Unix timestamp when the trade was matched |
|
||||
| `last_update` | string | Unix timestamp of last status update |
|
||||
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
|
||||
| `owner` | string | API key ID of the trade owner |
|
||||
| `maker_address` | string | Funder address |
|
||||
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
|
||||
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
|
||||
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
|
||||
|
||||
### MakerOrder Fields
|
||||
|
||||
Each entry in the `maker_orders` array contains:
|
||||
|
||||
| Field | Type | Description |
|
||||
| ---------------- | ------ | ---------------------------- |
|
||||
| `order_id` | string | Maker order ID (hash) |
|
||||
| `owner` | string | Maker's API key ID |
|
||||
| `maker_address` | string | Maker's funder address |
|
||||
| `matched_amount` | string | Amount matched in this trade |
|
||||
| `price` | string | Maker order price |
|
||||
| `fee_rate_bps` | string | Maker fee rate in bps |
|
||||
| `asset_id` | string | Token ID |
|
||||
| `outcome` | string | Outcome name |
|
||||
| `side` | string | `BUY` or `SELL` |
|
||||
|
||||
Retrieve your trades with the SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// All trades
|
||||
const trades = await client.getTrades();
|
||||
|
||||
// Filtered by market
|
||||
const marketTrades = await client.getTrades({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
|
||||
// With pagination
|
||||
const paginatedTrades = await client.getTradesPaginated({
|
||||
market: "0xbd31dc8a...",
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import TradeParams
|
||||
|
||||
# All trades
|
||||
trades = client.get_trades()
|
||||
|
||||
# Filtered by market
|
||||
market_trades = client.get_trades(
|
||||
TradeParams(
|
||||
market="0xbd31dc8a...",
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
use polymarket_client_sdk_v2::clob::types::request::TradesRequest;
|
||||
|
||||
// All trades
|
||||
let trades = client.trades(&TradesRequest::default(), None).await?;
|
||||
|
||||
// Filtered by market
|
||||
let request = TradesRequest::builder()
|
||||
.market("0xbd31dc8a...".parse()?)
|
||||
.build();
|
||||
let market_trades = client.trades(&request, None).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Heartbeat
|
||||
|
||||
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Send heartbeats in a loop
|
||||
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, auto-send in background:
|
||||
Client::start_heartbeats(&mut client)?;
|
||||
|
||||
// Or manually:
|
||||
let resp = client.post_heartbeat(None).await?; // None for first call
|
||||
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
|
||||
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
|
||||
|
||||
***
|
||||
|
||||
## Order Scoring
|
||||
|
||||
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript TypeScript theme={null}
|
||||
// Single order
|
||||
const scoring = await client.isOrderScoring({ orderId: "0x..." });
|
||||
console.log(scoring); // { scoring: true }
|
||||
|
||||
// Multiple orders
|
||||
const batchScoring = await client.areOrdersScoring({
|
||||
orderIds: ["0x...", "0x..."],
|
||||
});
|
||||
```
|
||||
|
||||
```python Python theme={null}
|
||||
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
|
||||
|
||||
# Single order
|
||||
scoring = client.is_order_scoring(
|
||||
OrderScoringParams(orderId="0x...")
|
||||
)
|
||||
|
||||
# Multiple orders
|
||||
batch_scoring = client.are_orders_scoring(
|
||||
OrdersScoringParams(orderIds=["0x...", "0x..."])
|
||||
)
|
||||
```
|
||||
|
||||
```rust Rust theme={null}
|
||||
// Single order
|
||||
let scoring = client.is_order_scoring("0x...").await?;
|
||||
println!("Scoring: {}", scoring.scoring);
|
||||
|
||||
// Multiple orders
|
||||
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
***
|
||||
|
||||
## Onchain Order Info
|
||||
|
||||
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
|
||||
|
||||
| Field | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `orderHash` | Unique hash for the filled order |
|
||||
| `maker` | The user who generated the order and source of funds |
|
||||
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
|
||||
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving pUSD for outcome tokens) |
|
||||
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving pUSD for outcome tokens) |
|
||||
| `makerAmountFilled` | Amount of the asset given out |
|
||||
| `takerAmountFilled` | Amount of the asset received |
|
||||
| `fee` | Fees paid by the order maker |
|
||||
|
||||
***
|
||||
|
||||
## Error Messages
|
||||
|
||||
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
|
||||
|
||||
| Error | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------ |
|
||||
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
|
||||
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
|
||||
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
|
||||
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
|
||||
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
|
||||
| `INVALID_ORDER_ERROR` | System error while inserting order |
|
||||
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
|
||||
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
|
||||
| `EXECUTION_ERROR` | System error while executing trade |
|
||||
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
|
||||
| `DELAYING_ORDER_ERROR` | System error while delaying order |
|
||||
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
|
||||
| `MARKET_NOT_READY` | Market is not yet accepting orders |
|
||||
|
||||
### Insert Statuses
|
||||
|
||||
When an order is successfully placed, the response includes a `status` field:
|
||||
|
||||
| Status | Description |
|
||||
| ----------- | -------------------------------------------------------------------- |
|
||||
| `matched` | Order placed and matched with a resting order |
|
||||
| `live` | Order placed and resting on the book |
|
||||
| `delayed` | Order is marketable but subject to a matching delay |
|
||||
| `unmatched` | Order is marketable but failed to delay — placement still successful |
|
||||
|
||||
***
|
||||
|
||||
## Security
|
||||
|
||||
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
|
||||
|
||||
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades.
|
||||
|
||||
***
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Create Order" icon="plus" href="/trading/orders/create">
|
||||
Build, sign, and submit orders
|
||||
</Card>
|
||||
|
||||
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
|
||||
Cancel single, multiple, or all orders
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
Reference in New Issue
Block a user