Update Polymarket documentation (2026-02-19)

- Added new documentation URLs from llms.txt index
- Updated TARGET.md with 244 total documentation pages
- Scraped new pages for trading, concepts, and API reference sections
- Updated changelog and new index pages
This commit is contained in:
AI Agent
2026-02-19 14:31:02 +01:00
parent 81f77eff3c
commit b2a29fe51f
250 changed files with 33306 additions and 9659 deletions
+287 -131
View File
@@ -2,172 +2,328 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Cancel Orders(s)
# Cancel Order
> Multiple endpoints to cancel a single order, multiple orders, all orders or all orders from a single market.
> Cancel single, multiple, or all open orders
# Cancel an single Order
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).
<Tip> This endpoint requires a L2 Header. </Tip>
***
Cancel an order.
**HTTP REQUEST**
`DELETE /<clob-endpoint>/order`
### Request Payload Parameters
| Name | Required | Type | Description |
| ------- | -------- | ------ | --------------------- |
| orderID | yes | string | ID of order to cancel |
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
## Cancel a Single Order
<CodeGroup>
```python Python theme={null}
resp = client.cancel(order_id="0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88")
print(resp)
```typescript TypeScript theme={null}
const resp = await client.cancelOrder("0xb816482a...");
console.log(resp);
// { canceled: ["0xb816482a..."], not_canceled: {} }
```
```javascript Typescript theme={null}
async function main() {
// Send it to the server
const resp = await clobClient.cancelOrder({
orderID:
"0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88",
});
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
resp = client.cancel(order_id="0xb816482a...")
print(resp)
# {"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
***
<Tip> This endpoint requires a L2 Header. </Tip>
**HTTP REQUEST**
`DELETE /<clob-endpoint>/orders`
### Request Payload Parameters
| Name | Required | Type | Description |
| ---- | -------- | --------- | --------------------------- |
| null | yes | string\[] | IDs of the orders to cancel |
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
## Cancel Multiple Orders
<CodeGroup>
```python Python theme={null}
resp = client.cancel_orders(["0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88", "0xaaaa..."])
print(resp)
```typescript TypeScript theme={null}
const resp = await client.cancelOrders(["0xb816482a...", "0xc927593b..."]);
```
```javascript Typescript theme={null}
async function main() {
// Send it to the server
const resp = await clobClient.cancelOrders([
"0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88",
"0xaaaa...",
]);
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
resp = client.cancel_orders([
"0xb816482a...",
"0xc927593b...",
])
```
```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
***
<Tip> This endpoint requires a L2 Header. </Tip>
## Cancel All Orders
Cancel all open orders posted by a user.
**HTTP REQUEST**
`DELETE /<clob-endpoint>/cancel-all`
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
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()
print(resp)
print("Done!")
```
```javascript Typescript theme={null}
async function main() {
const resp = await clobClient.cancelAll();
console.log(resp);
console.log(`Done!`);
}
main();
```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 orders from market
***
<Tip> This endpoint requires a L2 Header. </Tip>
## Cancel by Market
Cancel orders from market.
**HTTP REQUEST**
`DELETE /<clob-endpoint>/cancel-market-orders`
### Request Payload Parameters
| Name | Required | Type | Description |
| --------- | -------- | ------ | -------------------------- |
| market | no | string | condition id of the market |
| asset\_id | no | string | id of the asset/token |
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
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>
```python Python theme={null}
resp = client.cancel_market_orders(market="0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af", asset_id="52114319501245915516055106046884209969926127482827954674443846427813813222426")
print(resp)
```typescript TypeScript theme={null}
const resp = await client.cancelMarketOrders({
market: "0xbd31dc8a...", // optional: condition ID
asset_id: "52114319501245...", // optional: specific token
});
```
```javascript Typescript theme={null}
async function main() {
// Send it to the server
const resp = await clobClient.cancelMarketOrders({
market:
"0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
asset_id:
"52114319501245915516055106046884209969926127482827954674443846427813813222426",
});
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
resp = client.cancel_market_orders(
market="0xbd31dc8a...",
asset_id="52114319501245...", # optional
)
```
```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>
***
## Onchain Cancellation
If the API is unavailable, you can cancel orders directly on the [Exchange contract](https://github.com/Polymarket/ctf-exchange/tree/main/src) by calling `cancelOrder(Order order)` onchain. Pass the full order struct that was signed when placing the order.
Use the `CTFExchange` or `NegRiskCTFExchange` contract depending on the market type. See [Contract Addresses](/resources/contract-addresses) for addresses.
This is a fallback mechanism — API cancellation is instant while onchain cancellation requires a transaction.
***
## 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"])
```
</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.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(market="0xbd31dc8a...")
)
```
</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.clob_types import TradeParams
trades = client.get_trades()
market_trades = client.get_trades(
TradeParams(market="0xbd31dc8a...")
)
```
</CodeGroup>
Additional filter parameters: `id`, `maker_address`, `asset_id`, `before`, `after`.
For large result sets, use the paginated variant:
<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..."))
```
</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.clob_types import OrderScoringParams, OrdersScoringParams
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
batch = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
```
</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>
+429 -62
View File
@@ -2,95 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Check Order Reward Scoring
# Overview
> Check if an order is eligble or scoring for Rewards purposes
> Order types, tick sizes, and querying orders
<Tip> This endpoint requires a L2 Header. </Tip>
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.
Returns a boolean value where it is indicated if an order is scoring or not.
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) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
**HTTP REQUEST**
<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>
`GET /<clob-endpoint>/order-scoring?order_id={...}`
***
### Request Parameters
## Order Types
| Name | Required | Type | Description |
| ------- | -------- | ------ | ------------------------------------ |
| orderId | yes | string | id of order to get information about |
| 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 |
### Response Format
* **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.
| Name | Type | Description |
| ---- | ------------- | ------------------ |
| null | OrdersScoring | order scoring data |
<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>
An `OrdersScoring` object is of the form:
### Post-Only Orders
| Name | Type | Description |
| ------- | ------- | ---------------------------------------- |
| scoring | boolean | indicates if the order is scoring or not |
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
# Check if some orders are scoring
* 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.
> This endpoint requires a L2 Header.
***
Returns to a dictionary with boolean value where it is indicated if an order is scoring or not.
## Tick Sizes
**HTTP REQUEST**
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.
`POST /<clob-endpoint>/orders-scoring`
| 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 |
### Request Parameters
Retrieve the tick size for a market using the SDK:
| Name | Required | Type | Description |
| -------- | -------- | --------- | ------------------------------------------ |
| orderIds | yes | string\[] | ids of the orders to get information about |
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize(tokenID);
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
### Response Format
| Name | Type | Description |
| ---- | ------------- | ------------------- |
| null | OrdersScoring | orders scoring data |
An `OrdersScoring` object is a dictionary that indicates the order by if it score.
<RequestExample>
```python Python theme={null}
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
</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}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</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)
```
</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 **USDC.e** 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
* Onchain order cancellations
<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 USDC.e 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).
### 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)
```
</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.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</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.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</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)
```
</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.clob_types import OrderScoringParams, OrdersScoringParams
# Single order
scoring = client.is_order_scoring(
OrderScoringParams(
orderId="0x..."
)
OrderScoringParams(orderId="0x...")
)
print(scoring)
scoring = client.are_orders_scoring(
OrdersScoringParams(
orderIds=["0x..."]
)
# Multiple orders
batch_scoring = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
print(scoring)
```
</CodeGroup>
```javascript Typescript theme={null}
async function main() {
const scoring = await clobClient.isOrderScoring({
orderId: "0x...",
});
console.log(scoring);
}
***
main();
## Onchain Order Info
async function main() {
const scoring = await clobClient.areOrdersScoring({
orderIds: ["0x..."],
});
console.log(scoring);
}
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
main();
| 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 USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e for outcome tokens) |
| `makerAmountFilled` | Amount of the asset given out |
| `takerAmountFilled` | Amount of the asset received |
| `fee` | Fees paid by the order maker |
```
</RequestExample>
***
## 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. Users can cancel orders onchain independently if trust issues arise.
***
## 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>
+488 -189
View File
@@ -2,233 +2,532 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Place Multiple Orders (Batching)
# Create Order
> Instructions for placing multiple orders(Batch)
> Build, sign, and submit orders
<Tip> This endpoint requires a L2 Header </Tip>
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.
Polymarkets CLOB supports batch orders, allowing you to place up to `15` orders in a single request. Before using this feature, make sure you're comfortable placing a single order first. You can find the documentation for that [here.](/developers/CLOB/orders/create-order)
<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>
**HTTP REQUEST**
***
`POST /<clob-endpoint>/orders`
## Order Types
### Request Payload Parameters
| 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 |
| Name | Required | Type | Description |
| --------- | -------- | ------------- | ---------------------------------------------------------------- |
| PostOrder | yes | PostOrders\[] | list of signed order objects (Signed Order + Order Type + Owner) |
* **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
A `PostOrder` object is the form:
***
| Name | Required | Type | Description |
| --------- | -------- | ------- | -------------------------------------------------------------------------------------------- |
| order | yes | order | See below table for details on crafting this object |
| orderType | yes | string | order type ("FOK", "GTC", "GTD", "FAK") |
| owner | yes | string | api key of order owner |
| postOnly | no | boolean | if `true`, the order will only rest on the book and not match immediately (default: `false`) |
## Limit Orders
An `order` object is the form:
The simplest way to place a limit order — create, sign, and submit in one call:
| Name | Required | Type | Description |
| ------------- | -------- | ------- | -------------------------------------------------- |
| salt | yes | integer | random salt used to create unique order |
| maker | yes | string | maker address (funder) |
| signer | yes | string | signing address |
| taker | yes | string | taker address (operator) |
| tokenId | yes | string | ERC1155 token ID of conditional token being traded |
| makerAmount | yes | string | maximum amount maker is willing to spend |
| takerAmount | yes | string | minimum amount taker will pay the maker in return |
| expiration | yes | string | unix expiration timestamp |
| nonce | yes | string | maker's exchange nonce of the order is associated |
| feeRateBps | yes | string | fee rate basis points as required by the operator |
| side | yes | string | buy or sell enum index |
| signatureType | yes | integer | signature type enum index |
| signature | yes | string | hex encoded signature |
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
### Order types
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false,
},
OrderType.GTC,
);
* **FOK**: A Fill-Or-Kill order is an market order to buy (in dollars) or sell (in shares) shares that must be executed immediately in its entirety; otherwise, the entire order will be cancelled.
* **FAK**: A Fill-And-Kill order is a market order to buy (in dollars) or sell (in shares) that will be executed immediately for as many shares as are available; any portion not filled at once is cancelled.
* **GTC**: A Good-Til-Cancelled order is a limit order that is active until it is fulfilled or cancelled.
* **GTD**: A Good-Til-Date order is a type of order that is active until its specified date (UTC seconds timestamp), unless it has already been fulfilled or cancelled. There is a security threshold of one minute. If the order needs to expire in 90 seconds the correct expiration value is: now + 1 minute + 30 seconds
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
### Response Format
| Name | Type | Description |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | boolean indicating if server-side err (`success = false`) -> server-side error |
| errorMsg | string | error message in case of unsuccessful placement (in case `success = false`, e.g. `client-side error`, the reason is in `errorMsg`) |
| orderId | string | id of order |
| orderHashes | string\[] | hash of settlement transaction order was marketable and triggered a match |
### Insert Error Messages
If the `errorMsg` field of the response object from placement is not an empty string, the order was not able to be immediately placed. This might be because of a delay or because of a failure. If the `success` is not `true`, then there was an issue placing the order. The following `errorMessages` are possible:
#### Error
| Error | Success | Message | Description |
| ------------------------------------ | ------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| INVALID\_ORDER\_MIN\_TICK\_SIZE | yes | order is invalid. Price breaks minimum tick size rules | order price isn't accurate to correct tick sizing |
| INVALID\_ORDER\_MIN\_SIZE | yes | order is invalid. Size lower than the minimum | order size must meet min size threshold requirement |
| INVALID\_ORDER\_DUPLICATED | yes | order is invalid. Duplicated. Same order has already been placed, can't be placed again | |
| INVALID\_ORDER\_NOT\_ENOUGH\_BALANCE | yes | not enough balance / allowance | funder address doesn't have sufficient balance or allowance for order |
| INVALID\_ORDER\_EXPIRATION | yes | invalid expiration | expiration field expresses a time before now |
| INVALID\_ORDER\_ERROR | yes | could not insert order | system error while inserting order |
| INVALID\_POST\_ONLY\_ORDER\_TYPE | yes | invalid post-only order: only GTC and GTD order types are allowed | post only flag attached to a market order |
| INVALID\_POST\_ONLY\_ORDER | yes | invalid post-only order: order crosses book | post only order would match |
| EXECUTION\_ERROR | yes | could not run the execution | system error while attempting to execute trade |
| ORDER\_DELAYED | no | order match delayed due to market conditions | order placement delayed |
| DELAYING\_ORDER\_ERROR | yes | error delaying the order | system error while delaying order |
| FOK\_ORDER\_NOT\_FILLED\_ERROR | yes | order couldn't be fully filled, FOK orders are fully filled/killed | FOK order not fully filled so can't be placed |
| MARKET\_NOT\_READY | no | the market is not yet ready to process new orders | system not accepting orders for market yet |
### Insert Statuses
When placing an order, a status field is included. The status field provides additional information regarding the order's state as a result of the placement. Possible values include:
#### Status
| Status | Description |
| --------- | ------------------------------------------------------------ |
| matched | order placed and matched with an existing resting order |
| live | order placed and resting on the book |
| delayed | order marketable, but subject to matching delay |
| unmatched | order marketable, but failure delaying, placement successful |
<RequestExample>
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType, PostOrdersArgs
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTC
)
host: str = "https://clob.polymarket.com"
key: str = "" ##This is your Private Key. Export from https://reveal.magic.link/polymarket or from your Web3 Application
chain_id: int = 137 #No need to adjust this
POLYMARKET_PROXY_ADDRESS: str = '' #This is the address listed below your profile picture when using the Polymarket site.
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
</CodeGroup>
#Select from the following 3 initialization options to matches your login method, and remove any unused lines so only one client is initialized.
### Two-Step: Sign Then Submit
For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic:
### Initialization of a client using a Polymarket Proxy associated with an Email/Magic account. If you login with your email use this example.
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=1, funder=POLYMARKET_PROXY_ADDRESS)
<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 },
);
### Initialization of a client using a Polymarket Proxy associated with a Browser Wallet(Metamask, Coinbase Wallet, etc)
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=2, funder=POLYMARKET_PROXY_ADDRESS)
// Step 2: Submit to the CLOB
const response = await client.postOrder(signedOrder, OrderType.GTC);
```
### Initialization of a client that trades directly from an EOA.
client = ClobClient(host, key=key, chain_id=chain_id)
```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={
"tick_size": "0.01",
"neg_risk": False,
}
)
## Create and sign a limit order buying 100 YES tokens for 0.50c each
#Refer to the Markets API documentation to locate a tokenID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets
# Step 2: Submit to the CLOB
response = client.post_order(signed_order, OrderType.GTC)
```
</CodeGroup>
client.set_api_creds(client.create_or_derive_api_creds())
***
resp = client.post_orders([
## GTD Orders (Expiring)
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={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTD
)
```
</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";
// 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.order_builder.constants import BUY, SELL
from py_clob_client.clob_types import OrderType
# FOK BUY: spend exactly $100 or cancel entirely
buy_order = client.create_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100, # dollar amount
price=0.50, # worst-price limit (slippage protection)
options={"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(
token_id="TOKEN_ID",
side=SELL,
amount=200, # number of shares
price=0.45, # worst-price limit (slippage protection)
options={"tick_size": "0.01", "neg_risk": False},
)
client.post_order(sell_order, OrderType.FOK)
```
</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}
response = client.create_and_post_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100,
price=0.50,
options={"tick_size": "0.01", "neg_risk": False},
order_type=OrderType.FOK,
)
```
</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)
```
</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";
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.clob_types import OrderArgs, OrderType, PostOrdersArgs
from py_clob_client.order_builder.constants import BUY, SELL
response = client.post_orders([
PostOrdersArgs(
# Create and sign a limit order buying 100 YES tokens for 0.50 each
order=client.create_order(OrderArgs(
price=0.01,
size=5,
price=0.48,
size=500,
side=BUY,
token_id="88613172803544318200496156596909968959424174365708473463931555296257475886634",
)),
orderType=OrderType.GTC, # Good 'Til Cancelled
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
PostOrdersArgs(
# Create and sign a limit order selling 200 NO tokens for 0.25 each
order=client.create_order(OrderArgs(
price=0.01,
size=5,
side=BUY,
token_id="93025177978745967226369398316375153283719303181694312089956059680730874301533",
)),
orderType=OrderType.GTC, # Good 'Til Cancelled
)
price=0.52,
size=500,
side=SELL,
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
])
print(resp)
print("Done!")
```
</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), 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");
```
```javascript typescript theme={null}
import { ethers } from "ethers";
import { config as dotenvConfig } from "dotenv";
import { resolve } from "path";
import { ApiKeyCreds, Chain, ClobClient, OrderType, PostOrdersArgs, Side } from "../src";
```python Python theme={null}
tick_size = client.get_tick_size("TOKEN_ID")
```
</CodeGroup>
dotenvConfig({ path: resolve(__dirname, "../.env") });
### Negative Risk
async function main() {
const wallet = new ethers.Wallet(`${process.env.PK}`);
const chainId = parseInt(`${process.env.CHAIN_ID || Chain.AMOY}`) as Chain;
console.log(`Address: ${await wallet.getAddress()}, chainId: ${chainId}`);
Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets.
const host = process.env.CLOB_API_URL || "https://clob.polymarket.com";
const creds: ApiKeyCreds = {
key: `${process.env.CLOB_API_KEY}`,
secret: `${process.env.CLOB_SECRET}`,
passphrase: `${process.env.CLOB_PASS_PHRASE}`,
};
const clobClient = new ClobClient(host, chainId, wallet, creds);
await clobClient.cancelAll();
const YES = "71321045679252212594626385532706912750332728571942532289631379312455583992563";
const orders: PostOrdersArgs[] = [
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.4,
side: Side.BUY,
size: 100,
}),
orderType: OrderType.GTC,
},
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.45,
side: Side.BUY,
size: 100,
}),
orderType: OrderType.GTC,
},
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.55,
side: Side.SELL,
size: 100,
}),
orderType: OrderType.GTC,
},
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.6,
side: Side.SELL,
size: 100,
}),
orderType: OrderType.GTC,
},
];
// Send it to the server
const resp = await clobClient.postOrders(orders);
console.log(resp);
}
main();
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk("TOKEN_ID");
```
```REQUEST Example Payload theme={null}
[
{'order': {'salt': 660377097, 'maker': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'signer': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'taker': '0x0000000000000000000000000000000000000000', 'tokenId': '88613172803544318200496156596909968959424174365708473463931555296257475886634', 'makerAmount': '50000', 'takerAmount': '5000000', 'expiration': '0', 'nonce': '0', 'feeRateBps': '0', 'side': 'BUY', 'signatureType': 0, 'signature': '0xccb8d1298d698ebc0859e6a26044c848ac4a4b0e20a391a4574e42b9c9bf237e5fa09fc00743e3e2d2f8e909a21d60f276ce083cc35c6661410b892f5bcbe2291c'}, 'owner': 'PRIVATEKEY', 'orderType': 'GTC'},
{'order': {'salt': 1207111323, 'maker': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'signer': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'taker': '0x0000000000000000000000000000000000000000', 'tokenId': '93025177978745967226369398316375153283719303181694312089956059680730874301533', 'makerAmount': '50000', 'takerAmount': '5000000', 'expiration': '0', 'nonce': '0', 'feeRateBps': '0', 'side': 'BUY', 'signatureType': 0, 'signature': '0x0feca28666283824c27d7bead0bc441dde6df20dd71ef5ff7c84d3d1d5bf8aa4296fa382769dc11a92abe05b6f731d6c32556e9b4fb29e6eb50131af23a9ac941c'}, 'owner': 'PRIVATEKEY', 'orderType': 'GTC'}
]
```python Python theme={null}
is_neg_risk = client.get_neg_risk("TOKEN_ID")
```
</RequestExample>
</CodeGroup>
<Tip>
Both values are also available on the market object: `minimum_tick_size` and
`neg_risk`.
</Tip>
***
## Prerequisites
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **BUY orders**: USDC.e 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, allowances, and
onchain cancellations are tracked in real time. Any maker caught intentionally
abusing these checks will be blacklisted.
</Warning>
### Advanced Parameters
These optional fields can be passed in the `UserOrder` object for fine-grained control:
| Parameter | Type | Description |
| ------------ | ------ | ----------------------------------------------- |
| `feeRateBps` | number | Fee rate in basis points (default: market rate) |
| `nonce` | number | Custom nonce for order uniqueness |
| `taker` | string | Restrict the order to a specific taker address |
### 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 **3-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)
```
</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>
+495 -226
View File
@@ -2,263 +2,532 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Place Single Order
# Create Order
> Detailed instructions for creating, placing, and managing orders using Polymarket's CLOB API.
> Build, sign, and submit orders
# Create and Place an Order
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.
<Tip> This endpoint requires a L2 Header </Tip>
<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>
Create and place an order using the Polymarket CLOB API clients. All orders are represented as "limit" orders, but "market" orders are also supported. To place a market order, simply ensure your price is marketable against current resting limit orders, which are executed on input at the best price.
***
**HTTP REQUEST**
## Order Types
`POST /<clob-endpoint>/order`
| 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 |
### Request Payload Parameters
* **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
| Name | Required | Type | Description |
| --------- | -------- | ------- | -------------------------------------------------------------------------------------------- |
| order | yes | Order | signed object |
| owner | yes | string | api key of order owner |
| orderType | yes | string | order type ("FOK", "GTC", "GTD") |
| postOnly | no | boolean | if `true`, the order will only rest on the book and not match immediately (default: `false`) |
***
### Post-only orders
## Limit Orders
* postOnly submits a limit order that will not match resting liquidity upon entry.
* If a postOnly order would cross the spread (i.e., it is marketable), it will be rejected rather than executed.
* postOnly cannot be combined with market order types (e.g., FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
The simplest way to place a limit order — create, sign, and submit in one call:
An `order` object is the form:
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
| Name | Required | Type | Description |
| ------------- | -------- | ------- | -------------------------------------------------- |
| salt | yes | integer | random salt used to create unique order |
| maker | yes | string | maker address (funder) |
| signer | yes | string | signing address |
| taker | yes | string | taker address (operator) |
| tokenId | yes | string | ERC1155 token ID of conditional token being traded |
| makerAmount | yes | string | maximum amount maker is willing to spend |
| takerAmount | yes | string | minimum amount taker will pay the maker in return |
| expiration | yes | string | unix expiration timestamp |
| nonce | yes | string | maker's exchange nonce of the order is associated |
| feeRateBps | yes | string | fee rate basis points as required by the operator |
| side | yes | string | buy or sell enum index |
| signatureType | yes | integer | signature type enum index |
| signature | yes | string | hex encoded signature |
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false,
},
OrderType.GTC,
);
### Order types
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
* **FOK**: A Fill-Or-Kill order is an market order to buy (in dollars) or sell (in shares) shares that must be executed immediately in its entirety; otherwise, the entire order will be cancelled.
* **FAK**: A Fill-And-Kill order is a market order to buy (in dollars) or sell (in shares) that will be executed immediately for as many shares as are available; any portion not filled at once is cancelled.
* **GTC**: A Good-Til-Cancelled order is a limit order that is active until it is fulfilled or cancelled.
* **GTD**: A Good-Til-Date order is a type of order that is active until its specified date (UTC seconds timestamp), unless it has already been fulfilled or cancelled. There is a security threshold of one minute. If the order needs to expire in 90 seconds the correct expiration value is: now + 1 minute + 30 seconds
### Response Format
| Name | Type | Description |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | boolean indicating if server-side err (`success = false`) -> server-side error |
| errorMsg | string | error message in case of unsuccessful placement (in case `success = false`, e.g. `client-side error`, the reason is in `errorMsg`) |
| orderId | string | id of order |
| orderHashes | string\[] | hash of settlement transaction order was marketable and triggered a match |
### Insert Error Messages
If the `errorMsg` field of the response object from placement is not an empty string, the order was not able to be immediately placed. This might be because of a delay or because of a failure. If the `success` is not `true`, then there was an issue placing the order. The following `errorMessages` are possible:
#### Error
| Error | Success | Message | Description |
| ------------------------------------ | ------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| INVALID\_ORDER\_MIN\_TICK\_SIZE | yes | order is invalid. Price breaks minimum tick size rules | order price isn't accurate to correct tick sizing |
| INVALID\_ORDER\_MIN\_SIZE | yes | order is invalid. Size lower than the minimum | order size must meet min size threshold requirement |
| INVALID\_ORDER\_DUPLICATED | yes | order is invalid. Duplicated. Same order has already been placed, can't be placed again | |
| INVALID\_ORDER\_NOT\_ENOUGH\_BALANCE | yes | not enough balance / allowance | funder address doesn't have sufficient balance or allowance for order |
| INVALID\_ORDER\_EXPIRATION | yes | invalid expiration | expiration field expresses a time before now |
| INVALID\_ORDER\_ERROR | yes | could not insert order | system error while inserting order |
| INVALID\_POST\_ONLY\_ORDER\_TYPE | yes | invalid post-only order: only GTC and GTD order types are allowed | post only flag attached to a market order |
| INVALID\_POST\_ONLY\_ORDER | yes | invalid post-only order: order crosses book | post only order would match |
| EXECUTION\_ERROR | yes | could not run the execution | system error while attempting to execute trade |
| ORDER\_DELAYED | no | order match delayed due to market conditions | order placement delayed |
| DELAYING\_ORDER\_ERROR | yes | error delaying the order | system error while delaying order |
| FOK\_ORDER\_NOT\_FILLED\_ERROR | yes | order couldn't be fully filled, FOK orders are fully filled/killed | FOK order not fully filled so can't be placed |
| MARKET\_NOT\_READY | no | the market is not yet ready to process new orders | system not accepting orders for market yet |
### Insert Statuses
When placing an order, a status field is included. The status field provides additional information regarding the order's state as a result of the placement. Possible values include:
#### Status
| Status | Description |
| --------- | ------------------------------------------------------------ |
| matched | order placed and matched with an existing resting order |
| live | order placed and resting on the book |
| delayed | order marketable, but subject to matching delay |
| unmatched | order marketable, but failure delaying, placement successful |
<RequestExample>
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY
host: str = "https://clob.polymarket.com"
key: str = "" #This is your Private Key. Export from reveal.polymarket.com or from your Web3 Application
chain_id: int = 137 #No need to adjust this
POLYMARKET_PROXY_ADDRESS: str = '' #This is the address you deposit/send USDC to to FUND your Polymarket account.
#Select from the following 3 initialization options to matches your login method, and remove any unused lines so only one client is initialized.
### Initialization of a client using a Polymarket Proxy associated with an Email/Magic account. If you login with your email use this example.
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=1, funder=POLYMARKET_PROXY_ADDRESS)
### Initialization of a client using a Polymarket Proxy associated with a Browser Wallet(Metamask, Coinbase Wallet, etc)
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=2, funder=POLYMARKET_PROXY_ADDRESS)
### Initialization of a client that trades directly from an EOA.
client = ClobClient(host, key=key, chain_id=chain_id)
## Create and sign a limit order buying 100 YES tokens for 0.50c each
#Refer to the Markets API documentation to locate a tokenID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets
client.set_api_creds(client.create_or_derive_api_creds())
order_args = OrderArgs(
price=0.01,
size=5.0,
side=BUY,
token_id="", #Token ID you want to purchase goes here.
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTC
)
signed_order = client.create_order(order_args)
## GTC(Good-Till-Cancelled) Order
resp = client.post_order(signed_order, OrderType.GTC)
print(resp)
print("Order ID:", response["orderID"])
print("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);
```
```javascript typescript theme={null}
// GTC Order example
//
import { Side, OrderType } from "@polymarket/clob-client";
```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={
"tick_size": "0.01",
"neg_risk": False,
}
)
async function main() {
// Create a buy order for 100 YES for 0.50c
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
const order = await clobClient.createOrder({
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
# Step 2: Submit to the CLOB
response = client.post_order(signed_order, OrderType.GTC)
```
</CodeGroup>
***
## GTD Orders (Expiring)
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,
size: 100,
feeRateBps: 0,
nonce: 1,
});
console.log("Created Order", order);
expiration,
},
{ tickSize: "0.01", negRisk: false },
OrderType.GTD,
);
```
// Send it to the server
```python Python theme={null}
import time
// GTC Order
const resp = await clobClient.postOrder(order, OrderType.GTC);
console.log(resp);
}
# Expire in 1 hour (+ 60s security threshold buffer)
expiration = int(time.time()) + 60 + 3600
main();
// GTD Order example
//
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
expiration=expiration,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTD
)
```
</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";
async function main() {
// Create a buy order for 100 YES for 0.50c that expires in 1 minute
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
// There is a 1 minute of security threshold for the expiration field.
// If we need the order to expire in 30 seconds the correct expiration value is:
// now + 1 miute + 30 seconds
const oneMinute = 60 * 1000;
const seconds = 30 * 1000;
const expiration = parseInt(
((new Date().getTime() + oneMinute + seconds) / 1000).toString()
);
const order = await clobClient.createOrder({
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
price: 0.5,
// FOK BUY: spend exactly $100 or cancel entirely
const buyOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
size: 100,
feeRateBps: 0,
nonce: 1,
// There is a 1 minute of security threshold for the expiration field.
// If we need the order to expire in 30 seconds the correct expiration value is:
// now + 1 miute + 30 seconds
expiration: expiration,
});
console.log("Created Order", order);
amount: 100, // dollar amount
price: 0.5, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(buyOrder, OrderType.FOK);
// Send it to the server
// GTD Order
const resp = await clobClient.postOrder(order, OrderType.GTD);
console.log(resp);
}
main();
// FOK BUY Order example
//
import { Side, OrderType } from "@polymarket/clob-client";
async function main() {
// Create a market buy order for $100
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
const marketOrder = await clobClient.createMarketOrder({
side: Side.BUY,
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
amount: 100, // $$$
feeRateBps: 0,
nonce: 0,
price: 0.5,
});
console.log("Created Order", order);
// Send it to the server
// FOK Order
const resp = await clobClient.postOrder(order, OrderType.FOK);
console.log(resp);
}
main();
// FOK SELL Order example
//
import { Side, OrderType } from "@polymarket/clob-client";
async function main() {
// Create a market sell order for 100 shares
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
const marketOrder = await clobClient.createMarketOrder({
// FOK SELL: sell exactly 200 shares or cancel entirely
const sellOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.SELL,
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
amount: 100, // shares
feeRateBps: 0,
nonce: 0,
price: 0.5,
});
console.log("Created Order", order);
// Send it to the server
// FOK Order
const resp = await clobClient.postOrder(order, OrderType.FOK);
console.log(resp);
}
main();
amount: 200, // number of shares
price: 0.45, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(sellOrder, OrderType.FOK);
```
</RequestExample>
```python Python theme={null}
from py_clob_client.order_builder.constants import BUY, SELL
from py_clob_client.clob_types import OrderType
# FOK BUY: spend exactly $100 or cancel entirely
buy_order = client.create_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100, # dollar amount
price=0.50, # worst-price limit (slippage protection)
options={"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(
token_id="TOKEN_ID",
side=SELL,
amount=200, # number of shares
price=0.45, # worst-price limit (slippage protection)
options={"tick_size": "0.01", "neg_risk": False},
)
client.post_order(sell_order, OrderType.FOK)
```
</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}
response = client.create_and_post_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100,
price=0.50,
options={"tick_size": "0.01", "neg_risk": False},
order_type=OrderType.FOK,
)
```
</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)
```
</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";
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.clob_types import OrderArgs, OrderType, PostOrdersArgs
from py_clob_client.order_builder.constants import BUY, SELL
response = client.post_orders([
PostOrdersArgs(
order=client.create_order(OrderArgs(
price=0.48,
size=500,
side=BUY,
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
PostOrdersArgs(
order=client.create_order(OrderArgs(
price=0.52,
size=500,
side=SELL,
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
])
```
</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), 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")
```
</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")
```
</CodeGroup>
<Tip>
Both values are also available on the market object: `minimum_tick_size` and
`neg_risk`.
</Tip>
***
## Prerequisites
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **BUY orders**: USDC.e 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, allowances, and
onchain cancellations are tracked in real time. Any maker caught intentionally
abusing these checks will be blacklisted.
</Warning>
### Advanced Parameters
These optional fields can be passed in the `UserOrder` object for fine-grained control:
| Parameter | Type | Description |
| ------------ | ------ | ----------------------------------------------- |
| `feeRateBps` | number | Fee rate in basis points (default: market rate) |
| `nonce` | number | Custom nonce for order uniqueness |
| `taker` | string | Restrict the order to a specific taker address |
### 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 **3-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)
```
</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>
+441 -31
View File
@@ -2,52 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Get Active Orders
# Overview
<Tip> This endpoint requires a L2 Header. </Tip>
> Order types, tick sizes, and querying orders
Get active order(s) for a specific market.
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.
**HTTP REQUEST**
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) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
`GET /<clob-endpoint>/data/orders`
<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>
### Request Parameters
***
| Name | Required | Type | Description |
| --------- | -------- | ------ | ------------------------------------ |
| id | no | string | id of order to get information about |
| market | no | string | condition id of market |
| asset\_id | no | string | id of the asset/token |
## Order Types
### Response Format
| 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 |
| Name | Type | Description |
| ---- | ------------ | ---------------------------------------------------- |
| null | OpenOrder\[] | list of open orders filtered by the query parameters |
* **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"
```
</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}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</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)
```
</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 **USDC.e** 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
* Onchain order cancellations
<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 USDC.e 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).
### 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)
```
</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...",
});
```
<RequestExample>
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
resp = client.get_orders(
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
market="0xbd31dc8a...",
)
)
print(resp)
print("Done!")
```
</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...",
});
```
```javascript Typescript theme={null}
async function main() {
const resp = await clobClient.getOpenOrders({
market:
"0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
});
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</RequestExample>
</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)
```
</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.clob_types 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..."])
)
```
</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 USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e 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. Users can cancel orders onchain independently if trust issues arise.
***
## 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>
+440 -43
View File
@@ -2,65 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Get Order
# Overview
> Get information about an existing order
> Order types, tick sizes, and querying orders
<Tip>This endpoint requires a L2 Header. </Tip>
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.
Get single order by id.
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) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
**HTTP REQUEST**
<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>
`GET /<clob-endpoint>/data/order/<order_hash>`
***
### Request Parameters
## Order Types
| Name | Required | Type | Description |
| ---- | -------- | ------ | ------------------------------------ |
| id | no | string | id of order to get information about |
| 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 |
### Response Format
* **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.
| Name | Type | Description |
| ----- | --------- | ------------------ |
| order | OpenOrder | order if it exists |
<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>
An `OpenOrder` object is of the form:
### Post-Only Orders
| Name | Type | Description |
| ----------------- | --------- | -------------------------------------------------------------- |
| associate\_trades | string\[] | any Trade id the order has been partially included in |
| id | string | order id |
| status | string | order current status |
| market | string | market id (condition id) |
| original\_size | string | original order size at placement |
| outcome | string | human readable outcome the order is for |
| maker\_address | string | maker address (funder) |
| owner | string | api key |
| price | string | price |
| side | string | buy or sell |
| size\_matched | string | size of order that has been matched/filled |
| asset\_id | string | token id |
| expiration | string | unix timestamp when the order expired, 0 if it does not expire |
| type | string | order type (GTC, FOK, GTD) |
| created\_at | string | unix timestamp when the order was created |
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"
```
<RequestExample>
```python Python theme={null}
order = clob_client.get_order("0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc")
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
</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}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</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)
```
</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 **USDC.e** 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
* Onchain order cancellations
<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 USDC.e 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).
### 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)
```
</CodeGroup>
```javascript Typescript theme={null}
async function main() {
const order = await clobClient.getOrder(
"0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc"
);
console.log(order);
}
### Get Open Orders
main();
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...",
});
```
</RequestExample>
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</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.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</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)
```
</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.clob_types 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..."])
)
```
</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 USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e 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. Users can cancel orders onchain independently if trust issues arise.
***
## 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>
+456 -11
View File
@@ -2,17 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Onchain Order Info
# Overview
## How do I interpret the OrderFilled onchain event?
> Order types, tick sizes, and querying orders
Given an OrderFilled event:
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.
* `orderHash`: a unique hash for the Order being filled
* `maker`: the user generating the order and the source of funds for the order
* `taker`: the user filling the order OR the Exchange contract if the order fills multiple limit orders
* `makerAssetId`: id of the asset that is given out. If 0, indicates that the Order is a BUY, giving USDC in exchange for Outcome tokens. Else, indicates that the Order is a SELL, giving Outcome tokens in exchange for USDC.
* `takerAssetId`: id of the asset that is received. If 0, indicates that the Order is a SELL, receiving USDC in exchange for Outcome tokens. Else, indicates that the Order is a BUY, receiving Outcome tokens in exchange for USDC.
* `makerAmountFilled`: the amount of the asset that is given out.
* `takerAmountFilled`: the amount of the asset that is received.
* `fee`: the fees paid by the order maker
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) or [Python](https://github.com/Polymarket/py-clob-client) 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"
```
</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}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</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)
```
</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 **USDC.e** 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
* Onchain order cancellations
<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 USDC.e 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).
### 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)
```
</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.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</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.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</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)
```
</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.clob_types 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..."])
)
```
</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 USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e 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. Users can cancel orders onchain independently if trust issues arise.
***
## 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>
+443 -13
View File
@@ -2,32 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Orders Overview
# Overview
> Detailed instructions for creating, placing, and managing orders using Polymarket's CLOB API.
> Order types, tick sizes, and querying orders
All orders are expressed as limit orders (can be marketable). The underlying order primitive must be in the form expected and executable by the on-chain binary limit order protocol contract. Preparing such an order is quite involved (structuring, hashing, signing), thus Polymarket suggests using the open source typescript, python and golang libraries.
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) or [Python](https://github.com/Polymarket/py-clob-client) 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"
```
</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}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</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)
```
</CodeGroup>
***
## Allowances
To place an order, allowances must be set by the funder address for the specified `maker` asset for the Exchange contract. When buying, this means the funder must have set a USDC allowance greater than or equal to the spending amount. When selling, the funder must have set an allowance for the conditional token that is greater than or equal to the selling amount. This allows the Exchange contract to execute settlement according to the signed order instructions created by a user and matched by the operator.
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
## Signature Types
* **Buying**: the funder must have set a **USDC.e** 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.
Polymarkets CLOB supports 3 signature types. Orders must identify what signature type they use. The available typescript and python clients abstract the complexity of signing and preparing orders with the following signature types by allowing a funder address and signer type to be specified on initialization. The supported signature types are:
This allows the Exchange contract to execute settlement according to your signed order instructions.
| Type | ID | Description |
| ------------------ | -- | ------------------------------------------------------------------------------------------ |
| EOA | 0 | EIP712 signature signed by an EOA |
| POLY\_PROXY | 1 | EIP712 signatures signed by a signer associated with funding Polymarket proxy wallet |
| POLY\_GNOSIS\_SAFE | 2 | EIP712 signatures signed by a signer associated with funding Polymarket gnosis safe wallet |
***
## Validity Checks
Orders are continually monitored to make sure they remain valid. Specifically, this includes continually tracking underlying balances, allowances and on-chain order cancellations. Any maker that is caught intentionally abusing these checks (which are essentially real time) will be blacklisted.
Orders are continually monitored to make sure they remain valid. This includes tracking:
Additionally, there are rails on order placement in a market. Specifically, 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 USDC in your funding wallet, you can place one order to buy 1000 YES in marketA @ \$.50, then any additional buy orders to that market will be rejected since your entire balance is reserved for the first (and only) buy order. More explicitly the max size you can place for an order is:
* Underlying balances
* Allowances
* Onchain order cancellations
<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 USDC.e 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).
### 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)
```
</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.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</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.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</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)
```
</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.clob_types 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..."])
)
```
</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 USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e 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. Users can cancel orders onchain independently if trust issues arise.
***
## 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>