docs: sync Polymarket docs - 2026-04-14

This commit is contained in:
Etherdrake
2026-04-14 21:53:47 +02:00
parent 814cdc00c9
commit d8e396519a
263 changed files with 1118 additions and 21257 deletions
-422
View File
@@ -1,422 +0,0 @@
# Authentication
> How to authenticate requests to the CLOB API
The CLOB API uses two levels of authentication: **L1 (Private Key)** and **L2 (API Key)**. Either can be accomplished using the CLOB client or REST API.
## Public vs Authenticated
<CardGroup cols={1}>
<Card title="Public (No Auth)" icon="unlock">
The **Gamma API**, **Data API**, and CLOB read endpoints (orderbook, prices, spreads) require no authentication.
</Card>
<Card title="Authenticated (CLOB)" icon="lock">
CLOB trading endpoints (placing orders, cancellations, heartbeat) require all 5 `POLY_*` L2 HTTP headers.
</Card>
</CardGroup>
***
## Two-Level Authentication Model
The CLOB uses two levels of authentication: L1 (Private Key) and L2 (API Key). Either can be accomplished using the CLOB client or REST API
### L1 Authentication
L1 authentication uses the wallet's private key to sign an EIP-712 message used in the request header. It proves ownership and control over the private key. The private key stays in control of the user and all trading activity remains non-custodial.
**Used for:**
* Creating API credentials
* Deriving existing API credentials
* Signing and creating user's orders locally
### L2 Authentication
L2 uses API credentials (apiKey, secret, passphrase) generated from L1 authentication. These are used solely to authenticate requests made to the CLOB API. Requests are signed using HMAC-SHA256.
**Used for:**
* Cancel or get user's open orders
* Check user's balances and allowances
* Post user's signed orders
<Info>
Even with L2 authentication headers, methods that create user orders still
require the user to sign the order payload.
</Info>
***
## Getting API Credentials
Before making authenticated requests, you need to obtain API credentials using L1 authentication.
### Using the SDK
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const client = new ClobClient(
"https://clob.polymarket.com",
137, // Polygon mainnet
new Wallet(process.env.PRIVATE_KEY)
);
// Creates new credentials or derives existing ones
const credentials = await client.createOrDeriveApiKey();
console.log(credentials);
// {
// apiKey: "550e8400-e29b-41d4-a716-446655440000",
// secret: "base64EncodedSecretString",
// passphrase: "randomPassphraseString"
// }
```
</Tab>
<Tab title="Python">
```python theme={null}
from py_clob_client.client import ClobClient
import os
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137, # Polygon mainnet
key=os.getenv("PRIVATE_KEY")
)
# Creates new credentials or derives existing ones
credentials = client.create_or_derive_api_creds()
print(credentials)
# {
# "apiKey": "550e8400-e29b-41d4-a716-446655440000",
# "secret": "base64EncodedSecretString",
# "passphrase": "randomPassphraseString"
# }
```
</Tab>
<Tab title="Rust">
```rust theme={null}
use std::str::FromStr;
use polymarket_client_sdk::POLYGON;
use polymarket_client_sdk::auth::{LocalSigner, Signer};
use polymarket_client_sdk::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// Creates new credentials or derives existing ones,
// then initializes the authenticated client — all in one step
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
let credentials = client.credentials();
println!("API Key: {}", credentials.key());
```
</Tab>
</Tabs>
<Warning>
**Never commit private keys to version control.** Always use environment
variables or secure key management systems.
</Warning>
### Using the REST API
While we highly recommend using our provided clients to handle signing and authentication, the following is for developers who choose NOT to use our [Python](https://github.com/Polymarket/py-clob-client) or [TypeScript](https://github.com/Polymarket/clob-client) clients.
**Create API Credentials**
```bash theme={null}
POST https://clob.polymarket.com/auth/api-key
```
**Derive API Credentials**
```bash theme={null}
GET https://clob.polymarket.com/auth/derive-api-key
```
Required L1 headers:
| Header | Description |
| ---------------- | ---------------------- |
| `POLY_ADDRESS` | Polygon signer address |
| `POLY_SIGNATURE` | CLOB EIP-712 signature |
| `POLY_TIMESTAMP` | Current UNIX timestamp |
| `POLY_NONCE` | Nonce (default: 0) |
The `POLY_SIGNATURE` is generated by signing the following EIP-712 struct:
<Accordion title="EIP-712 Signing Example">
<CodeGroup>
```typescript TypeScript theme={null}
const domain = {
name: "ClobAuthDomain",
version: "1",
chainId: chainId, // Polygon Chain ID 137
};
const types = {
ClobAuth: [
{ name: "address", type: "address" },
{ name: "timestamp", type: "string" },
{ name: "nonce", type: "uint256" },
{ name: "message", type: "string" },
],
};
const value = {
address: signingAddress, // The Signing address
timestamp: ts, // The CLOB API server timestamp
nonce: nonce, // The nonce used
message: "This message attests that I control the given wallet",
};
const sig = await signer._signTypedData(domain, types, value);
```
```python Python theme={null}
domain = {
"name": "ClobAuthDomain",
"version": "1",
"chainId": chainId, # Polygon Chain ID 137
}
types = {
"ClobAuth": [
{"name": "address", "type": "address"},
{"name": "timestamp", "type": "string"},
{"name": "nonce", "type": "uint256"},
{"name": "message", "type": "string"},
]
}
value = {
"address": signingAddress, # The signing address
"timestamp": ts, # The CLOB API server timestamp
"nonce": nonce, # The nonce used
"message": "This message attests that I control the given wallet",
}
sig = signer.sign_typed_data(domain, types, value)
```
</CodeGroup>
</Accordion>
Reference implementations:
* [TypeScript](https://github.com/Polymarket/clob-client/blob/main/src/signing/eip712.ts)
* [Python](https://github.com/Polymarket/py-clob-client/blob/main/py_clob_client/signing/eip712.py)
Response:
```json theme={null}
{
"apiKey": "550e8400-e29b-41d4-a716-446655440000",
"secret": "base64EncodedSecretString",
"passphrase": "randomPassphraseString"
}
```
**You'll need all three values for L2 authentication.**
***
## L2 Authentication Headers
All trading endpoints require these 5 headers:
| Header | Description |
| ----------------- | ----------------------------- |
| `POLY_ADDRESS` | Polygon signer address |
| `POLY_SIGNATURE` | HMAC signature for request |
| `POLY_TIMESTAMP` | Current UNIX timestamp |
| `POLY_API_KEY` | User's API `apiKey` value |
| `POLY_PASSPHRASE` | User's API `passphrase` value |
The `POLY_SIGNATURE` for L2 is an HMAC-SHA256 signature created using the user's API credentials `secret` value. Reference implementations can be found in the [TypeScript](https://github.com/Polymarket/clob-client/blob/main/src/signing/hmac.ts) and [Python](https://github.com/Polymarket/py-clob-client/blob/main/py_clob_client/signing/hmac.py) clients.
### CLOB Client
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const client = new ClobClient(
"https://clob.polymarket.com",
137,
new Wallet(process.env.PRIVATE_KEY),
apiCreds, // Generated from L1 auth, API credentials enable L2 methods
1, // signatureType explained below
funderAddress // funder explained below
);
// Now you can trade!
const order = await client.createAndPostOrder(
{ tokenID: "123456", price: 0.65, size: 100, side: "BUY" },
{ tickSize: "0.01", negRisk: false }
);
```
</Tab>
<Tab title="Python">
```python theme={null}
from py_clob_client.client import ClobClient
import os
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=api_creds, # Generated from L1 auth, API credentials enable L2 methods
signature_type=1, # signatureType explained below
funder=os.getenv("FUNDER_ADDRESS") # funder explained below
)
# Now you can trade!
order = client.create_and_post_order(
{"token_id": "123456", "price": 0.65, "size": 100, "side": "BUY"},
{"tick_size": "0.01", "neg_risk": False}
)
```
</Tab>
<Tab title="Rust">
```rust theme={null}
use polymarket_client_sdk::clob::types::{Side, SignatureType};
use polymarket_client_sdk::types::dec;
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::Proxy) // signatureType explained below
// Funder auto-derived via CREATE2 for Proxy/GnosisSafe
.authenticate()
.await?;
// Now you can trade!
let order = client.limit_order()
.token_id("123456".parse()?)
.price(dec!(0.65))
.size(dec!(100))
.side(Side::Buy)
.build().await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</Tab>
</Tabs>
<Info>
Even with L2 authentication headers, methods that create user orders still
require the user to sign the order payload.
</Info>
***
## Signature Types and Funder
When initializing the L2 client, you must specify your wallet **signatureType** and the **funder** address which holds the funds:
| Signature Type | Value | Description |
| -------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| EOA | `0` | Standard Ethereum wallet (MetaMask). Funder is the EOA address and will need POL to pay gas on transactions. |
| POLY\_PROXY | `1` | A custom proxy wallet only used with users who logged in via Magic Link email/Google. Using this requires the user to have exported their PK from Polymarket.com and imported into your app. |
| GNOSIS\_SAFE | `2` | Gnosis Safe multisig proxy wallet (most common). Use this for any new or returning user who does not fit the other 2 types. |
<Tip>
The wallet address displayed to the user on Polymarket.com is the proxy wallet
and should be used as the funder. These can be deterministically derived or
you can deploy them on behalf of the user. These proxy wallets are
automatically deployed for the user on their first login to Polymarket.com.
</Tip>
***
## Security Best Practices
<AccordionGroup>
<Accordion title="Never expose private keys">
Store private keys in environment variables or secure key management systems. Never commit them to version control.
```bash theme={null}
# .env (never commit this file)
PRIVATE_KEY=0x...
```
</Accordion>
<Accordion title="Implement request signing on the server">
Never expose your API secret in client-side code. All authenticated requests should originate from your backend.
</Accordion>
</AccordionGroup>
***
## Troubleshooting
<AccordionGroup>
<Accordion title="Error - INVALID_SIGNATURE">
Your wallet's private key is incorrect or improperly formatted.
**Solutions:**
* Verify your private key is a valid hex string (starts with "0x")
* Ensure you're using the correct key for the intended address
* Check that the key has proper permissions
</Accordion>
<Accordion title="Error - NONCE_ALREADY_USED">
The nonce you provided has already been used to create an API key.
**Solutions:**
* Use `deriveApiKey()` with the same nonce to retrieve existing credentials
* Or use a different nonce with `createApiKey()`
</Accordion>
<Accordion title="Error - Invalid Funder Address">
Your funder address is incorrect or doesn't match your wallet.
**Solution:** Check your Polymarket profile address at [polymarket.com/settings](https://polymarket.com/settings).
If it does not exist or user has never logged into Polymarket.com, deploy it first before creating L2 authentication.
</Accordion>
<Accordion title="Lost both credentials and nonce">
Unfortunately, there's no way to recover lost API credentials without the nonce. You'll need to create new credentials:
```typescript theme={null}
// Create fresh credentials with a new nonce
const newCreds = await client.createApiKey();
// Save the nonce this time!
```
</Accordion>
</AccordionGroup>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Place Your First Order" icon="plus" href="/trading/quickstart">
Learn how to create and submit orders.
</Card>
<Card title="Geographic Restrictions" icon="globe" href="/api-reference/geoblock">
Check trading availability by region.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,368 +0,0 @@
# Builder Methods
> Methods for querying orders and trades using builder API credentials.
## Client Initialization
Builder methods require the client to initialize with a separate builder config using credentials acquired from [Polymarket.com](https://polymarket.com/settings?tab=builder) and the `@polymarket/builder-signing-sdk` package.
<Tabs>
<Tab title="Local Builder Credentials">
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { BuilderConfig, BuilderApiKeyCreds } from "@polymarket/builder-signing-sdk";
const builderConfig = new BuilderConfig({
localBuilderCreds: new BuilderApiKeyCreds({
key: process.env.BUILDER_API_KEY,
secret: process.env.BUILDER_SECRET,
passphrase: process.env.BUILDER_PASS_PHRASE,
}),
});
const clobClient = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds, // User's API credentials from L1 authentication
signatureType,
funderAddress,
undefined,
false,
builderConfig
);
```
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_builder_signing_sdk.config import BuilderConfig, BuilderApiKeyCreds
import os
builder_config = BuilderConfig(
local_builder_creds=BuilderApiKeyCreds(
key=os.getenv("BUILDER_API_KEY"),
secret=os.getenv("BUILDER_SECRET"),
passphrase=os.getenv("BUILDER_PASS_PHRASE"),
)
)
clob_client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=creds, # User's API credentials from L1 authentication
signature_type=signature_type,
funder=funder,
builder_config=builder_config
)
```
</CodeGroup>
</Tab>
<Tab title="Remote Builder Signing">
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { BuilderConfig } from "@polymarket/builder-signing-sdk";
const builderConfig = new BuilderConfig({
remoteBuilderConfig: { url: "http://localhost:3000/sign" }
});
const clobClient = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds, // User's API credentials from L1 authentication
signatureType,
funder,
undefined,
false,
builderConfig
);
```
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_builder_signing_sdk.config import BuilderConfig, RemoteBuilderConfig
import os
builder_config = BuilderConfig(
remote_builder_config=RemoteBuilderConfig(
url="http://localhost:3000/sign"
)
)
clob_client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=creds, # User's API credentials from L1 authentication
signature_type=signature_type,
funder=funder,
builder_config=builder_config
)
```
</CodeGroup>
</Tab>
</Tabs>
<Info>
See [Order Attribution](/trading/orders/attribution) for more information on builder signing.
</Info>
***
## Methods
***
### getOrder
Get details for a specific order by ID using builder authentication. When called from a builder-configured client, the request authenticates with builder headers and returns orders attributed to the builder.
```typescript Signature theme={null}
async getOrder(orderID: string): Promise<OpenOrder>
```
<Info>
When a `BuilderConfig` is present, the client automatically sends builder headers. If builder auth is unavailable, it falls back to standard L2 headers.
</Info>
<CodeGroup>
```typescript TypeScript theme={null}
const order = await clobClient.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = clob_client.get_order("0xb816482a...")
print(order)
```
</CodeGroup>
***
### getOpenOrders
Get all open orders attributed to the builder. When called from a builder-configured client, returns orders placed through the builder rather than orders owned by the authenticated user.
```typescript Signature theme={null}
async getOpenOrders(
params?: OpenOrderParams,
only_first_page?: boolean,
): Promise<OpenOrder[]>
```
**Params**
<ResponseField name="id" type="string">
Optional. Filter by order ID.
</ResponseField>
<ResponseField name="market" type="string">
Optional. Filter by market condition ID.
</ResponseField>
<ResponseField name="asset_id" type="string">
Optional. Filter by token ID.
</ResponseField>
```typescript TypeScript theme={null}
// All open orders for this builder
const orders = await clobClient.getOpenOrders();
// Filtered by market
const marketOrders = await clobClient.getOpenOrders({
market: "0xbd31dc8a...",
});
```
***
### getBuilderTrades
Retrieves all trades attributed to your builder account. Use this to track which trades were routed through your platform.
```typescript Signature theme={null}
async getBuilderTrades(
params?: TradeParams,
): Promise<BuilderTradesPaginatedResponse>
```
**Params (`TradeParams`)**
<ResponseField name="id" type="string">
Optional. Filter trades by trade ID.
</ResponseField>
<ResponseField name="maker_address" type="string">
Optional. Filter trades by maker address.
</ResponseField>
<ResponseField name="market" type="string">
Optional. Filter trades by market condition ID.
</ResponseField>
<ResponseField name="asset_id" type="string">
Optional. Filter trades by asset (token) ID.
</ResponseField>
<ResponseField name="before" type="string">
Optional. Return trades created before this cursor value.
</ResponseField>
<ResponseField name="after" type="string">
Optional. Return trades created after this cursor value.
</ResponseField>
**Response (`BuilderTradesPaginatedResponse`)**
<ResponseField name="trades" type="BuilderTrade[]">
Array of trades attributed to the builder account.
</ResponseField>
<ResponseField name="next_cursor" type="string">
Cursor string for fetching the next page of results.
</ResponseField>
<ResponseField name="limit" type="number">
Maximum number of trades returned per page.
</ResponseField>
<ResponseField name="count" type="number">
Total number of trades returned in this response.
</ResponseField>
**`BuilderTrade` fields**
<ResponseField name="id" type="string">
Unique identifier for the trade.
</ResponseField>
<ResponseField name="tradeType" type="string">
Type of the trade.
</ResponseField>
<ResponseField name="takerOrderHash" type="string">
Hash of the taker order associated with this trade.
</ResponseField>
<ResponseField name="builder" type="string">
Address of the builder who attributed this trade.
</ResponseField>
<ResponseField name="market" type="string">
Condition ID of the market this trade belongs to.
</ResponseField>
<ResponseField name="assetId" type="string">
Token ID of the asset traded.
</ResponseField>
<ResponseField name="side" type="string">
Side of the trade (e.g. BUY or SELL).
</ResponseField>
<ResponseField name="size" type="string">
Size of the trade in shares.
</ResponseField>
<ResponseField name="sizeUsdc" type="string">
Size of the trade denominated in USDC.
</ResponseField>
<ResponseField name="price" type="string">
Price at which the trade was executed.
</ResponseField>
<ResponseField name="status" type="string">
Current status of the trade.
</ResponseField>
<ResponseField name="outcome" type="string">
Outcome label associated with the traded asset.
</ResponseField>
<ResponseField name="outcomeIndex" type="number">
Index of the outcome within the market.
</ResponseField>
<ResponseField name="owner" type="string">
Address of the order owner (taker).
</ResponseField>
<ResponseField name="maker" type="string">
Address of the maker in the trade.
</ResponseField>
<ResponseField name="transactionHash" type="string">
On-chain transaction hash for the trade.
</ResponseField>
<ResponseField name="matchTime" type="string">
Timestamp when the trade was matched.
</ResponseField>
<ResponseField name="bucketIndex" type="number">
Bucket index used for trade grouping.
</ResponseField>
<ResponseField name="fee" type="string">
Fee charged for the trade in shares.
</ResponseField>
<ResponseField name="feeUsdc" type="string">
Fee charged for the trade denominated in USDC.
</ResponseField>
<ResponseField name="err_msg" type="string | null">
Optional. Error message if the trade encountered an issue, otherwise null.
</ResponseField>
<ResponseField name="createdAt" type="string | null">
Timestamp when the trade record was created, or null if unavailable.
</ResponseField>
<ResponseField name="updatedAt" type="string | null">
Timestamp when the trade record was last updated, or null if unavailable.
</ResponseField>
***
### revokeBuilderApiKey
Revokes the builder API key used to authenticate the current request. After revocation, the key can no longer be used for builder-authenticated requests.
```typescript Signature theme={null}
async revokeBuilderApiKey(): Promise<any>
```
<ResponseField name="returns" type="any">
Response from the revocation request.
</ResponseField>
***
## See Also
<CardGroup cols={2}>
<Card title="Builders Program" icon="hammer" href="/builders/overview">
Learn about the Builders Program and its benefits.
</Card>
<Card title="Order Attribution" icon="key" href="/trading/orders/attribution">
Attribute orders to your builder account.
</Card>
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place and manage orders with API credentials.
</Card>
<Card title="Gasless Transactions" icon="gas-pump" href="/trading/gasless">
Execute onchain operations without paying gas.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-403
View File
@@ -1,403 +0,0 @@
# L1 Methods
> These methods require a wallet signer (private key) but do not require user API credentials. Use these for initial setup.
## Client Initialization
L1 methods require the client to initialize with a signer.
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers";
const signer = new Wallet(process.env.PRIVATE_KEY);
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer // Signer required for L1 methods
);
// Ready to create user API credentials
const apiKey = await client.createApiKey();
```
</Tab>
<Tab title="Python">
```python theme={null}
from py_clob_client.client import ClobClient
import os
private_key = os.getenv("PRIVATE_KEY")
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=private_key # Signer required for L1 methods
)
# Ready to create user API credentials
api_key = client.create_api_key()
```
</Tab>
</Tabs>
<Warning>
Never commit private keys to version control. Always use environment variables or a secure key management system.
</Warning>
***
## API Key Management
***
### createApiKey
Creates a new API key (L2 credentials) for the wallet signer. Each wallet can only have one active API key at a time — creating a new key invalidates the previous one.
```typescript Signature theme={null}
async createApiKey(nonce?: number): Promise<ApiKeyCreds>
```
<ResponseField name="nonce" type="number">
Optional custom nonce for deterministic key generation. Optional.
</ResponseField>
<ResponseField name="apiKey" type="string">
The generated API key string.
</ResponseField>
<ResponseField name="secret" type="string">
The secret associated with the API key.
</ResponseField>
<ResponseField name="passphrase" type="string">
The passphrase associated with the API key.
</ResponseField>
***
### deriveApiKey
Derives an existing API key using a specific nonce. If you've already created credentials with a particular nonce, this returns the same credentials.
```typescript Signature theme={null}
async deriveApiKey(nonce?: number): Promise<ApiKeyCreds>
```
<ResponseField name="nonce" type="number">
The nonce used when originally creating the key. Optional.
</ResponseField>
<ResponseField name="apiKey" type="string">
The derived API key string.
</ResponseField>
<ResponseField name="secret" type="string">
The secret associated with the API key.
</ResponseField>
<ResponseField name="passphrase" type="string">
The passphrase associated with the API key.
</ResponseField>
***
### createOrDeriveApiKey
Convenience method that attempts to derive an API key with the default nonce, or creates a new one if it doesn't exist. **Recommended for initial setup.**
```typescript Signature theme={null}
async createOrDeriveApiKey(nonce?: number): Promise<ApiKeyCreds>
```
<ResponseField name="apiKey" type="string">
The API key string, either derived or newly created.
</ResponseField>
<ResponseField name="secret" type="string">
The secret associated with the API key.
</ResponseField>
<ResponseField name="passphrase" type="string">
The passphrase associated with the API key.
</ResponseField>
***
## Order Signing
### createOrder
Create and sign a limit order locally without posting it to the CLOB. Use this when you want to sign orders in advance or implement custom submission logic. Submit via [`postOrder()`](/trading/clients/l2#postorder) or [`postOrders()`](/trading/clients/l2#postorders).
```typescript Signature theme={null}
async createOrder(
userOrder: UserOrder,
options?: Partial<CreateOrderOptions>
): Promise<SignedOrder>
```
<ResponseField name="tokenID" type="string">
The token ID of the market outcome to trade.
</ResponseField>
<ResponseField name="price" type="number">
The limit price for the order.
</ResponseField>
<ResponseField name="size" type="number">
The size (number of shares) for the order.
</ResponseField>
<ResponseField name="side" type="Side">
The side of the order (buy or sell).
</ResponseField>
<ResponseField name="feeRateBps" type="number">
Optional fee rate in basis points. Optional.
</ResponseField>
<ResponseField name="nonce" type="number">
Optional nonce for the order. Optional.
</ResponseField>
<ResponseField name="expiration" type="number">
Optional expiration timestamp for the order. Optional.
</ResponseField>
<ResponseField name="taker" type="string">
Optional taker address for the order. Optional.
</ResponseField>
<ResponseField name="tickSize" type="TickSize">
The tick size used for order validation (CreateOrderOptions).
</ResponseField>
<ResponseField name="negRisk" type="boolean">
Optional flag for negative risk markets (CreateOrderOptions). Optional.
</ResponseField>
<ResponseField name="salt" type="string">
A random salt value for the signed order.
</ResponseField>
<ResponseField name="maker" type="string">
The maker's address.
</ResponseField>
<ResponseField name="signer" type="string">
The signer's address.
</ResponseField>
<ResponseField name="taker" type="string">
The taker's address in the signed order.
</ResponseField>
<ResponseField name="tokenId" type="string">
The token ID in the signed order.
</ResponseField>
<ResponseField name="makerAmount" type="string">
The maker amount as a string.
</ResponseField>
<ResponseField name="takerAmount" type="string">
The taker amount as a string.
</ResponseField>
<ResponseField name="side" type="number">
The side of the order as a number (0 = BUY, 1 = SELL).
</ResponseField>
<ResponseField name="expiration" type="string">
The expiration timestamp as a string.
</ResponseField>
<ResponseField name="nonce" type="string">
The nonce as a string.
</ResponseField>
<ResponseField name="feeRateBps" type="string">
The fee rate in basis points as a string.
</ResponseField>
<ResponseField name="signatureType" type="number">
The type identifier for the signature scheme used.
</ResponseField>
<ResponseField name="signature" type="string">
The cryptographic signature of the order.
</ResponseField>
***
### createMarketOrder
Create and sign a market order locally without posting it to the CLOB. Submit via [`postOrder()`](/trading/clients/l2#postorder) or [`postOrders()`](/trading/clients/l2#postorders).
```typescript Signature theme={null}
async createMarketOrder(
userMarketOrder: UserMarketOrder,
options?: Partial<CreateOrderOptions>
): Promise<SignedOrder>
```
<ResponseField name="tokenID" type="string">
The token ID of the market outcome to trade.
</ResponseField>
<ResponseField name="amount" type="number">
The order amount. For BUY orders this is a dollar amount; for SELL orders this is the number of shares.
</ResponseField>
<ResponseField name="side" type="Side">
The side of the order (buy or sell).
</ResponseField>
<ResponseField name="price" type="number">
Optional price limit for the market order. Optional.
</ResponseField>
<ResponseField name="feeRateBps" type="number">
Optional fee rate in basis points. Optional.
</ResponseField>
<ResponseField name="nonce" type="number">
Optional nonce for the order. Optional.
</ResponseField>
<ResponseField name="taker" type="string">
Optional taker address for the order. Optional.
</ResponseField>
<ResponseField name="orderType" type="OrderType.FOK | OrderType.FAK">
Optional order type, either FOK (Fill-Or-Kill) or FAK (Fill-And-Kill). Optional.
</ResponseField>
<ResponseField name="salt" type="string">
A random salt value for the signed order.
</ResponseField>
<ResponseField name="maker" type="string">
The maker's address.
</ResponseField>
<ResponseField name="signer" type="string">
The signer's address.
</ResponseField>
<ResponseField name="taker" type="string">
The taker's address in the signed order.
</ResponseField>
<ResponseField name="tokenId" type="string">
The token ID in the signed order.
</ResponseField>
<ResponseField name="makerAmount" type="string">
The maker amount as a string.
</ResponseField>
<ResponseField name="takerAmount" type="string">
The taker amount as a string.
</ResponseField>
<ResponseField name="side" type="number">
The side of the order as a number (0 = BUY, 1 = SELL).
</ResponseField>
<ResponseField name="expiration" type="string">
The expiration timestamp as a string.
</ResponseField>
<ResponseField name="nonce" type="string">
The nonce as a string.
</ResponseField>
<ResponseField name="feeRateBps" type="string">
The fee rate in basis points as a string.
</ResponseField>
<ResponseField name="signatureType" type="number">
The type identifier for the signature scheme used.
</ResponseField>
<ResponseField name="signature" type="string">
The cryptographic signature of the order.
</ResponseField>
***
## Troubleshooting
<AccordionGroup>
<Accordion title="Error - INVALID_SIGNATURE">
Your wallet's private key is incorrect or improperly formatted.
**Solution:**
* Verify your private key is a valid hex string (starts with `0x`)
* Ensure you're using the correct key for the intended address
* Check that the key has proper permissions
</Accordion>
<Accordion title="Error - NONCE_ALREADY_USED">
The nonce you provided has already been used to create an API key.
**Solution:**
* Use `deriveApiKey()` with the same nonce to retrieve existing credentials
* Or use a different nonce with `createApiKey()`
</Accordion>
<Accordion title="Error - Invalid Funder Address">
Your funder address is incorrect or doesn't match your wallet.
**Solution:** Check your proxy wallet address at [polymarket.com/settings](https://polymarket.com/settings). If it doesn't exist, the user has never logged in to Polymarket.com — deploy the proxy wallet first before creating L2 credentials.
</Accordion>
<Accordion title="Lost API credentials but have nonce">
```typescript theme={null}
// Use deriveApiKey with the original nonce
const recovered = await client.deriveApiKey(originalNonce);
```
</Accordion>
<Accordion title="Lost both credentials and nonce">
There's no way to recover lost credentials without the nonce. Create new ones:
```typescript theme={null}
// Create fresh credentials with a new nonce
const newCreds = await client.createApiKey();
// Save the nonce this time!
```
</Accordion>
</AccordionGroup>
***
## See Also
<CardGroup cols={2}>
<Card title="Authentication" icon="shield" href="/api-reference/authentication">
Deep dive into L1 and L2 authentication.
</Card>
<Card title="Trading Quickstart" icon="bolt" href="/trading/quickstart">
Initialize the client and place your first order.
</Card>
<Card title="Public Methods" icon="globe" href="/trading/clients/public">
Access market data, orderbooks, and prices without auth.
</Card>
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place and manage orders with API credentials.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-770
View File
@@ -1,770 +0,0 @@
# L2 Methods
> These methods require user API credentials (L2 headers). Use these for placing trades and managing your positions.
## Client Initialization
L2 methods require the client to initialize with a signer, signature type, API credentials, and funder address.
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers";
const signer = new Wallet(process.env.PRIVATE_KEY);
const apiCreds = {
apiKey: process.env.API_KEY,
secret: process.env.SECRET,
passphrase: process.env.PASSPHRASE,
};
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
2, // GNOSIS_SAFE
process.env.FUNDER_ADDRESS
);
// Ready to send authenticated requests
const order = await client.postOrder(signedOrder);
```
</Tab>
<Tab title="Python">
```python theme={null}
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
import os
api_creds = ApiCreds(
api_key=os.getenv("API_KEY"),
api_secret=os.getenv("SECRET"),
api_passphrase=os.getenv("PASSPHRASE")
)
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=api_creds,
signature_type=2, # GNOSIS_SAFE
funder=os.getenv("FUNDER_ADDRESS")
)
# Ready to send authenticated requests
order = client.post_order(signed_order)
```
</Tab>
</Tabs>
***
## Order Creation and Management
***
### createAndPostOrder
Convenience method that creates, signs, and posts a limit order in a single call. Use when you want to buy or sell at a specific price.
```typescript Signature theme={null}
async createAndPostOrder(
userOrder: UserOrder,
options?: Partial<CreateOrderOptions>,
orderType?: OrderType.GTC | OrderType.GTD, // Defaults to GTC
): Promise<OrderResponse>
```
**Params**
<ResponseField name="tokenID" type="string">
The token ID of the outcome to trade.
</ResponseField>
<ResponseField name="price" type="number">
The limit price for the order.
</ResponseField>
<ResponseField name="size" type="number">
The size of the order.
</ResponseField>
<ResponseField name="side" type="Side">
The side of the order (buy or sell).
</ResponseField>
<ResponseField name="feeRateBps" type="number">
Optional fee rate in basis points.
</ResponseField>
<ResponseField name="nonce" type="number">
Optional nonce for the order.
</ResponseField>
<ResponseField name="expiration" type="number">
Optional expiration timestamp for the order.
</ResponseField>
<ResponseField name="taker" type="string">
Optional taker address.
</ResponseField>
<ResponseField name="tickSize" type="TickSize">
Tick size for the order. One of `"0.1"`, `"0.01"`, `"0.001"`, `"0.0001"`.
</ResponseField>
<ResponseField name="negRisk" type="boolean">
Optional. Whether the market uses negative risk.
</ResponseField>
**Response**
<ResponseField name="success" type="boolean">
Whether the order was successfully placed.
</ResponseField>
<ResponseField name="errorMsg" type="string">
Error message if the order was not successful.
</ResponseField>
<ResponseField name="orderID" type="string">
The ID of the placed order.
</ResponseField>
<ResponseField name="transactionsHashes" type="string[]">
Array of transaction hashes associated with the order.
</ResponseField>
<ResponseField name="status" type="string">
The current status of the order.
</ResponseField>
<ResponseField name="takingAmount" type="string">
The amount being taken in the order.
</ResponseField>
<ResponseField name="makingAmount" type="string">
The amount being made in the order.
</ResponseField>
***
### createAndPostMarketOrder
Convenience method that creates, signs, and posts a market order in a single call. Use when you want to buy or sell at the current market price.
```typescript Signature theme={null}
async createAndPostMarketOrder(
userMarketOrder: UserMarketOrder,
options?: Partial<CreateOrderOptions>,
orderType?: OrderType.FOK | OrderType.FAK, // Defaults to FOK
): Promise<OrderResponse>
```
**Params**
<ResponseField name="tokenID" type="string">
The token ID of the outcome to trade.
</ResponseField>
<ResponseField name="amount" type="number">
The amount for the market order.
</ResponseField>
<ResponseField name="side" type="Side">
The side of the order (buy or sell).
</ResponseField>
<ResponseField name="price" type="number">
Optional price hint for the market order.
</ResponseField>
<ResponseField name="feeRateBps" type="number">
Optional fee rate in basis points.
</ResponseField>
<ResponseField name="nonce" type="number">
Optional nonce for the order.
</ResponseField>
<ResponseField name="taker" type="string">
Optional taker address.
</ResponseField>
<ResponseField name="orderType" type="OrderType.FOK | OrderType.FAK">
Optional order type override. Defaults to FOK.
</ResponseField>
**Response**
<ResponseField name="success" type="boolean">
Whether the order was successfully placed.
</ResponseField>
<ResponseField name="errorMsg" type="string">
Error message if the order was not successful.
</ResponseField>
<ResponseField name="orderID" type="string">
The ID of the placed order.
</ResponseField>
<ResponseField name="transactionsHashes" type="string[]">
Array of transaction hashes associated with the order.
</ResponseField>
<ResponseField name="status" type="string">
The current status of the order.
</ResponseField>
<ResponseField name="takingAmount" type="string">
The amount being taken in the order.
</ResponseField>
<ResponseField name="makingAmount" type="string">
The amount being made in the order.
</ResponseField>
***
### postOrder
Posts a pre-signed order to the CLOB. Use with [`createOrder()`](/trading/clients/l1#createorder) or [`createMarketOrder()`](/trading/clients/l1#createmarketorder) from L1 methods.
```typescript Signature theme={null}
async postOrder(
order: SignedOrder,
orderType?: OrderType, // Defaults to GTC
postOnly?: boolean, // Defaults to false
): Promise<OrderResponse>
```
***
### postOrders
Posts up to 15 pre-signed orders in a single batch.
```typescript Signature theme={null}
async postOrders(
args: PostOrdersArgs[],
): Promise<OrderResponse[]>
```
**Params**
<ResponseField name="order" type="SignedOrder">
The pre-signed order to post.
</ResponseField>
<ResponseField name="orderType" type="OrderType">
The order type (e.g. GTC, FOK, FAK).
</ResponseField>
<ResponseField name="postOnly" type="boolean">
Optional. Whether to post the order as post-only. Defaults to false.
</ResponseField>
***
### cancelOrder
Cancels a single open order.
```typescript Signature theme={null}
async cancelOrder(orderID: string): Promise<CancelOrdersResponse>
```
**Response**
<ResponseField name="canceled" type="string[]">
Array of order IDs that were successfully canceled.
</ResponseField>
<ResponseField name="not_canceled" type="Record<string, any>">
Map of order IDs to reasons why they could not be canceled.
</ResponseField>
***
### cancelOrders
Cancels multiple orders in a single batch.
```typescript Signature theme={null}
async cancelOrders(orderIDs: string[]): Promise<CancelOrdersResponse>
```
***
### cancelAll
Cancels all open orders.
```typescript Signature theme={null}
async cancelAll(): Promise<CancelOrdersResponse>
```
***
### cancelMarketOrders
Cancels all open orders for a specific market.
```typescript Signature theme={null}
async cancelMarketOrders(
payload: OrderMarketCancelParams
): Promise<CancelOrdersResponse>
```
**Params**
<ResponseField name="market" type="string">
Optional. The market condition ID to cancel orders for.
</ResponseField>
<ResponseField name="asset_id" type="string">
Optional. The token ID to cancel orders for.
</ResponseField>
***
## Order and Trade Queries
***
### getOrder
Get details for a specific order by ID.
```typescript Signature theme={null}
async getOrder(orderID: string): Promise<OpenOrder>
```
**Response**
<ResponseField name="id" type="string">
The unique order ID.
</ResponseField>
<ResponseField name="status" type="string">
The current status of the order.
</ResponseField>
<ResponseField name="owner" type="string">
The API key of the order owner.
</ResponseField>
<ResponseField name="maker_address" type="string">
The on-chain address of the order maker.
</ResponseField>
<ResponseField name="market" type="string">
The market condition ID the order belongs to.
</ResponseField>
<ResponseField name="asset_id" type="string">
The token ID the order is for.
</ResponseField>
<ResponseField name="side" type="string">
The side of the order (BUY or SELL).
</ResponseField>
<ResponseField name="original_size" type="string">
The original size of the order when it was placed.
</ResponseField>
<ResponseField name="size_matched" type="string">
The amount of the order that has been matched so far.
</ResponseField>
<ResponseField name="price" type="string">
The limit price of the order.
</ResponseField>
<ResponseField name="associate_trades" type="string[]">
Array of trade IDs associated with this order.
</ResponseField>
<ResponseField name="outcome" type="string">
The outcome label for the order's token.
</ResponseField>
<ResponseField name="created_at" type="number">
Unix timestamp of when the order was created.
</ResponseField>
<ResponseField name="expiration" type="string">
The expiration time of the order.
</ResponseField>
<ResponseField name="order_type" type="string">
The order type (e.g. GTC, FOK, FAK, GTD).
</ResponseField>
***
### getOpenOrders
Get all your open orders.
```typescript Signature theme={null}
async getOpenOrders(
params?: OpenOrderParams,
only_first_page?: boolean,
): Promise<OpenOrder[]>
```
**Params**
<ResponseField name="id" type="string">
Optional. Filter by order ID.
</ResponseField>
<ResponseField name="market" type="string">
Optional. Filter by market condition ID.
</ResponseField>
<ResponseField name="asset_id" type="string">
Optional. Filter by token ID.
</ResponseField>
***
### getTrades
Get your trade history (filled orders).
```typescript Signature theme={null}
async getTrades(
params?: TradeParams,
only_first_page?: boolean,
): Promise<Trade[]>
```
**Params**
<ResponseField name="id" type="string">
Optional. Filter by trade ID.
</ResponseField>
<ResponseField name="maker_address" type="string">
Optional. Filter by maker address.
</ResponseField>
<ResponseField name="market" type="string">
Optional. Filter by market condition ID.
</ResponseField>
<ResponseField name="asset_id" type="string">
Optional. Filter by token ID.
</ResponseField>
<ResponseField name="before" type="string">
Optional. Return trades before this timestamp.
</ResponseField>
<ResponseField name="after" type="string">
Optional. Return trades after this timestamp.
</ResponseField>
**Response**
<ResponseField name="id" type="string">
The unique trade ID.
</ResponseField>
<ResponseField name="taker_order_id" type="string">
The order ID of the taker side.
</ResponseField>
<ResponseField name="market" type="string">
The market condition ID for the trade.
</ResponseField>
<ResponseField name="asset_id" type="string">
The token ID for the trade.
</ResponseField>
<ResponseField name="side" type="Side">
The side of the trade (BUY or SELL).
</ResponseField>
<ResponseField name="size" type="string">
The size of the trade.
</ResponseField>
<ResponseField name="fee_rate_bps" type="string">
The fee rate in basis points.
</ResponseField>
<ResponseField name="price" type="string">
The price at which the trade was matched.
</ResponseField>
<ResponseField name="status" type="string">
The current status of the trade.
</ResponseField>
<ResponseField name="match_time" type="string">
The time at which the trade was matched.
</ResponseField>
<ResponseField name="last_update" type="string">
The time of the last update to this trade.
</ResponseField>
<ResponseField name="outcome" type="string">
The outcome label for the traded token.
</ResponseField>
<ResponseField name="bucket_index" type="number">
The bucket index for the trade.
</ResponseField>
<ResponseField name="owner" type="string">
The API key of the trade owner.
</ResponseField>
<ResponseField name="maker_address" type="string">
The on-chain address of the maker.
</ResponseField>
<ResponseField name="maker_orders" type="MakerOrder[]">
Array of maker order objects that participated in this trade. Each `MakerOrder` contains the following fields:
</ResponseField>
<ResponseField name="maker_orders[].order_id" type="string">
The maker order ID.
</ResponseField>
<ResponseField name="maker_orders[].owner" type="string">
The API key of the maker order owner.
</ResponseField>
<ResponseField name="maker_orders[].maker_address" type="string">
The on-chain address of the maker order maker.
</ResponseField>
<ResponseField name="maker_orders[].matched_amount" type="string">
The amount matched for this maker order.
</ResponseField>
<ResponseField name="maker_orders[].price" type="string">
The price of the maker order.
</ResponseField>
<ResponseField name="maker_orders[].fee_rate_bps" type="string">
The fee rate in basis points for the maker order.
</ResponseField>
<ResponseField name="maker_orders[].asset_id" type="string">
The token ID for the maker order.
</ResponseField>
<ResponseField name="maker_orders[].outcome" type="string">
The outcome label for the maker order's token.
</ResponseField>
<ResponseField name="maker_orders[].side" type="Side">
The side of the maker order (BUY or SELL).
</ResponseField>
<ResponseField name="transaction_hash" type="string">
The on-chain transaction hash for the trade.
</ResponseField>
<ResponseField name="trader_side" type="&#x22;TAKER&#x22; | &#x22;MAKER&#x22;">
Whether the authenticated user is the taker or a maker in this trade.
</ResponseField>
***
### getTradesPaginated
Get trade history with pagination for large result sets.
```typescript Signature theme={null}
async getTradesPaginated(
params?: TradeParams,
): Promise<TradesPaginatedResponse>
```
**Response**
<ResponseField name="trades" type="Trade[]">
Array of trade objects for the current page.
</ResponseField>
<ResponseField name="limit" type="number">
The maximum number of trades returned per page.
</ResponseField>
<ResponseField name="count" type="number">
The total number of trades matching the query.
</ResponseField>
***
## Balance and Allowances
***
### getBalanceAllowance
Get your balance and allowance for specific tokens.
```typescript Signature theme={null}
async getBalanceAllowance(
params?: BalanceAllowanceParams
): Promise<BalanceAllowanceResponse>
```
**Params**
<ResponseField name="asset_type" type="AssetType">
The type of asset to query. One of `"COLLATERAL"` or `"CONDITIONAL"`.
</ResponseField>
<ResponseField name="token_id" type="string">
Optional. The token ID to query (required when `asset_type` is `CONDITIONAL`).
</ResponseField>
**Response**
<ResponseField name="balance" type="string">
The current balance for the specified asset.
</ResponseField>
<ResponseField name="allowance" type="string">
The current allowance for the specified asset.
</ResponseField>
***
### updateBalanceAllowance
Updates the cached balance and allowance for specific tokens.
```typescript Signature theme={null}
async updateBalanceAllowance(
params?: BalanceAllowanceParams
): Promise<void>
```
***
## API Key Management
***
### getApiKeys
Get all API keys associated with your account.
```typescript Signature theme={null}
async getApiKeys(): Promise<ApiKeysResponse>
```
**Response**
<ResponseField name="apiKeys" type="ApiKeyCreds[]">
Array of API key credential objects associated with the account.
</ResponseField>
***
### deleteApiKey
Deletes (revokes) the currently authenticated API key.
```typescript Signature theme={null}
async deleteApiKey(): Promise<any>
```
***
## Notifications
***
### getNotifications
Retrieves all event notifications for the authenticated user. Records are automatically removed after 48 hours.
```typescript Signature theme={null}
async getNotifications(): Promise<Notification[]>
```
**Response**
<ResponseField name="id" type="number">
Unique notification ID.
</ResponseField>
<ResponseField name="owner" type="string">
The user's API key, or an empty string for global notifications.
</ResponseField>
<ResponseField name="payload" type="any">
Type-specific payload data for the notification.
</ResponseField>
<ResponseField name="timestamp" type="number">
Optional Unix timestamp of when the notification was created.
</ResponseField>
<ResponseField name="type" type="number">
Notification type (see below).
</ResponseField>
| Name | Value | Description |
| ------------------ | ----- | ---------------------------------------- |
| Order Cancellation | `1` | User's order was canceled |
| Order Fill | `2` | User's order was filled (maker or taker) |
| Market Resolved | `4` | Market was resolved |
***
### dropNotifications
Mark notifications as read/dismissed.
```typescript Signature theme={null}
async dropNotifications(params?: DropNotificationParams): Promise<void>
```
**Params**
<ResponseField name="ids" type="string[]">
Array of notification IDs to dismiss.
</ResponseField>
***
## See Also
<CardGroup cols={2}>
<Card title="Authentication" icon="shield" href="/api-reference/authentication">
Deep dive into L1 and L2 authentication.
</Card>
<Card title="L1 Methods" icon="key" href="/trading/clients/l1">
Sign orders and derive API credentials with your private key.
</Card>
<Card title="Public Methods" icon="globe" href="/trading/clients/public">
Read market data and orderbooks without auth.
</Card>
<Card title="WebSocket" icon="bolt" href="/market-data/websocket/overview">
Real-time market data streaming.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,106 +0,0 @@
# Clients & SDKs
> Official open-source libraries for interacting with Polymarket
Polymarket provides official open-source clients in TypeScript, Python, and Rust. All three support the full CLOB API including market data, order management, and authentication.
## Installation
<CodeGroup>
```bash TypeScript theme={null}
npm install @polymarket/clob-client ethers@5
```
```bash Python theme={null}
pip install py-clob-client
```
```bash Rust theme={null}
cargo add polymarket-client-sdk
```
</CodeGroup>
## Quick Example
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
);
const markets = await client.getMarkets();
```
```python Python theme={null}
from py_clob_client.client import ClobClient
client = ClobClient(
"https://clob.polymarket.com",
key=private_key,
chain_id=137,
creds=api_creds,
)
markets = client.get_markets()
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::{Client, Config};
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
let markets = client.markets(None).await?;
```
</CodeGroup>
## Source Code
| Language | Package | Repository |
| ---------- | ------------------------- | ------------------------------------------------------------------------------------ |
| TypeScript | `@polymarket/clob-client` | [github.com/Polymarket/clob-client](https://github.com/Polymarket/clob-client) |
| Python | `py-clob-client` | [github.com/Polymarket/py-clob-client](https://github.com/Polymarket/py-clob-client) |
| Rust | `polymarket-client-sdk` | [github.com/Polymarket/rs-clob-client](https://github.com/Polymarket/rs-clob-client) |
Each repository includes working examples in the `/examples` directory.
## Builder SDKs
If you're building an app through the [Builder Program](/builders/overview), additional signing SDKs are available:
| Language | Package | Repository |
| ---------- | --------------------------------- | ---------------------------------------------------------------------------------------------------- |
| TypeScript | `@polymarket/builder-signing-sdk` | [github.com/Polymarket/builder-signing-sdk](https://github.com/Polymarket/builder-signing-sdk) |
| Python | `py_builder_signing_sdk` | [github.com/Polymarket/py-builder-signing-sdk](https://github.com/Polymarket/py-builder-signing-sdk) |
See [Order Attribution](/trading/orders/attribution) for usage details.
## Relayer SDK
For [gasless transactions](/trading/gasless) using proxy wallets, the relayer client handles submitting transactions through Polymarket's relayer:
| Language | Package | Repository |
| ---------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| TypeScript | `@polymarket/builder-relayer-client` | [github.com/Polymarket/builder-relayer-client](https://github.com/Polymarket/builder-relayer-client) |
| Python | `py-builder-relayer-client` | [github.com/Polymarket/py-builder-relayer-client](https://github.com/Polymarket/py-builder-relayer-client) |
## Next Steps
<CardGroup cols={2}>
<Card title="Quickstart" icon="rocket" href="/quickstart">
Set up your client and place your first order.
</Card>
<Card title="Authentication" icon="lock" href="/api-reference/authentication">
Understand L1/L2 auth and API credentials.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,661 +0,0 @@
# Public Methods
> These methods can be called without a signer or user credentials. Use these for reading market data, prices, and order books.
## Client Initialization
Public methods require the client to initialize with the host URL and Polygon chain ID.
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
const client = new ClobClient(
"https://clob.polymarket.com",
137
);
// Ready to call public methods
const markets = await client.getMarkets();
```
</Tab>
<Tab title="Python">
```python theme={null}
from py_clob_client.client import ClobClient
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137
)
# Ready to call public methods
markets = client.get_markets()
```
</Tab>
</Tabs>
***
## Health Check
***
### getOk
Health check endpoint to verify the CLOB service is operational.
```typescript Signature theme={null}
async getOk(): Promise<any>
```
***
## Markets
***
### getMarket
Get details for a single market by condition ID.
```typescript Signature theme={null}
async getMarket(conditionId: string): Promise<Market>
```
<ResponseField name="accepting_order_timestamp" type="string">
Timestamp from which the market started accepting orders, or null if not set.
</ResponseField>
<ResponseField name="accepting_orders" type="boolean">
Whether the market is currently accepting orders.
</ResponseField>
<ResponseField name="active" type="boolean">
Whether the market is active.
</ResponseField>
<ResponseField name="archived" type="boolean">
Whether the market has been archived.
</ResponseField>
<ResponseField name="closed" type="boolean">
Whether the market is closed.
</ResponseField>
<ResponseField name="condition_id" type="string">
The unique condition ID for the market.
</ResponseField>
<ResponseField name="description" type="string">
Human-readable description of the market.
</ResponseField>
<ResponseField name="enable_order_book" type="boolean">
Whether the order book is enabled for this market.
</ResponseField>
<ResponseField name="end_date_iso" type="string">
ISO 8601 end date of the market.
</ResponseField>
<ResponseField name="fpmm" type="string">
Address of the Fixed Product Market Maker contract.
</ResponseField>
<ResponseField name="game_start_time" type="string">
Start time of the underlying game or event.
</ResponseField>
<ResponseField name="icon" type="string">
URL of the market icon image.
</ResponseField>
<ResponseField name="image" type="string">
URL of the market image.
</ResponseField>
<ResponseField name="is_50_50_outcome" type="boolean">
Whether the market has equal 50/50 outcomes.
</ResponseField>
<ResponseField name="maker_base_fee" type="number">
Base fee charged to makers in basis points.
</ResponseField>
<ResponseField name="market_slug" type="string">
URL-friendly slug identifier for the market.
</ResponseField>
<ResponseField name="minimum_order_size" type="number">
Minimum order size allowed in this market.
</ResponseField>
<ResponseField name="minimum_tick_size" type="number">
Minimum price increment allowed in this market.
</ResponseField>
<ResponseField name="neg_risk" type="boolean">
Whether the market uses negative risk (binary complementary tokens).
</ResponseField>
<ResponseField name="neg_risk_market_id" type="string">
Negative risk market identifier, if applicable.
</ResponseField>
<ResponseField name="neg_risk_request_id" type="string">
Negative risk request identifier, if applicable.
</ResponseField>
<ResponseField name="notifications_enabled" type="boolean">
Whether notifications are enabled for this market.
</ResponseField>
<ResponseField name="question" type="string">
The market question text.
</ResponseField>
<ResponseField name="question_id" type="string">
Unique identifier for the market question.
</ResponseField>
<ResponseField name="rewards" type="object">
Object containing reward config: `max_spread` (number), `min_size` (number), `rates` (any)
</ResponseField>
<ResponseField name="seconds_delay" type="number">
Delay in seconds before orders are processed.
</ResponseField>
<ResponseField name="tags" type="string[]">
List of tags associated with the market.
</ResponseField>
<ResponseField name="taker_base_fee" type="number">
Base fee charged to takers in basis points.
</ResponseField>
<ResponseField name="tokens" type="MarketToken[]">
Array of market tokens, each containing `outcome` (string), `price` (number), `token_id` (string), and `winner` (boolean).
</ResponseField>
***
### getMarkets
Get details for multiple markets paginated.
```typescript Signature theme={null}
async getMarkets(): Promise<PaginationPayload>
```
<ResponseField name="limit" type="number">
Maximum number of results per page.
</ResponseField>
<ResponseField name="count" type="number">
Total number of markets returned.
</ResponseField>
<ResponseField name="data" type="Market[]">
Array of Market objects. See `getMarket()` for the full Market structure.
</ResponseField>
***
### getSimplifiedMarkets
Get simplified market data paginated for faster loading.
```typescript Signature theme={null}
async getSimplifiedMarkets(): Promise<PaginationPayload>
```
<ResponseField name="limit" type="number">
Maximum number of results per page.
</ResponseField>
<ResponseField name="count" type="number">
Total number of markets returned.
</ResponseField>
<ResponseField name="data" type="SimplifiedMarket[]">
Array of simplified market objects, each containing `accepting_orders` (boolean), `active` (boolean), `archived` (boolean), `closed` (boolean), `condition_id` (string), `rewards` (object with `rates`, `min_size`, `max_spread`), and `tokens` (SimplifiedToken\[]) with `outcome` (string), `price` (number), `token_id` (string).
</ResponseField>
***
### getSamplingMarkets
Get markets eligible for sampling/liquidity rewards.
```typescript Signature theme={null}
async getSamplingMarkets(): Promise<PaginationPayload>
```
***
### getSamplingSimplifiedMarkets
Get simplified market data for markets eligible for sampling/liquidity rewards.
```typescript Signature theme={null}
async getSamplingSimplifiedMarkets(): Promise<PaginationPayload>
```
***
## Order Books and Prices
***
### calculateMarketPrice
Calculate the estimated price for a market order of a given size.
```typescript Signature theme={null}
async calculateMarketPrice(
tokenID: string,
side: Side,
amount: number,
orderType: OrderType = OrderType.FOK
): Promise<number>
```
<ResponseField name="tokenID" type="string">
The token ID to calculate the market price for.
</ResponseField>
<ResponseField name="side" type="Side">
The side of the order. One of: `BUY`, `SELL`
</ResponseField>
<ResponseField name="amount" type="number">
The size of the order to calculate price for.
</ResponseField>
<ResponseField name="orderType" type="OrderType">
The order type. One of: `GTC` (Good Till Cancelled), `FOK` (Fill or Kill), `GTD` (Good Till Date), `FAK` (Fill and Kill). Defaults to `FOK`.
</ResponseField>
<ResponseField name="returns" type="number">
The calculated estimated market price for the given order size.
</ResponseField>
***
### getOrderBook
Get the order book for a specific token ID.
```typescript Signature theme={null}
async getOrderBook(tokenID: string): Promise<OrderBookSummary>
```
<ResponseField name="market" type="string">
The market condition ID.
</ResponseField>
<ResponseField name="asset_id" type="string">
The token/asset ID for this order book.
</ResponseField>
<ResponseField name="timestamp" type="string">
Timestamp of the order book snapshot.
</ResponseField>
<ResponseField name="bids" type="OrderSummary[]">
Array of bid entries, each with `price` (string) and `size` (string).
</ResponseField>
<ResponseField name="asks" type="OrderSummary[]">
Array of ask entries, each with `price` (string) and `size` (string).
</ResponseField>
<ResponseField name="min_order_size" type="string">
Minimum order size for this market.
</ResponseField>
<ResponseField name="tick_size" type="string">
Minimum price increment for this market.
</ResponseField>
<ResponseField name="neg_risk" type="boolean">
Whether the market uses negative risk.
</ResponseField>
<ResponseField name="hash" type="string">
Hash of the order book state.
</ResponseField>
***
### getOrderBooks
Get order books for multiple token IDs.
```typescript Signature theme={null}
async getOrderBooks(params: BookParams[]): Promise<OrderBookSummary[]>
```
<ResponseField name="token_id" type="string">
The token ID to fetch the order book for.
</ResponseField>
<ResponseField name="side" type="Side">
The side of the book to query. One of: `BUY`, `SELL`
</ResponseField>
<ResponseField name="returns" type="OrderBookSummary[]">
Array of OrderBookSummary objects. See `getOrderBook()` for the full structure.
</ResponseField>
***
### getPrice
Get the current best price for buying or selling a token ID.
```typescript Signature theme={null}
async getPrice(
tokenID: string,
side: "BUY" | "SELL"
): Promise<any>
```
<ResponseField name="price" type="string">
The current best price for the requested side.
</ResponseField>
***
### getPrices
Get the current best prices for multiple token IDs.
```typescript Signature theme={null}
async getPrices(params: BookParams[]): Promise<PricesResponse>
```
<ResponseField name="returns" type="PricesResponse">
A map of token IDs to their prices. Each entry contains an optional `BUY` (string) and/or `SELL` (string) price.
</ResponseField>
***
### getMidpoint
Get the midpoint price (average of best bid and best ask) for a token ID.
```typescript Signature theme={null}
async getMidpoint(tokenID: string): Promise<any>
```
<ResponseField name="mid" type="string">
The midpoint price, calculated as the average of best bid and best ask.
</ResponseField>
***
### getMidpoints
Get the midpoint prices for multiple token IDs.
```typescript Signature theme={null}
async getMidpoints(params: BookParams[]): Promise<any>
```
<ResponseField name="returns" type="object">
A map of token IDs to their midpoint price strings. Each key is a token ID and its value is the midpoint price as a string.
</ResponseField>
***
### getSpread
Get the spread (difference between best ask and best bid) for a token ID.
```typescript Signature theme={null}
async getSpread(tokenID: string): Promise<SpreadResponse>
```
<ResponseField name="spread" type="string">
The spread value, calculated as the difference between best ask and best bid.
</ResponseField>
***
### getSpreads
Get the spreads for multiple token IDs.
```typescript Signature theme={null}
async getSpreads(params: BookParams[]): Promise<SpreadsResponse>
```
<ResponseField name="returns" type="object">
A map of token IDs to their spread strings. Each key is a token ID and its value is the spread as a string.
</ResponseField>
***
### getPricesHistory
Get historical price data for a token.
```typescript Signature theme={null}
async getPricesHistory(params: PriceHistoryFilterParams): Promise<MarketPrice[]>
```
<ResponseField name="market" type="string">
The token ID to fetch price history for.
</ResponseField>
<ResponseField name="startTs" type="number">
Optional start timestamp (Unix seconds) for the price history range.
</ResponseField>
<ResponseField name="endTs" type="number">
Optional end timestamp (Unix seconds) for the price history range.
</ResponseField>
<ResponseField name="fidelity" type="number">
Optional fidelity/resolution of the price history data.
</ResponseField>
<ResponseField name="interval" type="PriceHistoryInterval">
Time interval for the price history. One of: `max`, `1w`, `1d`, `6h`, `1h`
</ResponseField>
<ResponseField name="t" type="number">
Unix timestamp of the price data point.
</ResponseField>
<ResponseField name="p" type="number">
Price value at the corresponding timestamp.
</ResponseField>
***
## Trades
***
### getLastTradePrice
Get the price of the most recent trade for a token.
```typescript Signature theme={null}
async getLastTradePrice(tokenID: string): Promise<LastTradePrice>
```
<ResponseField name="price" type="string">
The price of the most recent trade.
</ResponseField>
<ResponseField name="side" type="string">
The side of the most recent trade.
</ResponseField>
***
### getLastTradesPrices
Get the most recent trade prices for multiple tokens.
```typescript Signature theme={null}
async getLastTradesPrices(params: BookParams[]): Promise<LastTradePriceWithToken[]>
```
<ResponseField name="price" type="string">
The price of the most recent trade for the token.
</ResponseField>
<ResponseField name="side" type="string">
The side of the most recent trade.
</ResponseField>
<ResponseField name="token_id" type="string">
The token ID this trade price corresponds to.
</ResponseField>
***
### getMarketTradesEvents
Get recent trade events for a market.
```typescript Signature theme={null}
async getMarketTradesEvents(conditionID: string): Promise<MarketTradeEvent[]>
```
<ResponseField name="event_type" type="string">
The type of trade event.
</ResponseField>
<ResponseField name="market" type="object">
Object containing market info: `condition_id` (string), `asset_id` (string), `question` (string), `icon` (string), `slug` (string).
</ResponseField>
<ResponseField name="user" type="object">
Object containing user info: `address` (string), `username` (string), `profile_picture` (string), `optimized_profile_picture` (string), `pseudonym` (string).
</ResponseField>
<ResponseField name="side" type="Side">
The side of the trade. One of: `BUY`, `SELL`
</ResponseField>
<ResponseField name="size" type="string">
The size of the trade.
</ResponseField>
<ResponseField name="fee_rate_bps" type="string">
The fee rate in basis points for the trade.
</ResponseField>
<ResponseField name="price" type="string">
The price at which the trade was executed.
</ResponseField>
<ResponseField name="outcome" type="string">
The outcome label for the traded token.
</ResponseField>
<ResponseField name="outcome_index" type="number">
The index of the outcome in the market.
</ResponseField>
<ResponseField name="transaction_hash" type="string">
The on-chain transaction hash for the trade.
</ResponseField>
<ResponseField name="timestamp" type="string">
The timestamp of when the trade event occurred.
</ResponseField>
***
## Market Parameters
***
### getFeeRateBps
Get the fee rate in basis points for a token.
```typescript Signature theme={null}
async getFeeRateBps(tokenID: string): Promise<number>
```
<ResponseField name="returns" type="number">
The fee rate in basis points for the specified token.
</ResponseField>
***
### getTickSize
Get the tick size (minimum price increment) for a market.
```typescript Signature theme={null}
async getTickSize(tokenID: string): Promise<TickSize>
```
<ResponseField name="returns" type="string">
The tick size for the market. One of: `0.1`, `0.01`, `0.001`, `0.0001`
</ResponseField>
***
### getNegRisk
Check if a market uses negative risk (binary complementary tokens).
```typescript Signature theme={null}
async getNegRisk(tokenID: string): Promise<boolean>
```
<ResponseField name="returns" type="boolean">
Whether the market uses negative risk.
</ResponseField>
***
## Time and Server Info
### getServerTime
Get the current server timestamp.
```typescript Signature theme={null}
async getServerTime(): Promise<number>
```
<ResponseField name="returns" type="number">
Unix timestamp in seconds representing the current server time.
</ResponseField>
***
## See Also
<CardGroup cols={2}>
<Card title="L1 Methods" icon="key" href="/trading/clients/l1">
Private key authentication to create or derive API credentials.
</Card>
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place orders, cancel orders, and query your trades.
</Card>
<Card title="REST API Reference" icon="code" href="/api-reference/introduction">
Complete REST endpoint documentation.
</Card>
<Card title="WebSocket" icon="bolt" href="/market-data/websocket/overview">
Real-time market data streaming.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-207
View File
@@ -1,207 +0,0 @@
# Geographic Restrictions
> Check geographic restrictions before placing orders on the Polymarket API
Polymarket restricts order placement from certain geographic locations due to regulatory requirements and compliance with international sanctions. Before placing orders, builders should verify the location.
<Warning>
Orders submitted from blocked regions will be rejected. Implement geoblock
checks in your application to provide users with appropriate feedback before
they attempt to trade.
</Warning>
***
## Geoblock Endpoint
Check the geographic eligibility of the requesting IP address:
```bash theme={null}
GET https://polymarket.com/api/geoblock
```
<Note>This endpoint is on `polymarket.com`, not the API servers.</Note>
### Response
```json theme={null}
{
"blocked": true,
"ip": "203.0.113.42",
"country": "US",
"region": "NY"
}
```
| Field | Type | Description |
| --------- | ------- | ----------------------------------------------- |
| `blocked` | boolean | Whether the user is blocked from placing orders |
| `ip` | string | Detected IP address |
| `country` | string | ISO 3166-1 alpha-2 country code |
| `region` | string | Region/state code |
***
## Blocked Countries
The following countries are restricted from placing orders on Polymarket. Countries marked as **close-only** can close existing positions but cannot open new ones:
| Country Code | Country Name | Status |
| ------------ | ------------------------------------ | ---------- |
| AU | Australia | Blocked |
| BE | Belgium | Blocked |
| BY | Belarus | Blocked |
| BI | Burundi | Blocked |
| CF | Central African Republic | Blocked |
| CD | Congo (Kinshasa) | Blocked |
| CU | Cuba | Blocked |
| DE | Germany | Blocked |
| ET | Ethiopia | Blocked |
| FR | France | Blocked |
| GB | United Kingdom | Blocked |
| IR | Iran | Blocked |
| IQ | Iraq | Blocked |
| IT | Italy | Blocked |
| KP | North Korea | Blocked |
| LB | Lebanon | Blocked |
| LY | Libya | Blocked |
| MM | Myanmar | Blocked |
| NI | Nicaragua | Blocked |
| NL | Netherlands | Blocked |
| PL | Poland | Close-only |
| RU | Russia | Blocked |
| SG | Singapore | Close-only |
| SO | Somalia | Blocked |
| SS | South Sudan | Blocked |
| SD | Sudan | Blocked |
| SY | Syria | Blocked |
| TH | Thailand | Close-only |
| TW | Taiwan | Close-only |
| UM | United States Minor Outlying Islands | Blocked |
| US | United States | Blocked |
| VE | Venezuela | Blocked |
| YE | Yemen | Blocked |
| ZW | Zimbabwe | Blocked |
***
## Blocked Regions
In addition to fully blocked countries, the following specific regions within otherwise accessible countries are also restricted:
| Country | Region | Region Code |
| ------------ | ------- | ----------- |
| Canada (CA) | Ontario | ON |
| Ukraine (UA) | Crimea | 43 |
| Ukraine (UA) | Donetsk | 14 |
| Ukraine (UA) | Luhansk | 09 |
***
## Blocking Logic
The geoblocking system includes:
1. **OFAC-Sanctioned Countries**: Countries sanctioned by the U.S. Office of Foreign Assets Control (OFAC)
2. **Additional Regulatory Restrictions**: Countries added for specific regulatory compliance reasons
***
## Server Infrastructure
* **Primary Servers**: eu-west-2
* **Closest Non-Georestricted Region**: eu-west-1
***
## Usage Examples
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
interface GeoblockResponse {
blocked: boolean;
ip: string;
country: string;
region: string;
}
async function checkGeoblock(): Promise<GeoblockResponse> {
const response = await fetch("https://polymarket.com/api/geoblock");
return response.json();
}
// Usage
const geo = await checkGeoblock();
if (geo.blocked) {
console.log(`Trading not available in ${geo.country}`);
} else {
console.log("Trading available");
}
```
</Tab>
<Tab title="Python">
```python theme={null}
import requests
def check_geoblock() -> dict:
response = requests.get("https://polymarket.com/api/geoblock")
return response.json()
# Usage
geo = check_geoblock()
if geo["blocked"]:
print(f"Trading not available in {geo['country']}")
else:
print("Trading available")
```
</Tab>
<Tab title="Rust">
```rust theme={null}
use polymarket_client_sdk::clob::Client;
let client = Client::default();
let geo = client.check_geoblock().await?;
if geo.blocked {
println!("Trading not available in {}", geo.country);
} else {
println!("Trading available");
}
```
</Tab>
</Tabs>
***
## Why These Restrictions
Geographic restrictions are implemented to ensure compliance with:
* International sanctions and embargoes
* Local financial regulations
* Gambling and prediction market laws
* Anti-money laundering (AML) requirements
* Know Your Customer (KYC) regulations
If you believe you are incorrectly restricted or have questions about geographic availability, please contact [Polymarket Support](https://polymarket.com/support).
***
## Next Steps
<CardGroup cols={2}>
<Card title="Authentication" icon="key" href="/api-reference/authentication">
Learn how to authenticate trading requests.
</Card>
<Card title="Place Orders" icon="plus" href="/trading/quickstart">
Start placing orders (from eligible regions).
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-229
View File
@@ -1,229 +0,0 @@
# Overview
> Trading on the Polymarket CLOB
Polymarket's CLOB (Central Limit Order Book) is a hybrid-decentralized trading system — offchain order matching with onchain settlement via the [Exchange contract](https://github.com/Polymarket/ctf-exchange/tree/main/src) ([audited by Chainsecurity](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)). All trading is non-custodial. Orders are [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signed messages, and matched trades settle atomically on Polygon. The operator cannot set prices or execute unauthorized trades — users can always cancel orders onchain independently.
We recommend using the open-source SDK clients, which handle order signing, authentication, and submission:
<CardGroup cols={3}>
<Card title="TypeScript Client" icon="github" href="https://github.com/Polymarket/clob-client">
<p className="font-mono text-[0.8rem]">
npm install @polymarket/clob-client
</p>
</Card>
<Card title="Python Client" icon="github" href="https://github.com/Polymarket/py-clob-client">
<p className="font-mono text-[0.8rem]">pip install py-clob-client</p>
</Card>
<Card title="Rust Client" icon="github" href="https://github.com/Polymarket/rs-clob-client">
<p className="font-mono text-[0.8rem]">cargo add polymarket-client-sdk</p>
</Card>
</CardGroup>
<Info>
You can also use the REST API directly, but you'll need to manage [EIP-712
order
signing](https://github.com/Polymarket/clob-client/blob/main/src/signing/eip712.ts)
and [HMAC authentication
headers](https://github.com/Polymarket/clob-client/blob/main/src/signing/hmac.ts)
yourself. See [REST API Headers](#rest-api-headers) below.
</Info>
***
## Authentication
The CLOB uses two levels of authentication:
| Level | Method | Purpose |
| ------ | ------------------------------- | ----------------------------------------- |
| **L1** | EIP-712 signature (private key) | Create or derive API credentials |
| **L2** | HMAC-SHA256 (API credentials) | Place orders, cancel orders, query trades |
You use your private key once to derive **L2 credentials** (API key, secret, passphrase), which authenticate all subsequent trading requests.
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const signer = new Wallet(process.env.PRIVATE_KEY);
// Derive L2 API credentials
const tempClient = new ClobClient("https://clob.polymarket.com", 137, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
```
```python Python theme={null}
from py_clob_client.client import ClobClient
import os
private_key = os.getenv("PRIVATE_KEY")
# Derive L2 API credentials
temp_client = ClobClient("https://clob.polymarket.com", key=private_key, chain_id=137)
api_creds = temp_client.create_or_derive_api_creds()
```
```rust Rust theme={null}
use std::str::FromStr;
use polymarket_client_sdk::POLYGON;
use polymarket_client_sdk::auth::{LocalSigner, Signer};
use polymarket_client_sdk::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// Derive L2 API credentials and initialize client in one step
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
```
</CodeGroup>
***
## Signature Types
When initializing the trading client, you must specify your wallet's **signature type** and **funder address**:
| Wallet Type | ID | When to Use | Funder Address |
| ---------------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| **EOA** | `0` | Standalone wallet — you pay your own gas (POL for gas) | Your EOA wallet address |
| **POLY\_PROXY** | `1` | Polymarket account via Magic Link (email/Google login). Requires [exported private key](https://polymarket.com/settings) from Polymarket.com | Your proxy wallet address |
| **GNOSIS\_SAFE** | `2` | Polymarket account via browser wallet (MetaMask, Rabby) or embedded wallet (Privy, Turnkey). Most common type | Your proxy wallet address |
<Note>
If you have a Polymarket.com account, your funds are in a proxy wallet visible
in the profile dropdown. Use type `1` or `2`. Type `0` is for standalone EOA
wallets only.
</Note>
### Initialize the Trading Client
<CodeGroup>
```typescript TypeScript theme={null}
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
2, // GNOSIS_SAFE
"0x...", // Your proxy wallet address
);
```
```python Python theme={null}
client = ClobClient(
"https://clob.polymarket.com",
key=private_key,
chain_id=137,
creds=api_creds,
signature_type=2, # GNOSIS_SAFE
funder="0x..." # Your proxy wallet address
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::SignatureType;
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::GnosisSafe) // Funder auto-derived via CREATE2
.authenticate()
.await?;
```
</CodeGroup>
***
## REST API Headers
If you're using the REST API directly (without the SDK), you need to attach authentication headers to each request.
**L1 Headers** — for creating or deriving API credentials:
| Header | Description |
| ---------------- | ------------------- |
| `POLY_ADDRESS` | Your wallet address |
| `POLY_SIGNATURE` | EIP-712 signature |
| `POLY_TIMESTAMP` | Unix timestamp |
| `POLY_NONCE` | Request nonce |
**L2 Headers** — for all trading operations (orders, cancellations, queries):
| Header | Description |
| ----------------- | ------------------------------------ |
| `POLY_ADDRESS` | Your wallet address |
| `POLY_SIGNATURE` | HMAC-SHA256 signature of the request |
| `POLY_TIMESTAMP` | Unix timestamp |
| `POLY_API_KEY` | Your API key |
| `POLY_PASSPHRASE` | Your API passphrase |
<Note>
Even with L2 authentication, methods that create orders still require the
user's private key for EIP-712 order payload signing. L2 credentials
authenticate the request, but the order itself must be signed by the key.
</Note>
***
## Client Methods
<CardGroup cols={2}>
<Card title="Public Methods" icon="globe" href="/trading/clients/public">
Market data, orderbooks, prices, and spreads — no auth required.
</Card>
<Card title="L1 Methods" icon="key" href="/trading/clients/l1">
Sign orders and derive API credentials with your private key.
</Card>
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place orders, cancel orders, query trades, and manage notifications.
</Card>
<Card title="Builder Methods" icon="hammer" href="/trading/clients/builder">
Track attributed trades and manage builder credentials.
</Card>
</CardGroup>
***
## What Is in This Section
<CardGroup cols={2}>
<Card title="Quickstart" icon="bolt" href="/trading/quickstart">
Place your first order end-to-end
</Card>
<Card title="Orderbook" icon="chart-bar" href="/trading/orderbook">
Reading the orderbook, prices, spreads, and midpoints
</Card>
<Card title="Orders" icon="list-check" href="/trading/orders/create">
Order types, tick sizes, creating, cancelling, and querying orders
</Card>
<Card title="Fees" icon="receipt" href="/trading/fees">
Fee structure, fee-enabled markets, and maker rebates
</Card>
<Card title="Gasless Transactions" icon="gas-pump" href="/trading/gasless">
Execute onchain operations without paying gas
</Card>
<Card title="CTF Tokens" icon="coins" href="/trading/ctf/overview">
Split, merge, and redeem outcome tokens
</Card>
<Card title="Bridge" icon="bridge" href="/trading/bridge/deposit">
Deposit and withdraw funds across chains
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,399 +0,0 @@
# Cancel Order
> Cancel single, multiple, or all open orders
All cancel endpoints require [L2 authentication](/trading/overview#authentication). The response always includes `canceled` (list of cancelled order IDs) and `not_canceled` (map of order IDs to failure reasons).
***
## Cancel a Single Order
<CodeGroup>
```typescript TypeScript theme={null}
const resp = await client.cancelOrder("0xb816482a...");
console.log(resp);
// { canceled: ["0xb816482a..."], not_canceled: {} }
```
```python Python theme={null}
resp = client.cancel(order_id="0xb816482a...")
print(resp)
# {"canceled": ["0xb816482a..."], "not_canceled": {}}
```
```rust Rust theme={null}
let resp = client.cancel_order("0xb816482a...").await?;
println!("{:?}", resp);
// CancelOrdersResponse { canceled: ["0xb816482a..."], not_canceled: {} }
```
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/order" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '{"orderID": "0xb816482a..."}'
```
</CodeGroup>
***
## Cancel Multiple Orders
<CodeGroup>
```typescript TypeScript theme={null}
const resp = await client.cancelOrders(["0xb816482a...", "0xc927593b..."]);
```
```python Python theme={null}
resp = client.cancel_orders([
"0xb816482a...",
"0xc927593b...",
])
```
```rust Rust theme={null}
let resp = client.cancel_orders(&["0xb816482a...", "0xc927593b..."]).await?;
```
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/orders" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '["0xb816482a...", "0xc927593b..."]'
```
</CodeGroup>
***
## Cancel All Orders
Cancel every open order across all markets:
<CodeGroup>
```typescript TypeScript theme={null}
const resp = await client.cancelAll();
```
```python Python theme={null}
resp = client.cancel_all()
```
```rust Rust theme={null}
let resp = client.cancel_all_orders().await?;
```
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/cancel-all" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..."
```
</CodeGroup>
***
## Cancel by Market
Cancel all orders for a specific market, optionally filtered to a single token. Both `market` and `asset_id` are optional — omit both to cancel all orders.
<CodeGroup>
```typescript TypeScript theme={null}
const resp = await client.cancelMarketOrders({
market: "0xbd31dc8a...", // optional: condition ID
asset_id: "52114319501245...", // optional: specific token
});
```
```python Python theme={null}
resp = client.cancel_market_orders(
market="0xbd31dc8a...",
asset_id="52114319501245...", # optional
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::CancelMarketOrderRequest;
let request = CancelMarketOrderRequest::builder()
.market("0xbd31dc8a...".parse()?)
.asset_id("52114319501245...".parse()?)
.build();
let resp = client.cancel_market_orders(&request).await?;
```
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/cancel-market-orders" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '{"market": "0xbd31dc8a...", "asset_id": "52114319501245..."}'
```
</CodeGroup>
***
## 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"])
```
```rust Rust theme={null}
let order = client.order("0xb816482a...").await?;
println!("{:?} {}", order.status, order.size_matched);
```
</CodeGroup>
### Get Open Orders
Retrieve all open orders, optionally filtered by market or token:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by token
const tokenOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(market="0xbd31dc8a...")
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::OrdersRequest;
// All open orders
let orders = client.orders(&OrdersRequest::default(), None).await?;
// Filtered by market
let request = OrdersRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_orders = client.orders(&request, None).await?;
```
</CodeGroup>
### OpenOrder Object
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Condition ID |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Size at placement |
| `size_matched` | string | Amount filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `associate_trades` | string\[] | Trade IDs this order has been included in |
| `expiration` | string | Unix expiration timestamp (`0` if none) |
| `created_at` | string | Unix creation timestamp |
***
## Trade History
When an order is matched, it creates a trade. Trades progress through these statuses:
| Status | Terminal | Description |
| ----------- | -------- | --------------------------------------- |
| `MATCHED` | No | Matched and sent for onchain submission |
| `MINED` | No | Mined on the chain, no finality yet |
| `CONFIRMED` | Yes | Achieved finality — trade successful |
| `RETRYING` | No | Transaction failed — being retried |
| `FAILED` | Yes | Failed permanently |
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
trades = client.get_trades()
market_trades = client.get_trades(
TradeParams(market="0xbd31dc8a...")
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::TradesRequest;
// All trades
let trades = client.trades(&TradesRequest::default(), None).await?;
// Filtered by market
let request = TradesRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_trades = client.trades(&request, None).await?;
```
</CodeGroup>
Additional filter parameters: `id`, `maker_address`, `asset_id`, `before`, `after`.
The Rust SDK uses cursor-based pagination via the `next_cursor` parameter:
<CodeGroup>
```typescript TypeScript theme={null}
const page = await client.getTradesPaginated({ market: "0xbd31dc8a..." });
console.log(page.trades, page.count); // trades array + total count
```
```python Python theme={null}
page = client.get_trades_paginated(TradeParams(market="0xbd31dc8a..."))
```
```rust Rust theme={null}
// First page
let page = client.trades(&request, None).await?;
println!("{} trades, cursor: {}", page.data.len(), page.next_cursor);
// Next page
let page2 = client.trades(&request, Some(page.next_cursor)).await?;
```
</CodeGroup>
### Trade Object
| Field | Type | Description |
| ------------------ | ------------- | ------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order hash |
| `market` | string | Condition ID |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `price` | string | Execution price |
| `fee_rate_bps` | string | Fee rate in basis points |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when matched |
| `last_update` | string | Unix timestamp of last status change |
| `outcome` | string | Human-readable outcome (e.g., "Yes") |
| `maker_address` | string | Maker's funder address |
| `owner` | string | API key of the trade owner |
| `transaction_hash` | string | Onchain transaction hash |
| `bucket_index` | number | Index for trade reconciliation |
| `trader_side` | string | `TAKER` or `MAKER` |
| `maker_orders` | MakerOrder\[] | Maker orders that filled this trade |
<Note>
A single trade can be split across multiple onchain transactions due to gas
limits. Use `bucket_index` and `match_time` to reconcile related transactions
back to a single logical trade.
</Note>
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
// Multiple orders
const batch = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.clob_types import OrderScoringParams, OrdersScoringParams
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
batch = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
```
```rust Rust theme={null}
// Single order
let scoring = client.is_order_scoring("0x...").await?;
// Multiple orders
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
```
</CodeGroup>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
<Card title="Fees" icon="receipt" href="/trading/fees">
Understand fee structures and maker rebates
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,540 +0,0 @@
# Overview
> Order types, tick sizes, and querying orders
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) 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"
```
```rust Rust theme={null}
let resp = client.tick_size(token_id).await?;
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
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
}
)
```
```rust Rust theme={null}
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
// The order builder fetches neg_risk and uses the correct exchange contract.
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
```rust Rust theme={null}
let is_neg_risk = client.neg_risk(token_id).await?;
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **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). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
```rust Rust theme={null}
let order = client.order("0xb816482a...").await?;
println!("{order:?}");
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::OrdersRequest;
// All open orders
let orders = client.orders(&OrdersRequest::default(), None).await?;
// Filtered by market
let request = OrdersRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_orders = client.orders(&request, None).await?;
// Filtered by asset
let request = OrdersRequest::builder()
.asset_id("52114319501245...".parse()?)
.build();
let asset_orders = client.orders(&request, None).await?;
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::TradesRequest;
// All trades
let trades = client.trades(&TradesRequest::default(), None).await?;
// Filtered by market
let request = TradesRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_trades = client.trades(&request, None).await?;
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
```rust Rust theme={null}
// With the `heartbeats` feature, auto-send in background:
Client::start_heartbeats(&mut client)?;
// Or manually:
let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.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..."])
)
```
```rust Rust theme={null}
// Single order
let scoring = client.is_order_scoring("0x...").await?;
println!("Scoring: {}", scoring.scoring);
// Multiple orders
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving 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>
Built with [Mintlify](https://mintlify.com).
@@ -1,692 +0,0 @@
# Create Order
> Build, sign, and submit orders
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
<Info>
The SDK handles EIP-712 signing and submission for you. If you prefer the REST
API directly, see [Authentication](/api-reference/authentication) for constructing the
required headers and the [API Reference](/api-reference/introduction) for full endpoint
documentation including the raw order object fields and request/response schemas.
</Info>
***
## Order Types
| Type | Behavior | Use Case |
| ------- | -------------------------------------------------------------------- | ------------------------------- |
| **GTC** | Good-Til-Cancelled — rests on the book until filled or cancelled | Default for limit orders |
| **GTD** | Good-Til-Date — active until a specified expiration time | Auto-expire before known events |
| **FOK** | Fill-Or-Kill — must fill immediately and entirely, or cancel | All-or-nothing market orders |
| **FAK** | Fill-And-Kill — fills what's available immediately, cancels the rest | Partial-fill market orders |
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
***
## Limit Orders
The simplest way to place a limit order — create, sign, and submit in one call:
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false,
},
OrderType.GTC,
);
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
```python Python theme={null}
from py_clob_client.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
)
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::Side;
use polymarket_client_sdk::types::dec;
let token_id = "TOKEN_ID".parse()?;
let order = client
.limit_order()
.token_id(token_id)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
println!("Order ID: {}", response.order_id);
println!("Status: {:?}", response.status);
```
</CodeGroup>
### Two-Step Sign Then Submit
For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic:
<CodeGroup>
```typescript TypeScript theme={null}
// Step 1: Create and sign locally
const signedOrder = await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{ tickSize: "0.01", negRisk: false },
);
// Step 2: Submit to the CLOB
const response = await client.postOrder(signedOrder, OrderType.GTC);
```
```python Python theme={null}
# Step 1: Create and sign locally
signed_order = client.create_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
}
)
# Step 2: Submit to the CLOB
response = client.post_order(signed_order, OrderType.GTC)
```
```rust Rust theme={null}
// Step 1: Create order (auto-fetches tick size, neg risk, fee rate)
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
// Step 2: Sign and submit separately
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
***
## GTD Orders
GTD orders auto-expire at a specified time. Useful for quoting around known events.
<CodeGroup>
```typescript TypeScript theme={null}
// Expire in 1 hour (+ 60s security threshold buffer)
const expiration = Math.floor(Date.now() / 1000) + 60 + 3600;
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
expiration,
},
{ tickSize: "0.01", negRisk: false },
OrderType.GTD,
);
```
```python Python theme={null}
import time
# Expire in 1 hour (+ 60s security threshold buffer)
expiration = int(time.time()) + 60 + 3600
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
expiration=expiration,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTD
)
```
```rust Rust theme={null}
use chrono::{TimeDelta, Utc};
use polymarket_client_sdk::clob::types::OrderType;
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.order_type(OrderType::GTD)
.expiration(Utc::now() + TimeDelta::hours(1))
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
<Note>
There is a security threshold of one minute on GTD expiration. To set an
effective lifetime of N seconds, use `now + 60 + N`. For example, for a
30-second effective lifetime, set the expiration to `now + 60 + 30`.
</Note>
***
## Market Orders
Market orders execute immediately against resting liquidity using FOK or FAK types:
<CodeGroup>
```typescript TypeScript theme={null}
import { Side, OrderType } from "@polymarket/clob-client";
// 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)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::{Amount, OrderType, Side};
let token_id = "TOKEN_ID".parse()?;
// FOK BUY: spend exactly $100 or cancel entirely
let buy = client
.market_order()
.token_id(token_id)
.amount(Amount::usdc(dec!(100))?)
.price(dec!(0.50)) // worst-price limit (slippage protection)
.side(Side::Buy)
.order_type(OrderType::FOK)
.build()
.await?;
let signed = client.sign(&signer, buy).await?;
client.post_order(signed).await?;
// FOK SELL: sell exactly 200 shares or cancel entirely
let sell = client
.market_order()
.token_id(token_id)
.amount(Amount::shares(dec!(200))?)
.price(dec!(0.45)) // worst-price limit (slippage protection)
.side(Side::Sell)
.order_type(OrderType::FOK)
.build()
.await?;
let signed = client.sign(&signer, sell).await?;
client.post_order(signed).await?;
```
</CodeGroup>
* **FOK** — fill entirely or cancel the whole order
* **FAK** — fill what's available, cancel the rest
The `price` field on market orders acts as a **worst-price limit** (slippage protection), not a target execution price.
### One-Step Market Order
For convenience, `createAndPostMarketOrder` handles creation, signing, and submission in one call:
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
amount: 100,
price: 0.5,
},
{ tickSize: "0.01", negRisk: false },
OrderType.FOK,
);
```
```python Python theme={null}
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,
)
```
```rust Rust theme={null}
let order = client
.market_order()
.token_id("TOKEN_ID".parse()?)
.amount(Amount::usdc(dec!(100))?)
.price(dec!(0.50))
.side(Side::Buy)
.order_type(OrderType::FOK)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
***
## Post-Only Orders
Post-only orders guarantee you're always the maker. If the order would match immediately (cross the spread), it's rejected instead of executed.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.postOrder(signedOrder, OrderType.GTC, true);
```
```python Python theme={null}
response = client.post_order(signed_order, OrderType.GTC, post_only=True)
```
```rust Rust theme={null}
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.post_only(true)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
* Only works with **GTC** and **GTD** order types
* Rejected if combined with FOK or FAK
***
## Batch Orders
Place up to **15 orders** in a single request:
<CodeGroup>
```typescript TypeScript theme={null}
import { OrderType, Side, PostOrdersArgs } from "@polymarket/clob-client";
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,
),
])
```
```rust Rust theme={null}
let token_id = "TOKEN_ID".parse()?;
let bid = client
.limit_order()
.token_id(token_id)
.price(dec!(0.48))
.size(dec!(500))
.side(Side::Buy)
.build()
.await?;
let ask = client
.limit_order()
.token_id(token_id)
.price(dec!(0.52))
.size(dec!(500))
.side(Side::Sell)
.build()
.await?;
let signed_bid = client.sign(&signer, bid).await?;
let signed_ask = client.sign(&signer, ask).await?;
let response = client.post_orders(vec![signed_bid, signed_ask]).await?;
```
</CodeGroup>
***
## Order Options
Every order requires two market-specific options: `tickSize` and `negRisk`. For details on signature types (`0` = EOA, `1` = POLY\_PROXY, `2` = GNOSIS\_SAFE), see [Authentication](/api-reference/authentication#signature-types-and-funder).
### Tick Sizes
Your order price must conform to the market's tick size, or the order is rejected.
| Tick Size | Precision | Example Prices |
| --------- | ---------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize("TOKEN_ID");
```
```python Python theme={null}
tick_size = client.get_tick_size("TOKEN_ID")
```
```rust Rust theme={null}
let token_id = "TOKEN_ID".parse()?;
let tick_size = client.tick_size(token_id).await?;
```
</CodeGroup>
### Negative Risk
Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets.
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk("TOKEN_ID");
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk("TOKEN_ID")
```
```rust Rust theme={null}
let token_id = "TOKEN_ID".parse()?;
let is_neg_risk = client.neg_risk(token_id).await?;
```
</CodeGroup>
<Tip>
Both values are also available on the market object: `minimum_tick_size` and
`neg_risk`. In Rust, the order builder auto-fetches both — you don't need to look them up manually.
</Tip>
***
## Prerequisites
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **BUY orders**: 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)
```
```rust Rust theme={null}
// With the `heartbeats` feature, the Rust SDK can auto-send heartbeats
// in a background task — no manual loop needed:
Client::start_heartbeats(&mut client)?;
// ... your trading logic ...
client.stop_heartbeats().await?;
// Or send manually:
let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
```
</CodeGroup>
* Include the most recent `heartbeat_id` in each request. Use an empty string for the first request.
* If you send an expired ID, the server responds with `400` and the correct ID. Update and retry.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Cancel Orders" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all open orders
</Card>
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-692
View File
@@ -1,692 +0,0 @@
# Create Order
> Build, sign, and submit orders
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
<Info>
The SDK handles EIP-712 signing and submission for you. If you prefer the REST
API directly, see [Authentication](/api-reference/authentication) for constructing the
required headers and the [API Reference](/api-reference/introduction) for full endpoint
documentation including the raw order object fields and request/response schemas.
</Info>
***
## Order Types
| Type | Behavior | Use Case |
| ------- | -------------------------------------------------------------------- | ------------------------------- |
| **GTC** | Good-Til-Cancelled — rests on the book until filled or cancelled | Default for limit orders |
| **GTD** | Good-Til-Date — active until a specified expiration time | Auto-expire before known events |
| **FOK** | Fill-Or-Kill — must fill immediately and entirely, or cancel | All-or-nothing market orders |
| **FAK** | Fill-And-Kill — fills what's available immediately, cancels the rest | Partial-fill market orders |
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
***
## Limit Orders
The simplest way to place a limit order — create, sign, and submit in one call:
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false,
},
OrderType.GTC,
);
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
```python Python theme={null}
from py_clob_client.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
)
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::Side;
use polymarket_client_sdk::types::dec;
let token_id = "TOKEN_ID".parse()?;
let order = client
.limit_order()
.token_id(token_id)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
println!("Order ID: {}", response.order_id);
println!("Status: {:?}", response.status);
```
</CodeGroup>
### Two-Step Sign Then Submit
For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic:
<CodeGroup>
```typescript TypeScript theme={null}
// Step 1: Create and sign locally
const signedOrder = await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{ tickSize: "0.01", negRisk: false },
);
// Step 2: Submit to the CLOB
const response = await client.postOrder(signedOrder, OrderType.GTC);
```
```python Python theme={null}
# Step 1: Create and sign locally
signed_order = client.create_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
}
)
# Step 2: Submit to the CLOB
response = client.post_order(signed_order, OrderType.GTC)
```
```rust Rust theme={null}
// Step 1: Create order (auto-fetches tick size, neg risk, fee rate)
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
// Step 2: Sign and submit separately
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
***
## GTD Orders
GTD orders auto-expire at a specified time. Useful for quoting around known events.
<CodeGroup>
```typescript TypeScript theme={null}
// Expire in 1 hour (+ 60s security threshold buffer)
const expiration = Math.floor(Date.now() / 1000) + 60 + 3600;
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
expiration,
},
{ tickSize: "0.01", negRisk: false },
OrderType.GTD,
);
```
```python Python theme={null}
import time
# Expire in 1 hour (+ 60s security threshold buffer)
expiration = int(time.time()) + 60 + 3600
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
expiration=expiration,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTD
)
```
```rust Rust theme={null}
use chrono::{TimeDelta, Utc};
use polymarket_client_sdk::clob::types::OrderType;
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.order_type(OrderType::GTD)
.expiration(Utc::now() + TimeDelta::hours(1))
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
<Note>
There is a security threshold of one minute on GTD expiration. To set an
effective lifetime of N seconds, use `now + 60 + N`. For example, for a
30-second effective lifetime, set the expiration to `now + 60 + 30`.
</Note>
***
## Market Orders
Market orders execute immediately against resting liquidity using FOK or FAK types:
<CodeGroup>
```typescript TypeScript theme={null}
import { Side, OrderType } from "@polymarket/clob-client";
// 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)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::{Amount, OrderType, Side};
let token_id = "TOKEN_ID".parse()?;
// FOK BUY: spend exactly $100 or cancel entirely
let buy = client
.market_order()
.token_id(token_id)
.amount(Amount::usdc(dec!(100))?)
.price(dec!(0.50)) // worst-price limit (slippage protection)
.side(Side::Buy)
.order_type(OrderType::FOK)
.build()
.await?;
let signed = client.sign(&signer, buy).await?;
client.post_order(signed).await?;
// FOK SELL: sell exactly 200 shares or cancel entirely
let sell = client
.market_order()
.token_id(token_id)
.amount(Amount::shares(dec!(200))?)
.price(dec!(0.45)) // worst-price limit (slippage protection)
.side(Side::Sell)
.order_type(OrderType::FOK)
.build()
.await?;
let signed = client.sign(&signer, sell).await?;
client.post_order(signed).await?;
```
</CodeGroup>
* **FOK** — fill entirely or cancel the whole order
* **FAK** — fill what's available, cancel the rest
The `price` field on market orders acts as a **worst-price limit** (slippage protection), not a target execution price.
### One-Step Market Order
For convenience, `createAndPostMarketOrder` handles creation, signing, and submission in one call:
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
amount: 100,
price: 0.5,
},
{ tickSize: "0.01", negRisk: false },
OrderType.FOK,
);
```
```python Python theme={null}
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,
)
```
```rust Rust theme={null}
let order = client
.market_order()
.token_id("TOKEN_ID".parse()?)
.amount(Amount::usdc(dec!(100))?)
.price(dec!(0.50))
.side(Side::Buy)
.order_type(OrderType::FOK)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
***
## Post-Only Orders
Post-only orders guarantee you're always the maker. If the order would match immediately (cross the spread), it's rejected instead of executed.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.postOrder(signedOrder, OrderType.GTC, true);
```
```python Python theme={null}
response = client.post_order(signed_order, OrderType.GTC, post_only=True)
```
```rust Rust theme={null}
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.post_only(true)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
* Only works with **GTC** and **GTD** order types
* Rejected if combined with FOK or FAK
***
## Batch Orders
Place up to **15 orders** in a single request:
<CodeGroup>
```typescript TypeScript theme={null}
import { OrderType, Side, PostOrdersArgs } from "@polymarket/clob-client";
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,
),
])
```
```rust Rust theme={null}
let token_id = "TOKEN_ID".parse()?;
let bid = client
.limit_order()
.token_id(token_id)
.price(dec!(0.48))
.size(dec!(500))
.side(Side::Buy)
.build()
.await?;
let ask = client
.limit_order()
.token_id(token_id)
.price(dec!(0.52))
.size(dec!(500))
.side(Side::Sell)
.build()
.await?;
let signed_bid = client.sign(&signer, bid).await?;
let signed_ask = client.sign(&signer, ask).await?;
let response = client.post_orders(vec![signed_bid, signed_ask]).await?;
```
</CodeGroup>
***
## Order Options
Every order requires two market-specific options: `tickSize` and `negRisk`. For details on signature types (`0` = EOA, `1` = POLY\_PROXY, `2` = GNOSIS\_SAFE), see [Authentication](/api-reference/authentication#signature-types-and-funder).
### Tick Sizes
Your order price must conform to the market's tick size, or the order is rejected.
| Tick Size | Precision | Example Prices |
| --------- | ---------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize("TOKEN_ID");
```
```python Python theme={null}
tick_size = client.get_tick_size("TOKEN_ID")
```
```rust Rust theme={null}
let token_id = "TOKEN_ID".parse()?;
let tick_size = client.tick_size(token_id).await?;
```
</CodeGroup>
### Negative Risk
Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets.
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk("TOKEN_ID");
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk("TOKEN_ID")
```
```rust Rust theme={null}
let token_id = "TOKEN_ID".parse()?;
let is_neg_risk = client.neg_risk(token_id).await?;
```
</CodeGroup>
<Tip>
Both values are also available on the market object: `minimum_tick_size` and
`neg_risk`. In Rust, the order builder auto-fetches both — you don't need to look them up manually.
</Tip>
***
## Prerequisites
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **BUY orders**: 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)
```
```rust Rust theme={null}
// With the `heartbeats` feature, the Rust SDK can auto-send heartbeats
// in a background task — no manual loop needed:
Client::start_heartbeats(&mut client)?;
// ... your trading logic ...
client.stop_heartbeats().await?;
// Or send manually:
let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
```
</CodeGroup>
* Include the most recent `heartbeat_id` in each request. Use an empty string for the first request.
* If you send an expired ID, the server responds with `400` and the correct ID. Update and retry.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Cancel Orders" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all open orders
</Card>
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,540 +0,0 @@
# Overview
> Order types, tick sizes, and querying orders
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) 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"
```
```rust Rust theme={null}
let resp = client.tick_size(token_id).await?;
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
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
}
)
```
```rust Rust theme={null}
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
// The order builder fetches neg_risk and uses the correct exchange contract.
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
```rust Rust theme={null}
let is_neg_risk = client.neg_risk(token_id).await?;
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **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). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
```rust Rust theme={null}
let order = client.order("0xb816482a...").await?;
println!("{order:?}");
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::OrdersRequest;
// All open orders
let orders = client.orders(&OrdersRequest::default(), None).await?;
// Filtered by market
let request = OrdersRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_orders = client.orders(&request, None).await?;
// Filtered by asset
let request = OrdersRequest::builder()
.asset_id("52114319501245...".parse()?)
.build();
let asset_orders = client.orders(&request, None).await?;
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::TradesRequest;
// All trades
let trades = client.trades(&TradesRequest::default(), None).await?;
// Filtered by market
let request = TradesRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_trades = client.trades(&request, None).await?;
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
```rust Rust theme={null}
// With the `heartbeats` feature, auto-send in background:
Client::start_heartbeats(&mut client)?;
// Or manually:
let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.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..."])
)
```
```rust Rust theme={null}
// Single order
let scoring = client.is_order_scoring("0x...").await?;
println!("Scoring: {}", scoring.scoring);
// Multiple orders
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving 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>
Built with [Mintlify](https://mintlify.com).
-540
View File
@@ -1,540 +0,0 @@
# Overview
> Order types, tick sizes, and querying orders
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) 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"
```
```rust Rust theme={null}
let resp = client.tick_size(token_id).await?;
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
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
}
)
```
```rust Rust theme={null}
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
// The order builder fetches neg_risk and uses the correct exchange contract.
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
```rust Rust theme={null}
let is_neg_risk = client.neg_risk(token_id).await?;
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **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). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
```rust Rust theme={null}
let order = client.order("0xb816482a...").await?;
println!("{order:?}");
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::OrdersRequest;
// All open orders
let orders = client.orders(&OrdersRequest::default(), None).await?;
// Filtered by market
let request = OrdersRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_orders = client.orders(&request, None).await?;
// Filtered by asset
let request = OrdersRequest::builder()
.asset_id("52114319501245...".parse()?)
.build();
let asset_orders = client.orders(&request, None).await?;
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::TradesRequest;
// All trades
let trades = client.trades(&TradesRequest::default(), None).await?;
// Filtered by market
let request = TradesRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_trades = client.trades(&request, None).await?;
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
```rust Rust theme={null}
// With the `heartbeats` feature, auto-send in background:
Client::start_heartbeats(&mut client)?;
// Or manually:
let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.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..."])
)
```
```rust Rust theme={null}
// Single order
let scoring = client.is_order_scoring("0x...").await?;
println!("Scoring: {}", scoring.scoring);
// Multiple orders
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving 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>
Built with [Mintlify](https://mintlify.com).
@@ -1,540 +0,0 @@
# Overview
> Order types, tick sizes, and querying orders
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) 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"
```
```rust Rust theme={null}
let resp = client.tick_size(token_id).await?;
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
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
}
)
```
```rust Rust theme={null}
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
// The order builder fetches neg_risk and uses the correct exchange contract.
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
```rust Rust theme={null}
let is_neg_risk = client.neg_risk(token_id).await?;
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **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). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
```rust Rust theme={null}
let order = client.order("0xb816482a...").await?;
println!("{order:?}");
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::OrdersRequest;
// All open orders
let orders = client.orders(&OrdersRequest::default(), None).await?;
// Filtered by market
let request = OrdersRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_orders = client.orders(&request, None).await?;
// Filtered by asset
let request = OrdersRequest::builder()
.asset_id("52114319501245...".parse()?)
.build();
let asset_orders = client.orders(&request, None).await?;
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::TradesRequest;
// All trades
let trades = client.trades(&TradesRequest::default(), None).await?;
// Filtered by market
let request = TradesRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_trades = client.trades(&request, None).await?;
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
```rust Rust theme={null}
// With the `heartbeats` feature, auto-send in background:
Client::start_heartbeats(&mut client)?;
// Or manually:
let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.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..."])
)
```
```rust Rust theme={null}
// Single order
let scoring = client.is_order_scoring("0x...").await?;
println!("Scoring: {}", scoring.scoring);
// Multiple orders
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving 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>
Built with [Mintlify](https://mintlify.com).
-540
View File
@@ -1,540 +0,0 @@
# Overview
> Order types, tick sizes, and querying orders
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) 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"
```
```rust Rust theme={null}
let resp = client.tick_size(token_id).await?;
// resp.minimum_tick_size: TickSize::Tenth | Hundredth | Thousandth | TenThousandth
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
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
}
)
```
```rust Rust theme={null}
// The Rust SDK auto-detects neg risk from the token ID — no flag needed.
// The order builder fetches neg_risk and uses the correct exchange contract.
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
```rust Rust theme={null}
let is_neg_risk = client.neg_risk(token_id).await?;
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **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). [Builder-authenticated](/trading/clients/builder) clients can also query orders attributed to their builder account using the same methods.
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
```rust Rust theme={null}
let order = client.order("0xb816482a...").await?;
println!("{order:?}");
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::OrdersRequest;
// All open orders
let orders = client.orders(&OrdersRequest::default(), None).await?;
// Filtered by market
let request = OrdersRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_orders = client.orders(&request, None).await?;
// Filtered by asset
let request = OrdersRequest::builder()
.asset_id("52114319501245...".parse()?)
.build();
let asset_orders = client.orders(&request, None).await?;
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::TradesRequest;
// All trades
let trades = client.trades(&TradesRequest::default(), None).await?;
// Filtered by market
let request = TradesRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_trades = client.trades(&request, None).await?;
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
```rust Rust theme={null}
// With the `heartbeats` feature, auto-send in background:
Client::start_heartbeats(&mut client)?;
// Or manually:
let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.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..."])
)
```
```rust Rust theme={null}
// Single order
let scoring = client.is_order_scoring("0x...").await?;
println!("Scoring: {}", scoring.scoring);
// Multiple orders
let batch = client.are_orders_scoring(&["0x...", "0x..."]).await?;
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving 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>
Built with [Mintlify](https://mintlify.com).
-283
View File
@@ -1,283 +0,0 @@
# Quickstart
> Place your first order on Polymarket
This guide walks you through placing an order on Polymarket end-to-end.
<Steps>
<Step title="Install the SDK">
<CodeGroup>
```bash TypeScript theme={null}
npm install @polymarket/clob-client ethers@5
```
```bash Python theme={null}
pip install py-clob-client
```
```bash Rust theme={null}
cargo add polymarket-client-sdk --features clob
```
</CodeGroup>
</Step>
<Step title="Set Up Your Client">
Derive your API credentials and initialize the trading client. This example uses an EOA wallet (type `0`) — your wallet pays its own gas and acts as the funder:
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const HOST = "https://clob.polymarket.com";
const CHAIN_ID = 137; // Polygon mainnet
const signer = new Wallet(process.env.PRIVATE_KEY);
// Derive API credentials
const tempClient = new ClobClient(HOST, CHAIN_ID, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
// Initialize trading client
const client = new ClobClient(
HOST,
CHAIN_ID,
signer,
apiCreds,
0, // EOA
signer.address,
);
```
```python Python theme={null}
from py_clob_client.client import ClobClient
import os
host = "https://clob.polymarket.com"
chain_id = 137 # Polygon mainnet
private_key = os.getenv("PRIVATE_KEY")
# Derive API credentials
temp_client = ClobClient(host, key=private_key, chain_id=chain_id)
api_creds = temp_client.create_or_derive_api_creds()
# Initialize trading client
client = ClobClient(
host,
key=private_key,
chain_id=chain_id,
creds=api_creds,
signature_type=0, # EOA
funder="YOUR_WALLET_ADDRESS"
)
```
```rust Rust theme={null}
use std::str::FromStr;
use polymarket_client_sdk::POLYGON;
use polymarket_client_sdk::auth::{LocalSigner, Signer};
use polymarket_client_sdk::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// Derive API credentials and initialize client (EOA by default)
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
```
</CodeGroup>
<Note>
If you have a Polymarket.com account, your funds are in a proxy wallet — use
signature type `1` or `2` instead. See [Signature
Types](/trading/overview#signature-types) for details.
</Note>
<Warning>
Before trading, your funder address needs **USDC.e** (for buying outcome
tokens) and **POL** (for gas, if using EOA type `0`). Proxy wallet users
(types `1` and `2`) can use Polymarket's gasless relayer instead.
</Warning>
</Step>
<Step title="Place an Order">
Get a token ID from the [Markets API](/market-data/fetching-markets), then create and submit your order:
<CodeGroup>
```typescript TypeScript theme={null}
import { Side, OrderType } from "@polymarket/clob-client";
const response = await client.createAndPostOrder(
{
tokenID: "YOUR_TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false, // Set to true for multi-outcome markets
},
OrderType.GTC,
);
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
```python Python theme={null}
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="YOUR_TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False, # Set to True for multi-outcome markets
},
order_type=OrderType.GTC
)
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::Side;
use polymarket_client_sdk::types::dec;
let token_id = "YOUR_TOKEN_ID".parse()?;
// Tick size and neg risk are auto-fetched by the order builder
let order = client
.limit_order()
.token_id(token_id)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed_order = client.sign(&signer, order).await?;
let response = client.post_order(signed_order).await?;
println!("Order ID: {}", response.order_id);
println!("Status: {:?}", response.status);
```
</CodeGroup>
<Tip>
Look up a market's `tickSize` and `negRisk` values using the SDK's
`getTickSize()` and `getNegRisk()` methods, or from the market object returned
by the API.
</Tip>
</Step>
<Step title="Check Your Orders">
<CodeGroup>
```typescript TypeScript theme={null}
// View all open orders
const openOrders = await client.getOpenOrders();
console.log(`You have ${openOrders.length} open orders`);
// View your trade history
const trades = await client.getTrades();
console.log(`You've made ${trades.length} trades`);
// Cancel an order
await client.cancelOrder(response.orderID);
```
```python Python theme={null}
# View all open orders
open_orders = client.get_orders()
print(f"You have {len(open_orders)} open orders")
# View your trade history
trades = client.get_trades()
print(f"You've made {len(trades)} trades")
# Cancel an order
client.cancel(order_id=response["orderID"])
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::{OrdersRequest, TradesRequest};
// View all open orders
let open_orders = client.orders(&OrdersRequest::default(), None).await?;
println!("You have {} open orders", open_orders.data.len());
// View your trade history
let trades = client.trades(&TradesRequest::default(), None).await?;
println!("You've made {} trades", trades.data.len());
// Cancel an order
client.cancel_order(&response.order_id).await?;
```
</CodeGroup>
</Step>
</Steps>
***
## Troubleshooting
<AccordionGroup>
<Accordion title="L2 AUTH NOT AVAILABLE - Invalid Signature">
Wrong private key, signature type, or funder address for the derived API credentials.
* Check that `signatureType` matches your account type (`0`, `1`, or `2`)
* Ensure `funder` is correct for your wallet type
* Re-derive credentials with `createOrDeriveApiKey()` if unsure
</Accordion>
<Accordion title="Order rejected - insufficient balance">
Your funder address doesn't have enough tokens:
* **BUY orders**: need USDC.e in your funder address
* **SELL orders**: need outcome tokens in your funder address
* Ensure you have more USDC.e than what's committed in open orders
</Accordion>
<Accordion title="Order rejected - insufficient allowance">
You need to approve the Exchange contract to spend your tokens. This is
typically done through the Polymarket UI on your first trade, or using the CTF
contract's `setApprovalForAll()` method.
</Accordion>
<Accordion title="What is my funder address">
Your funder address is the wallet where your funds are held:
* **EOA (type 0)**: Your wallet address directly
* **Proxy wallet (type 1 or 2)**: Go to [polymarket.com/settings](https://polymarket.com/settings) and look for the wallet address in the profile dropdown
If the proxy wallet doesn't exist, log into Polymarket.com first (it's deployed on first login).
</Accordion>
<Accordion title="Blocked by Cloudflare or Geoblock">
You're trying to place a trade from a restricted region. See [Geographic Restrictions](/api-reference/geoblock) for details.
</Accordion>
</AccordionGroup>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Create Orders" icon="plus" href="/trading/orders/create">
Order types, tick sizes, and error handling
</Card>
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
File diff suppressed because one or more lines are too long
-133
View File
@@ -1,133 +0,0 @@
# Get prices history
> Retrieve historical price data for a market.
## OpenAPI
````yaml /api-spec/clob-openapi.yaml get /prices-history
openapi: 3.1.0
info:
title: Polymarket CLOB API
description: Polymarket CLOB API Reference
license:
name: MIT
identifier: MIT
version: 1.0.0
servers:
- url: https://clob.polymarket.com
description: Production CLOB API
- url: https://clob-staging.polymarket.com
description: Staging CLOB API
security: []
tags:
- name: Trade
description: Trade endpoints
- name: Markets
description: Market data endpoints
- name: Account
description: Account and authentication endpoints
- name: Notifications
description: User notification endpoints
- name: Rewards
description: Rewards and earnings endpoints
- name: Rebates
description: Maker rebate endpoints
paths:
/prices-history:
get:
tags:
- Markets
summary: Get prices history
description: Retrieve historical price data for a market.
operationId: getPricesHistory
parameters:
- name: market
in: query
required: true
description: The market (asset id) to query.
schema:
type: string
- name: startTs
in: query
required: false
description: Filter by items after this unix timestamp.
schema:
type: number
format: double
- name: endTs
in: query
required: false
description: Filter by items before this unix timestamp.
schema:
type: number
format: double
- name: interval
in: query
required: false
description: Time interval for data aggregation.
schema:
type: string
enum:
- max
- all
- 1m
- 1w
- 1d
- 6h
- 1h
- name: fidelity
in: query
required: false
description: Accuracy of the data expressed in minutes. Default is 1 minute.
schema:
type: integer
responses:
'200':
description: Successful response with price history
content:
application/json:
schema:
$ref: '#/components/schemas/PricesHistoryResponse'
'400':
description: Bad Request - Missing or invalid query parameters
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
security: []
components:
schemas:
PricesHistoryResponse:
type: object
properties:
history:
type: array
items:
$ref: '#/components/schemas/MarketPrice'
ErrorResponse:
type: object
required:
- error
properties:
error:
type: string
description: Error message
MarketPrice:
type: object
properties:
t:
type: integer
format: uint32
p:
type: number
format: float
````
Built with [Mintlify](https://mintlify.com).
@@ -1,229 +0,0 @@
# Overview
> Trading on the Polymarket CLOB
Polymarket's CLOB (Central Limit Order Book) is a hybrid-decentralized trading system — offchain order matching with onchain settlement via the [Exchange contract](https://github.com/Polymarket/ctf-exchange/tree/main/src) ([audited by Chainsecurity](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)). All trading is non-custodial. Orders are [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signed messages, and matched trades settle atomically on Polygon. The operator cannot set prices or execute unauthorized trades — users can always cancel orders onchain independently.
We recommend using the open-source SDK clients, which handle order signing, authentication, and submission:
<CardGroup cols={3}>
<Card title="TypeScript Client" icon="github" href="https://github.com/Polymarket/clob-client">
<p className="font-mono text-[0.8rem]">
npm install @polymarket/clob-client
</p>
</Card>
<Card title="Python Client" icon="github" href="https://github.com/Polymarket/py-clob-client">
<p className="font-mono text-[0.8rem]">pip install py-clob-client</p>
</Card>
<Card title="Rust Client" icon="github" href="https://github.com/Polymarket/rs-clob-client">
<p className="font-mono text-[0.8rem]">cargo add polymarket-client-sdk</p>
</Card>
</CardGroup>
<Info>
You can also use the REST API directly, but you'll need to manage [EIP-712
order
signing](https://github.com/Polymarket/clob-client/blob/main/src/signing/eip712.ts)
and [HMAC authentication
headers](https://github.com/Polymarket/clob-client/blob/main/src/signing/hmac.ts)
yourself. See [REST API Headers](#rest-api-headers) below.
</Info>
***
## Authentication
The CLOB uses two levels of authentication:
| Level | Method | Purpose |
| ------ | ------------------------------- | ----------------------------------------- |
| **L1** | EIP-712 signature (private key) | Create or derive API credentials |
| **L2** | HMAC-SHA256 (API credentials) | Place orders, cancel orders, query trades |
You use your private key once to derive **L2 credentials** (API key, secret, passphrase), which authenticate all subsequent trading requests.
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const signer = new Wallet(process.env.PRIVATE_KEY);
// Derive L2 API credentials
const tempClient = new ClobClient("https://clob.polymarket.com", 137, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
```
```python Python theme={null}
from py_clob_client.client import ClobClient
import os
private_key = os.getenv("PRIVATE_KEY")
# Derive L2 API credentials
temp_client = ClobClient("https://clob.polymarket.com", key=private_key, chain_id=137)
api_creds = temp_client.create_or_derive_api_creds()
```
```rust Rust theme={null}
use std::str::FromStr;
use polymarket_client_sdk::POLYGON;
use polymarket_client_sdk::auth::{LocalSigner, Signer};
use polymarket_client_sdk::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// Derive L2 API credentials and initialize client in one step
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
```
</CodeGroup>
***
## Signature Types
When initializing the trading client, you must specify your wallet's **signature type** and **funder address**:
| Wallet Type | ID | When to Use | Funder Address |
| ---------------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| **EOA** | `0` | Standalone wallet — you pay your own gas (POL for gas) | Your EOA wallet address |
| **POLY\_PROXY** | `1` | Polymarket account via Magic Link (email/Google login). Requires [exported private key](https://polymarket.com/settings) from Polymarket.com | Your proxy wallet address |
| **GNOSIS\_SAFE** | `2` | Polymarket account via browser wallet (MetaMask, Rabby) or embedded wallet (Privy, Turnkey). Most common type | Your proxy wallet address |
<Note>
If you have a Polymarket.com account, your funds are in a proxy wallet visible
in the profile dropdown. Use type `1` or `2`. Type `0` is for standalone EOA
wallets only.
</Note>
### Initialize the Trading Client
<CodeGroup>
```typescript TypeScript theme={null}
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
2, // GNOSIS_SAFE
"0x...", // Your proxy wallet address
);
```
```python Python theme={null}
client = ClobClient(
"https://clob.polymarket.com",
key=private_key,
chain_id=137,
creds=api_creds,
signature_type=2, # GNOSIS_SAFE
funder="0x..." # Your proxy wallet address
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::SignatureType;
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::GnosisSafe) // Funder auto-derived via CREATE2
.authenticate()
.await?;
```
</CodeGroup>
***
## REST API Headers
If you're using the REST API directly (without the SDK), you need to attach authentication headers to each request.
**L1 Headers** — for creating or deriving API credentials:
| Header | Description |
| ---------------- | ------------------- |
| `POLY_ADDRESS` | Your wallet address |
| `POLY_SIGNATURE` | EIP-712 signature |
| `POLY_TIMESTAMP` | Unix timestamp |
| `POLY_NONCE` | Request nonce |
**L2 Headers** — for all trading operations (orders, cancellations, queries):
| Header | Description |
| ----------------- | ------------------------------------ |
| `POLY_ADDRESS` | Your wallet address |
| `POLY_SIGNATURE` | HMAC-SHA256 signature of the request |
| `POLY_TIMESTAMP` | Unix timestamp |
| `POLY_API_KEY` | Your API key |
| `POLY_PASSPHRASE` | Your API passphrase |
<Note>
Even with L2 authentication, methods that create orders still require the
user's private key for EIP-712 order payload signing. L2 credentials
authenticate the request, but the order itself must be signed by the key.
</Note>
***
## Client Methods
<CardGroup cols={2}>
<Card title="Public Methods" icon="globe" href="/trading/clients/public">
Market data, orderbooks, prices, and spreads — no auth required.
</Card>
<Card title="L1 Methods" icon="key" href="/trading/clients/l1">
Sign orders and derive API credentials with your private key.
</Card>
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place orders, cancel orders, query trades, and manage notifications.
</Card>
<Card title="Builder Methods" icon="hammer" href="/trading/clients/builder">
Track attributed trades and manage builder credentials.
</Card>
</CardGroup>
***
## What Is in This Section
<CardGroup cols={2}>
<Card title="Quickstart" icon="bolt" href="/trading/quickstart">
Place your first order end-to-end
</Card>
<Card title="Orderbook" icon="chart-bar" href="/trading/orderbook">
Reading the orderbook, prices, spreads, and midpoints
</Card>
<Card title="Orders" icon="list-check" href="/trading/orders/create">
Order types, tick sizes, creating, cancelling, and querying orders
</Card>
<Card title="Fees" icon="receipt" href="/trading/fees">
Fee structure, fee-enabled markets, and maker rebates
</Card>
<Card title="Gasless Transactions" icon="gas-pump" href="/trading/gasless">
Execute onchain operations without paying gas
</Card>
<Card title="CTF Tokens" icon="coins" href="/trading/ctf/overview">
Split, merge, and redeem outcome tokens
</Card>
<Card title="Bridge" icon="bridge" href="/trading/bridge/deposit">
Deposit and withdraw funds across chains
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-229
View File
@@ -1,229 +0,0 @@
# Overview
> Trading on the Polymarket CLOB
Polymarket's CLOB (Central Limit Order Book) is a hybrid-decentralized trading system — offchain order matching with onchain settlement via the [Exchange contract](https://github.com/Polymarket/ctf-exchange/tree/main/src) ([audited by Chainsecurity](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)). All trading is non-custodial. Orders are [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signed messages, and matched trades settle atomically on Polygon. The operator cannot set prices or execute unauthorized trades — users can always cancel orders onchain independently.
We recommend using the open-source SDK clients, which handle order signing, authentication, and submission:
<CardGroup cols={3}>
<Card title="TypeScript Client" icon="github" href="https://github.com/Polymarket/clob-client">
<p className="font-mono text-[0.8rem]">
npm install @polymarket/clob-client
</p>
</Card>
<Card title="Python Client" icon="github" href="https://github.com/Polymarket/py-clob-client">
<p className="font-mono text-[0.8rem]">pip install py-clob-client</p>
</Card>
<Card title="Rust Client" icon="github" href="https://github.com/Polymarket/rs-clob-client">
<p className="font-mono text-[0.8rem]">cargo add polymarket-client-sdk</p>
</Card>
</CardGroup>
<Info>
You can also use the REST API directly, but you'll need to manage [EIP-712
order
signing](https://github.com/Polymarket/clob-client/blob/main/src/signing/eip712.ts)
and [HMAC authentication
headers](https://github.com/Polymarket/clob-client/blob/main/src/signing/hmac.ts)
yourself. See [REST API Headers](#rest-api-headers) below.
</Info>
***
## Authentication
The CLOB uses two levels of authentication:
| Level | Method | Purpose |
| ------ | ------------------------------- | ----------------------------------------- |
| **L1** | EIP-712 signature (private key) | Create or derive API credentials |
| **L2** | HMAC-SHA256 (API credentials) | Place orders, cancel orders, query trades |
You use your private key once to derive **L2 credentials** (API key, secret, passphrase), which authenticate all subsequent trading requests.
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const signer = new Wallet(process.env.PRIVATE_KEY);
// Derive L2 API credentials
const tempClient = new ClobClient("https://clob.polymarket.com", 137, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
```
```python Python theme={null}
from py_clob_client.client import ClobClient
import os
private_key = os.getenv("PRIVATE_KEY")
# Derive L2 API credentials
temp_client = ClobClient("https://clob.polymarket.com", key=private_key, chain_id=137)
api_creds = temp_client.create_or_derive_api_creds()
```
```rust Rust theme={null}
use std::str::FromStr;
use polymarket_client_sdk::POLYGON;
use polymarket_client_sdk::auth::{LocalSigner, Signer};
use polymarket_client_sdk::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// Derive L2 API credentials and initialize client in one step
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
```
</CodeGroup>
***
## Signature Types
When initializing the trading client, you must specify your wallet's **signature type** and **funder address**:
| Wallet Type | ID | When to Use | Funder Address |
| ---------------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| **EOA** | `0` | Standalone wallet — you pay your own gas (POL for gas) | Your EOA wallet address |
| **POLY\_PROXY** | `1` | Polymarket account via Magic Link (email/Google login). Requires [exported private key](https://polymarket.com/settings) from Polymarket.com | Your proxy wallet address |
| **GNOSIS\_SAFE** | `2` | Polymarket account via browser wallet (MetaMask, Rabby) or embedded wallet (Privy, Turnkey). Most common type | Your proxy wallet address |
<Note>
If you have a Polymarket.com account, your funds are in a proxy wallet visible
in the profile dropdown. Use type `1` or `2`. Type `0` is for standalone EOA
wallets only.
</Note>
### Initialize the Trading Client
<CodeGroup>
```typescript TypeScript theme={null}
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
2, // GNOSIS_SAFE
"0x...", // Your proxy wallet address
);
```
```python Python theme={null}
client = ClobClient(
"https://clob.polymarket.com",
key=private_key,
chain_id=137,
creds=api_creds,
signature_type=2, # GNOSIS_SAFE
funder="0x..." # Your proxy wallet address
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::SignatureType;
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::GnosisSafe) // Funder auto-derived via CREATE2
.authenticate()
.await?;
```
</CodeGroup>
***
## REST API Headers
If you're using the REST API directly (without the SDK), you need to attach authentication headers to each request.
**L1 Headers** — for creating or deriving API credentials:
| Header | Description |
| ---------------- | ------------------- |
| `POLY_ADDRESS` | Your wallet address |
| `POLY_SIGNATURE` | EIP-712 signature |
| `POLY_TIMESTAMP` | Unix timestamp |
| `POLY_NONCE` | Request nonce |
**L2 Headers** — for all trading operations (orders, cancellations, queries):
| Header | Description |
| ----------------- | ------------------------------------ |
| `POLY_ADDRESS` | Your wallet address |
| `POLY_SIGNATURE` | HMAC-SHA256 signature of the request |
| `POLY_TIMESTAMP` | Unix timestamp |
| `POLY_API_KEY` | Your API key |
| `POLY_PASSPHRASE` | Your API passphrase |
<Note>
Even with L2 authentication, methods that create orders still require the
user's private key for EIP-712 order payload signing. L2 credentials
authenticate the request, but the order itself must be signed by the key.
</Note>
***
## Client Methods
<CardGroup cols={2}>
<Card title="Public Methods" icon="globe" href="/trading/clients/public">
Market data, orderbooks, prices, and spreads — no auth required.
</Card>
<Card title="L1 Methods" icon="key" href="/trading/clients/l1">
Sign orders and derive API credentials with your private key.
</Card>
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place orders, cancel orders, query trades, and manage notifications.
</Card>
<Card title="Builder Methods" icon="hammer" href="/trading/clients/builder">
Track attributed trades and manage builder credentials.
</Card>
</CardGroup>
***
## What Is in This Section
<CardGroup cols={2}>
<Card title="Quickstart" icon="bolt" href="/trading/quickstart">
Place your first order end-to-end
</Card>
<Card title="Orderbook" icon="chart-bar" href="/trading/orderbook">
Reading the orderbook, prices, spreads, and midpoints
</Card>
<Card title="Orders" icon="list-check" href="/trading/orders/create">
Order types, tick sizes, creating, cancelling, and querying orders
</Card>
<Card title="Fees" icon="receipt" href="/trading/fees">
Fee structure, fee-enabled markets, and maker rebates
</Card>
<Card title="Gasless Transactions" icon="gas-pump" href="/trading/gasless">
Execute onchain operations without paying gas
</Card>
<Card title="CTF Tokens" icon="coins" href="/trading/ctf/overview">
Split, merge, and redeem outcome tokens
</Card>
<Card title="Bridge" icon="bridge" href="/trading/bridge/deposit">
Deposit and withdraw funds across chains
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,233 +0,0 @@
# Market Channel
> Real-time orderbook, price, and trade data
Public channel for market data updates (level 2 price data). Subscribe with asset IDs to receive orderbook snapshots, price changes, trade executions, and market events.
## Endpoint
```
wss://ws-subscriptions-clob.polymarket.com/ws/market
```
## Subscription
```json theme={null}
{
"assets_ids": ["<token_id_1>", "<token_id_2>"],
"type": "market",
"custom_feature_enabled": true
}
```
Set `custom_feature_enabled: true` to receive `best_bid_ask`, `new_market`, and `market_resolved` events.
## Message Types
Each message includes an `event_type` field identifying the type.
### book
Emitted when first subscribed to a market and when there is a trade that affects the book.
```json theme={null}
{
"event_type": "book",
"asset_id": "65818619657568813474341868652308942079804919287380422192892211131408793125422",
"market": "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
"bids": [
{ "price": ".48", "size": "30" },
{ "price": ".49", "size": "20" },
{ "price": ".50", "size": "15" }
],
"asks": [
{ "price": ".52", "size": "25" },
{ "price": ".53", "size": "60" },
{ "price": ".54", "size": "10" }
],
"timestamp": "123456789000",
"hash": "0x0...."
}
```
### price\_change
Emitted when a new order is placed or an order is cancelled.
```json theme={null}
{
"market": "0x5f65177b394277fd294cd75650044e32ba009a95022d88a0c1d565897d72f8f1",
"price_changes": [
{
"asset_id": "71321045679252212594626385532706912750332728571942532289631379312455583992563",
"price": "0.5",
"size": "200",
"side": "BUY",
"hash": "56621a121a47ed9333273e21c83b660cff37ae50",
"best_bid": "0.5",
"best_ask": "1"
},
{
"asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
"price": "0.5",
"size": "200",
"side": "SELL",
"hash": "1895759e4df7a796bf4f1c5a5950b748306923e2",
"best_bid": "0",
"best_ask": "0.5"
}
],
"timestamp": "1757908892351",
"event_type": "price_change"
}
```
A `size` of `"0"` means the price level has been removed from the book.
### tick\_size\_change
Emitted when the minimum tick size of a market changes. This happens when the book's price reaches the limits: price > 0.96 or price \< 0.04.
```json theme={null}
{
"event_type": "tick_size_change",
"asset_id": "65818619657568813474341868652308942079804919287380422192892211131408793125422",
"market": "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
"old_tick_size": "0.01",
"new_tick_size": "0.001",
"timestamp": "100000000"
}
```
### last\_trade\_price
Emitted when a maker and taker order is matched, creating a trade event.
```json theme={null}
{
"asset_id": "114122071509644379678018727908709560226618148003371446110114509806601493071694",
"event_type": "last_trade_price",
"fee_rate_bps": "0",
"market": "0x6a67b9d828d53862160e470329ffea5246f338ecfffdf2cab45211ec578b0347",
"price": "0.456",
"side": "BUY",
"size": "219.217767",
"timestamp": "1750428146322"
}
```
### best\_bid\_ask
<Note>Requires `custom_feature_enabled: true`.</Note>
Emitted when the best bid or ask prices for a market change.
```json theme={null}
{
"event_type": "best_bid_ask",
"market": "0x0005c0d312de0be897668695bae9f32b624b4a1ae8b140c49f08447fcc74f442",
"asset_id": "85354956062430465315924116860125388538595433819574542752031640332592237464430",
"best_bid": "0.73",
"best_ask": "0.77",
"spread": "0.04",
"timestamp": "1766789469958"
}
```
### new\_market
<Note>Requires `custom_feature_enabled: true`.</Note>
Emitted when a new market is created.
The payload also includes market metadata fields such as `tags`,
`condition_id`, `active`, `clob_token_ids`, `sports_market_type`, `line`,
`game_start_time`, `order_price_min_tick_size`, `group_item_title`,
`taker_base_fee`, `fees_enabled`, and `fee_schedule`.
Where a `FeeSchedule` object is of the form:
| Name | Type | Description |
| ------------ | ------- | --------------------------------- |
| exponent | string | fee curve exponent |
| rate | string | fee rate |
| taker\_only | boolean | whether fee applies to taker only |
| rebate\_rate | string | maker rebate rate |
```json theme={null}
{
"id": "1031769",
"question": "Will NVIDIA (NVDA) close above $240 end of January?",
"market": "0x311d0c4b6671ab54af4970c06fcf58662516f5168997bdda209ec3db5aa6b0c1",
"slug": "nvda-above-240-on-january-30-2026",
"description": "This market will resolve to \"Yes\" if the official closing price...",
"assets_ids": [
"76043073756653678226373981964075571318267289248134717369284518995922789326425",
"31690934263385727664202099278545688007799199447969475608906331829650099442770"
],
"outcomes": ["Yes", "No"],
"event_message": {
"id": "125819",
"ticker": "nvda-above-in-january-2026",
"slug": "nvda-above-in-january-2026",
"title": "Will NVIDIA (NVDA) close above ___ end of January?",
"description": "This market will resolve to \"Yes\" if the official closing price..."
},
"timestamp": "1766790415550",
"event_type": "new_market",
"tags": ["stocks"],
"condition_id": "0x311d0c4b6671ab54af4970c06fcf58662516f5168997bdda209ec3db5aa6b0c1",
"active": true,
"clob_token_ids": [
"76043073756653678226373981964075571318267289248134717369284518995922789326425",
"31690934263385727664202099278545688007799199447969475608906331829650099442770"
],
"sports_market_type": "",
"line": "",
"game_start_time": "",
"order_price_min_tick_size": "0.01",
"group_item_title": "NVDA above $240",
"taker_base_fee": "0",
"fees_enabled": true,
"fee_schedule": {
"exponent": "2",
"rate": "0.02",
"taker_only": true,
"rebate_rate": "0"
}
}
```
### market\_resolved
<Note>Requires `custom_feature_enabled: true`.</Note>
Emitted when a market is resolved.
```json theme={null}
{
"id": "1031769",
"question": "Will NVIDIA (NVDA) close above $240 end of January?",
"market": "0x311d0c4b6671ab54af4970c06fcf58662516f5168997bdda209ec3db5aa6b0c1",
"slug": "nvda-above-240-on-january-30-2026",
"description": "This market will resolve to \"Yes\" if the official closing price...",
"assets_ids": [
"76043073756653678226373981964075571318267289248134717369284518995922789326425",
"31690934263385727664202099278545688007799199447969475608906331829650099442770"
],
"outcomes": ["Yes", "No"],
"winning_asset_id": "76043073756653678226373981964075571318267289248134717369284518995922789326425",
"winning_outcome": "Yes",
"event_message": {
"id": "125819",
"ticker": "nvda-above-in-january-2026",
"slug": "nvda-above-in-january-2026",
"title": "Will NVIDIA (NVDA) close above ___ end of January?",
"description": "This market will resolve to \"Yes\" if the official closing price..."
},
"timestamp": "1766790415550",
"event_type": "market_resolved"
}
```
Built with [Mintlify](https://mintlify.com).
@@ -1,122 +0,0 @@
# User Channel
> Authenticated order and trade updates
Authenticated channel for updates related to your orders and trades, filtered by API key.
## Endpoint
```
wss://ws-subscriptions-clob.polymarket.com/ws/user
```
## Authentication
Include API credentials in your subscription message:
```json theme={null}
{
"auth": {
"apiKey": "your-api-key",
"secret": "your-api-secret",
"passphrase": "your-passphrase"
},
"markets": ["0x1234...condition_id"],
"type": "user"
}
```
<Warning>
Never expose your API credentials in client-side code. Use the user channel
only from server environments.
</Warning>
## Message Types
Each message includes a `type` field identifying the event.
### trade
Emitted when:
* A market order is matched (`MATCHED`)
* A limit order for the user is included in a trade (`MATCHED`)
* Subsequent status changes for the trade (`MINED`, `CONFIRMED`, `RETRYING`, `FAILED`)
```json theme={null}
{
"asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
"event_type": "trade",
"id": "28c4d2eb-bbea-40e7-a9f0-b2fdb56b2c2e",
"last_update": "1672290701",
"maker_orders": [
{
"asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
"matched_amount": "10",
"order_id": "0xff354cd7ca7539dfa9c28d90943ab5779a4eac34b9b37a757d7b32bdfb11790b",
"outcome": "YES",
"owner": "9180014b-33c8-9240-a14b-bdca11c0a465",
"price": "0.57"
}
],
"market": "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
"matchtime": "1672290701",
"outcome": "YES",
"owner": "9180014b-33c8-9240-a14b-bdca11c0a465",
"price": "0.57",
"side": "BUY",
"size": "10",
"status": "MATCHED",
"taker_order_id": "0x06bc63e346ed4ceddce9efd6b3af37c8f8f440c92fe7da6b2d0f9e4ccbc50c42",
"timestamp": "1672290701",
"trade_owner": "9180014b-33c8-9240-a14b-bdca11c0a465",
"type": "TRADE"
}
```
#### Trade Statuses
```
MATCHED → MINED → CONFIRMED
↓ ↑
RETRYING ───┘
FAILED
```
| Status | Terminal | Description |
| ----------- | -------- | ----------------------------------------------------------------------------------------------- |
| `MATCHED` | No | Trade has been matched and sent to the executor service by the operator |
| `MINED` | No | Trade observed to be mined into the chain, no finality threshold established |
| `CONFIRMED` | Yes | Trade has achieved strong probabilistic finality and was successful |
| `RETRYING` | No | Trade transaction has failed (revert or reorg) and is being retried/resubmitted by the operator |
| `FAILED` | Yes | Trade has failed and is not being retried |
### order
Emitted when:
* An order is placed (`PLACEMENT`)
* An order is updated — some of it is matched (`UPDATE`)
* An order is cancelled (`CANCELLATION`)
```json theme={null}
{
"asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
"associate_trades": null,
"event_type": "order",
"id": "0xff354cd7ca7539dfa9c28d90943ab5779a4eac34b9b37a757d7b32bdfb11790b",
"market": "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
"order_owner": "9180014b-33c8-9240-a14b-bdca11c0a465",
"original_size": "10",
"outcome": "YES",
"owner": "9180014b-33c8-9240-a14b-bdca11c0a465",
"price": "0.57",
"side": "SELL",
"size_matched": "0",
"timestamp": "1672290687",
"type": "PLACEMENT"
}
```
Built with [Mintlify](https://mintlify.com).
-179
View File
@@ -1,179 +0,0 @@
# Overview
> Real-time market data and trading updates via WebSocket
Polymarket provides WebSocket channels for near real-time streaming of orderbook data, trades, and personal order activity. There are four available channels: `market`, `user`, `sports`, and `RTDS` (Real-Time Data Socket).
## Channels
| Channel | Endpoint | Auth |
| ----------------------------------- | ------------------------------------------------------ | -------- |
| Market | `wss://ws-subscriptions-clob.polymarket.com/ws/market` | No |
| User | `wss://ws-subscriptions-clob.polymarket.com/ws/user` | Yes |
| Sports | `wss://sports-api.polymarket.com/ws` | No |
| [RTDS](/market-data/websocket/rtds) | `wss://ws-live-data.polymarket.com` | Optional |
### Market Channel
| Type | Description | Custom Feature |
| ------------------ | ----------------------- | -------------- |
| `book` | Full orderbook snapshot | No |
| `price_change` | Price level updates | No |
| `tick_size_change` | Tick size changes | No |
| `last_trade_price` | Trade executions | No |
| `best_bid_ask` | Best prices update | Yes |
| `new_market` | New market created | Yes |
| `market_resolved` | Market resolution | Yes |
Types marked "Custom Feature" require `custom_feature_enabled: true` in your subscription.
### User Channel
| Type | Description |
| ------- | --------------------------------------------- |
| `trade` | Trade lifecycle updates (MATCHED → CONFIRMED) |
| `order` | Order placements, updates, and cancellations |
### Sports
| Type | Description |
| -------------- | ------------------------------------- |
| `sport_result` | Live game scores, periods, and status |
## Subscribing
Send a subscription message after connecting to specify which data you want to receive.
### Market Channel
```json theme={null}
{
"assets_ids": [
"21742633143463906290569050155826241533067272736897614950488156847949938836455",
"48331043336612883890938759509493159234755048973500640148014422747788308965732"
],
"type": "market",
"custom_feature_enabled": true
}
```
| Field | Type | Description |
| ------------------------ | --------- | ----------------------------------------------------------------- |
| `assets_ids` | string\[] | Token IDs to subscribe to |
| `type` | string | Channel identifier |
| `custom_feature_enabled` | boolean | Enable `best_bid_ask`, `new_market`, and `market_resolved` events |
### User Channel
```json theme={null}
{
"auth": {
"apiKey": "your-api-key",
"secret": "your-api-secret",
"passphrase": "your-passphrase"
},
"markets": ["0x1234...condition_id"],
"type": "user"
}
```
<Note>
The `auth` fields (`apiKey`, `secret`, `passphrase`) are **only required for
the user channel**. For the market channel, these fields are optional and can
be omitted.
</Note>
| Field | Type | Description |
| --------- | --------- | -------------------------------------------------- |
| `auth` | object | API credentials (`apiKey`, `secret`, `passphrase`) |
| `markets` | string\[] | Condition IDs to receive events for |
| `type` | string | Channel identifier |
<Note>
The user channel subscribes by **condition IDs** (market identifiers), not
asset IDs. Each market has one condition ID but two asset IDs (Yes and No
tokens).
</Note>
### Sports Channel
No subscription message required. Connect and start receiving data for all active sports events.
## Dynamic Subscription
Modify subscriptions without reconnecting.
### Subscribe to more assets
```json theme={null}
{
"assets_ids": ["new_asset_id_1", "new_asset_id_2"],
"operation": "subscribe",
"custom_feature_enabled": true
}
```
### Unsubscribe from assets
```json theme={null}
{
"assets_ids": ["asset_id_to_remove"],
"operation": "unsubscribe"
}
```
For the user channel, use `markets` instead of `assets_ids`:
```json theme={null}
{
"markets": ["0x1234...condition_id"],
"operation": "subscribe"
}
```
## Heartbeats
### Market and User Channels
Send `PING` every 10 seconds. The server responds with `PONG`.
```
PING
```
### Sports Channel
The server sends `ping` every 5 seconds. Respond with `pong` within 10 seconds.
```
pong
```
<Warning>
If you don't respond to the server's ping within 10 seconds, the connection
will be closed.
</Warning>
## Troubleshooting
<Accordion title="Connection closes immediately after opening">
Send a valid subscription message immediately after connecting. The server may
close connections that don't subscribe within a timeout period.
</Accordion>
<Accordion title="Connection drops after about 10 seconds">
You're not sending heartbeats. Send `PING` every 10 seconds for market/user
channels, or respond to server `ping` with `pong` for the sports channel.
</Accordion>
<Accordion title="Not receiving any messages">
1. Verify your asset IDs or condition IDs are correct 2. Check that the
markets are active (not resolved) 3. Set `custom_feature_enabled: true` if
expecting `best_bid_ask`, `new_market`, or `market_resolved` events
</Accordion>
<Accordion title="Authentication failed - user channel">
Verify your API credentials are correct and haven't expired.
</Accordion>
Built with [Mintlify](https://mintlify.com).
@@ -1,179 +0,0 @@
# Overview
> Real-time market data and trading updates via WebSocket
Polymarket provides WebSocket channels for near real-time streaming of orderbook data, trades, and personal order activity. There are four available channels: `market`, `user`, `sports`, and `RTDS` (Real-Time Data Socket).
## Channels
| Channel | Endpoint | Auth |
| ----------------------------------- | ------------------------------------------------------ | -------- |
| Market | `wss://ws-subscriptions-clob.polymarket.com/ws/market` | No |
| User | `wss://ws-subscriptions-clob.polymarket.com/ws/user` | Yes |
| Sports | `wss://sports-api.polymarket.com/ws` | No |
| [RTDS](/market-data/websocket/rtds) | `wss://ws-live-data.polymarket.com` | Optional |
### Market Channel
| Type | Description | Custom Feature |
| ------------------ | ----------------------- | -------------- |
| `book` | Full orderbook snapshot | No |
| `price_change` | Price level updates | No |
| `tick_size_change` | Tick size changes | No |
| `last_trade_price` | Trade executions | No |
| `best_bid_ask` | Best prices update | Yes |
| `new_market` | New market created | Yes |
| `market_resolved` | Market resolution | Yes |
Types marked "Custom Feature" require `custom_feature_enabled: true` in your subscription.
### User Channel
| Type | Description |
| ------- | --------------------------------------------- |
| `trade` | Trade lifecycle updates (MATCHED → CONFIRMED) |
| `order` | Order placements, updates, and cancellations |
### Sports
| Type | Description |
| -------------- | ------------------------------------- |
| `sport_result` | Live game scores, periods, and status |
## Subscribing
Send a subscription message after connecting to specify which data you want to receive.
### Market Channel
```json theme={null}
{
"assets_ids": [
"21742633143463906290569050155826241533067272736897614950488156847949938836455",
"48331043336612883890938759509493159234755048973500640148014422747788308965732"
],
"type": "market",
"custom_feature_enabled": true
}
```
| Field | Type | Description |
| ------------------------ | --------- | ----------------------------------------------------------------- |
| `assets_ids` | string\[] | Token IDs to subscribe to |
| `type` | string | Channel identifier |
| `custom_feature_enabled` | boolean | Enable `best_bid_ask`, `new_market`, and `market_resolved` events |
### User Channel
```json theme={null}
{
"auth": {
"apiKey": "your-api-key",
"secret": "your-api-secret",
"passphrase": "your-passphrase"
},
"markets": ["0x1234...condition_id"],
"type": "user"
}
```
<Note>
The `auth` fields (`apiKey`, `secret`, `passphrase`) are **only required for
the user channel**. For the market channel, these fields are optional and can
be omitted.
</Note>
| Field | Type | Description |
| --------- | --------- | -------------------------------------------------- |
| `auth` | object | API credentials (`apiKey`, `secret`, `passphrase`) |
| `markets` | string\[] | Condition IDs to receive events for |
| `type` | string | Channel identifier |
<Note>
The user channel subscribes by **condition IDs** (market identifiers), not
asset IDs. Each market has one condition ID but two asset IDs (Yes and No
tokens).
</Note>
### Sports Channel
No subscription message required. Connect and start receiving data for all active sports events.
## Dynamic Subscription
Modify subscriptions without reconnecting.
### Subscribe to more assets
```json theme={null}
{
"assets_ids": ["new_asset_id_1", "new_asset_id_2"],
"operation": "subscribe",
"custom_feature_enabled": true
}
```
### Unsubscribe from assets
```json theme={null}
{
"assets_ids": ["asset_id_to_remove"],
"operation": "unsubscribe"
}
```
For the user channel, use `markets` instead of `assets_ids`:
```json theme={null}
{
"markets": ["0x1234...condition_id"],
"operation": "subscribe"
}
```
## Heartbeats
### Market and User Channels
Send `PING` every 10 seconds. The server responds with `PONG`.
```
PING
```
### Sports Channel
The server sends `ping` every 5 seconds. Respond with `pong` within 10 seconds.
```
pong
```
<Warning>
If you don't respond to the server's ping within 10 seconds, the connection
will be closed.
</Warning>
## Troubleshooting
<Accordion title="Connection closes immediately after opening">
Send a valid subscription message immediately after connecting. The server may
close connections that don't subscribe within a timeout period.
</Accordion>
<Accordion title="Connection drops after about 10 seconds">
You're not sending heartbeats. Send `PING` every 10 seconds for market/user
channels, or respond to server `ping` with `pong` for the sports channel.
</Accordion>
<Accordion title="Not receiving any messages">
1. Verify your asset IDs or condition IDs are correct 2. Check that the
markets are active (not resolved) 3. Set `custom_feature_enabled: true` if
expecting `best_bid_ask`, `new_market`, or `market_resolved` events
</Accordion>
<Accordion title="Authentication failed - user channel">
Verify your API credentials are correct and haven't expired.
</Accordion>
Built with [Mintlify](https://mintlify.com).
-104
View File
@@ -1,104 +0,0 @@
# Contract Addresses
> All Polymarket smart contract addresses on Polygon
All Polymarket contracts are deployed on **Polygon mainnet** (Chain ID: 137). This is the single source of truth for all contract addresses used across the platform.
***
## Core Trading Contracts
| Contract | Address | Description |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| CTF Exchange | [`0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E`](https://polygonscan.com/address/0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E) | Standard market order matching and settlement |
| Neg Risk CTF Exchange | [`0xC5d563A36AE78145C45a50134d48A1215220f80a`](https://polygonscan.com/address/0xC5d563A36AE78145C45a50134d48A1215220f80a) | Order matching for [neg risk](/advanced/neg-risk) (multi-outcome) markets |
| Neg Risk Adapter | [`0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296`](https://polygonscan.com/address/0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296) | Converts No tokens between outcomes in neg risk markets |
| Conditional Tokens (CTF) | [`0x4D97DCd97eC945f40cF65F87097ACe5EA0476045`](https://polygonscan.com/address/0x4D97DCd97eC945f40cF65F87097ACe5EA0476045) | ERC1155 token storage — split, merge, and redeem operations |
***
## Token Contracts
| Contract | Address | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| USDC.e (Bridged USDC) | [`0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`](https://polygonscan.com/address/0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) | Collateral token used for all Polymarket trading (6 decimals) |
***
## Wallet Factory Contracts
| Contract | Address | Description |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| Gnosis Safe Factory | [`0xaacfeea03eb1561c4e67d661e40682bd20e3541b`](https://polygonscan.com/address/0xaacfeea03eb1561c4e67d661e40682bd20e3541b) | Deploys Safe wallets |
| Polymarket Proxy Factory | [`0xaB45c5A4B0c941a2F231C04C3f49182e1A254052`](https://polygonscan.com/address/0xaB45c5A4B0c941a2F231C04C3f49182e1A254052) | Deploys proxy wallets |
***
## Resolution Contracts
| Contract | Address | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| UMA Adapter | [`0x6A9D222616C90FcA5754cd1333cFD9b7fb6a4F74`](https://polygonscan.com/address/0x6A9D222616C90FcA5754cd1333cFD9b7fb6a4F74) | Adapter connecting Polymarket to the UMA Optimistic Oracle |
| UMA Optimistic Oracle | [`0xCB1822859cEF82Cd2Eb4E6276C7916e692995130`](https://polygonscan.com/address/0xCB1822859cEF82Cd2Eb4E6276C7916e692995130) | Handles market resolution proposals and disputes |
***
## Liquidity
| Contract | Address | Description |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| Uniswap v3 USDC.e/USDC Pool | [`0xd36ec33c8bed5a9f7b6630855f1533455b98a418`](https://polygonscan.com/address/0xd36ec33c8bed5a9f7b6630855f1533455b98a418) | Used for USDC.e ↔ USDC conversion during withdrawals |
***
## Source Code
<CardGroup cols={2}>
<Card title="CTF Exchange" icon="github" href="https://github.com/Polymarket/ctf-exchange">
Order matching and settlement contracts
</Card>
<Card title="Conditional Tokens" icon="github" href="https://github.com/gnosis/conditional-tokens-contracts">
Gnosis Conditional Token Framework (ERC1155)
</Card>
</CardGroup>
***
## Usage in Code
<CodeGroup>
```typescript TypeScript theme={null}
const ADDRESSES = {
USDC_E: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
CTF: "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045",
CTF_EXCHANGE: "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E",
NEG_RISK_CTF_EXCHANGE: "0xC5d563A36AE78145C45a50134d48A1215220f80a",
};
```
```python Python theme={null}
ADDRESSES = {
"USDC_E": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"CTF": "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045",
"CTF_EXCHANGE": "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E",
"NEG_RISK_CTF_EXCHANGE": "0xC5d563A36AE78145C45a50134d48A1215220f80a",
}
```
```rust Rust theme={null}
use polymarket_client_sdk::{POLYGON, contract_config};
// Addresses are built into the SDK — no hardcoding needed
let config = contract_config(POLYGON, false).expect("polygon config");
// config.exchange: 0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E
// config.collateral: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
// config.conditional_tokens: 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045
let neg_config = contract_config(POLYGON, true).expect("polygon neg risk config");
// neg_config.exchange: 0xC5d563A36AE78145C45a50134d48A1215220f80a
// neg_config.neg_risk_adapter: Some(0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296)
```
</CodeGroup>
Built with [Mintlify](https://mintlify.com).
-61
View File
@@ -1,61 +0,0 @@
# Merge Tokens
> Convert outcome token pairs back to USDC.e
**Merging** is the inverse of splitting — it converts a full set of outcome tokens back into USDC.e collateral. For every 1 Yes token and 1 No token you merge, you receive \$1 USDC.e. The condition must already be prepared on the CTF contract (via `prepareCondition`).
```
100 Yes tokens + 100 No tokens → $100 USDC.e
```
## Prerequisites
Before merging, you need:
1. **Equal amounts** of both Yes and No tokens
2. **Condition ID** of the market
3. **Sufficient gas** for the transaction
## How It Works
1. You call `mergePositions()` with the amount and market details
2. One unit of each position in a full set is burned in return for 1 collateral unit
3. The CTF contract releases USDC.e back to your wallet
The operation is atomic — if you don't have enough of both tokens, the transaction reverts.
## Function Parameters
<ResponseField name="collateralToken" type="IERC20">
USDC.e (Bridged USDC) contract address: `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`
</ResponseField>
<ResponseField name="parentCollectionId" type="bytes32">
Always `0x0000...0000` (32 zero bytes) for Polymarket markets
</ResponseField>
<ResponseField name="conditionId" type="bytes32">
The market's condition ID, available from the Markets API
</ResponseField>
<ResponseField name="partition" type="uint[]">
Array of index sets: `[1, 2]` for binary markets
</ResponseField>
<ResponseField name="amount" type="uint256">
The number of full sets to merge. Also the amount of collateral to receive.
</ResponseField>
## Next Steps
<CardGroup cols={2}>
<Card title="Redeem Tokens" icon="hand-holding-dollar" href="/trading/ctf/redeem">
Exchange winning tokens for USDC.e after resolution
</Card>
<Card title="CTF Overview" icon="book" href="/trading/ctf/overview">
Learn more about the Conditional Token Framework
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-138
View File
@@ -1,138 +0,0 @@
# Conditional Token Framework
> Onchain token mechanics powering Polymarket positions
All outcomes on Polymarket are tokenized using the **Conditional Token Framework (CTF)**, an open standard developed by Gnosis. Understanding CTF operations enables advanced trading strategies, market making, and direct smart contract interactions.
## What is CTF
The Conditional Token Framework creates **ERC1155 tokens** representing outcomes of prediction markets. Each binary market has two tokens:
| Token | Redeems for | Condition |
| ------- | ------------- | -------------------- |
| **Yes** | \$1.00 USDC.e | Event occurs |
| **No** | \$1.00 USDC.e | Event does not occur |
These tokens are always **fully collateralized** — every Yes/No pair is backed by exactly \$1.00 USDC.e locked in the CTF contract.
## Core Operations
CTF provides three fundamental operations:
<CardGroup cols={3}>
<Card title="Split" icon="scissors" href="/trading/ctf/split">
Convert USDC.e into Yes + No token pairs
</Card>
<Card title="Merge" icon="merge" href="/trading/ctf/merge">
Convert Yes + No pairs back to USDC.e
</Card>
<Card title="Redeem" icon="hand-holding-dollar" href="/trading/ctf/redeem">
Exchange winning tokens for USDC.e after resolution
</Card>
</CardGroup>
## Token Flow
<Frame>
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/token-flow.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=36f5a57946ac2b83136e17b6c06b358c" alt="" className="dark:hidden" width="1596" height="952" data-path="images/core-concepts/token-flow.png" />
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/token-flow.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=69d150ea49ffa18cd7f24689342b1bec" alt="" className="hidden dark:block" width="1596" height="952" data-path="images/dark/core-concepts/token-flow.png" />
</Frame>
## Token Identifiers
Each outcome token has a unique **position ID** (also called token ID or asset ID), computed onchain in three steps.
### Step 1 - Condition ID
```
getConditionId(oracle, questionId, outcomeSlotCount)
```
| Parameter | Type | Value |
| ------------------ | --------- | ---------------------------------------------------------------- |
| `oracle` | `address` | [UMA CTF Adapter](https://github.com/Polymarket/uma-ctf-adapter) |
| `questionId` | `bytes32` | Hash of the UMA ancillary data |
| `outcomeSlotCount` | `uint` | `2` for all binary markets |
### Step 2 - Collection IDs
```
getCollectionId(parentCollectionId, conditionId, indexSet)
```
| Parameter | Type | Value |
| -------------------- | --------- | --------------------------------------------------------------- |
| `parentCollectionId` | `bytes32` | `bytes32(0)` — always zero for top-level positions |
| `conditionId` | `bytes32` | The condition ID from step 1 |
| `indexSet` | `uint` | `1` (`0b01`) for the first outcome, `2` (`0b10`) for the second |
The `indexSet` is a bitmask denoting which outcome slots belong to a collection. It must be a nonempty proper subset of the condition's outcome slots. Binary markets always have exactly two collections — one per outcome.
### Step 3 - Position IDs
```
getPositionId(collateralToken, collectionId)
```
| Parameter | Type | Value |
| ----------------- | --------- | ----------------------------------------- |
| `collateralToken` | `IERC20` | USDC.e contract address on Polygon |
| `collectionId` | `bytes32` | One of the two collection IDs from step 2 |
The two resulting position IDs are the ERC1155 token IDs for the Yes and No outcomes of the market.
<Note>
You can look up token IDs directly via the Gamma API (`GET /markets` or `GET /events`
— the `tokens` array on each market contains both outcome token IDs). Computing them
manually is only necessary for direct smart contract integration.
</Note>
## Standard vs Neg Risk Markets
Polymarket has two market types with different CTF configurations:
| Feature | Standard Markets | Neg Risk Markets |
| ----------------- | ------------------- | --------------------- |
| CTF Contract | ConditionalTokens | ConditionalTokens |
| Exchange Contract | CTF Exchange | Neg Risk CTF Exchange |
| Multi-outcome | Independent markets | Linked via conversion |
| `negRisk` flag | `false` | `true` |
For neg risk markets, an additional **conversion** operation allows exchanging a No token for Yes tokens in all other outcomes. See [Negative Risk Markets](/advanced/neg-risk) for details.
## Contract Addresses
See [Contract Addresses](/resources/contract-addresses) for all Polymarket smart contract addresses on Polygon.
## Resources
<CardGroup cols={2}>
<Card title="CTF Source Code" icon="github" href="https://github.com/gnosis/conditional-tokens-contracts">
Gnosis Conditional Tokens smart contracts
</Card>
<Card title="Code Examples" icon="code" href="https://github.com/Polymarket/examples/tree/main/examples">
Python and TypeScript examples for onchain operations
</Card>
</CardGroup>
## Next Steps
<CardGroup cols={3}>
<Card title="Split Tokens" icon="scissors" href="/trading/ctf/split">
Create outcome token pairs from USDC.e
</Card>
<Card title="Merge Tokens" icon="merge" href="/trading/ctf/merge">
Convert token pairs back to USDC.e
</Card>
<Card title="Redeem Tokens" icon="hand-holding-dollar" href="/trading/ctf/redeem">
Collect winnings after resolution
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-92
View File
@@ -1,92 +0,0 @@
# Redeem Tokens
> Exchange winning tokens for USDC.e after market resolution
**Redeeming** converts winning outcome tokens into USDC.e after a market resolves. Each winning token is worth exactly $1.00 — the losing token is worth $0.
```
Market resolves YES:
100 Yes tokens → $100 USDC.e
100 No tokens → $0
```
## When to Redeem
Redemption is only available **after a market resolves**. Once the oracle reports the outcome:
* **Winning tokens** can be redeemed for \$1.00 USDC.e each
* **Losing tokens** are worth \$0 and produce no payout
<Note>
You can redeem at any time after resolution — there's no deadline. Your
winning tokens will always be redeemable.
</Note>
## How Resolution Works
1. The market's end condition is met (event occurs, date passes, etc.)
2. The UMA Adapter oracle reports the outcome via `reportPayouts()`
3. The CTF contract records the payout vector
4. Redemption becomes available for winning tokens
## Prerequisites
Before redeeming:
1. **Market must be resolved** — check the market's `resolved` status
2. **Hold winning tokens** — only the winning outcome can be redeemed
3. **Know the condition ID** — required for the redemption call
## Function Parameters
<ResponseField name="collateralToken" type="IERC20">
USDC.e (Bridged USDC) contract address: `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`
</ResponseField>
<ResponseField name="parentCollectionId" type="bytes32">
Always `0x0000...0000` (32 zero bytes) for Polymarket markets
</ResponseField>
<ResponseField name="conditionId" type="bytes32">
The market's condition ID
</ResponseField>
<ResponseField name="indexSets" type="uint[]">
Array of index sets to redeem: `[1, 2]` redeems both outcomes (only winning
pays)
</ResponseField>
<Note>
Redemption burns your entire token balance for the condition — there is no
amount parameter.
</Note>
## Payout Mechanics
The CTF uses a **payout vector** to determine redemption values:
| Outcome | Payout Vector | Redemption |
| -------- | ------------- | ----------------- |
| Yes wins | `[1, 0]` | Yes = $1, No = $0 |
| No wins | `[0, 1]` | Yes = $0, No = $1 |
When you call `redeemPositions()`:
* Your token balance is multiplied by the payout
* Winning tokens are burned
* USDC.e is transferred to your wallet
* Losing tokens are burned as well, but produce a \$0 payout
## Next Steps
<CardGroup cols={2}>
<Card title="CTF Overview" icon="book" href="/trading/ctf/overview">
Learn more about the Conditional Token Framework
</Card>
<Card title="Resolution Process" icon="gavel" href="/concepts/resolution">
Understand how markets are resolved
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-67
View File
@@ -1,67 +0,0 @@
# Split Tokens
> Convert USDC.e into outcome token pairs
**Splitting** converts USDC.e collateral into a full (position) set of outcome tokens. For every \$1 USDC.e you split, you receive 1 Yes token and 1 No token.
```
$100 USDC.e → 100 Yes tokens + 100 No tokens
```
## Prerequisites
Before splitting, ensure you have:
1. **USDC.e balance** on Polygon
2. **USDC.e approval** for the CTF contract to spend your tokens
3. **Condition ID** of the market — the condition must already be prepared on the CTF contract (via `prepareCondition`)
<Note>
If the partition is trivial, invalid, or refers to more slots than the
condition is prepared with, the transaction will revert.
</Note>
## How It Works
1. You approve the CTF contract to spend your USDC.e
2. You call `splitPosition()` with the amount and market details
3. The CTF contract transfers USDC.e from your wallet and mints both outcome tokens
The operation is atomic — if any step fails, the entire transaction reverts.
## Function Parameters
<ResponseField name="collateralToken" type="IERC20">
USDC.e (Bridged USDC) contract address: `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`
</ResponseField>
<ResponseField name="parentCollectionId" type="bytes32">
Always `0x0000...0000` (32 zero bytes) for Polymarket markets
</ResponseField>
<ResponseField name="conditionId" type="bytes32">
The market's condition ID, available from the Markets API
</ResponseField>
<ResponseField name="partition" type="uint[]">
Array of index sets: `[1, 2]` for binary markets (Yes = 1, No = 2)
</ResponseField>
<ResponseField name="amount" type="uint256">
The amount of collateral or stake to split. Also the number of full sets to
receive.
</ResponseField>
## Next Steps
<CardGroup cols={2}>
<Card title="Merge Tokens" icon="merge" href="/trading/ctf/merge">
Convert token pairs back to USDC.e
</Card>
<Card title="Trade on Orderbook" icon="chart-line" href="/trading/orders/create">
Place orders using your newly split tokens
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-552
View File
@@ -1,552 +0,0 @@
# Real-Time Data Socket
> Stream comments, crypto prices, and equity prices via WebSocket
The Polymarket Real-Time Data Socket (RTDS) is a WebSocket-based streaming service that provides real-time updates for **comments**, **crypto prices**, and **equity prices**.
<Card title="TypeScript client" icon="github" href="https://github.com/Polymarket/real-time-data-client">
Official RTDS TypeScript client (`real-time-data-client`).
</Card>
## Endpoint
```
wss://ws-live-data.polymarket.com
```
Some user-specific streams may require `gamma_auth` with your wallet address.
## Subscribing
Send a JSON message to subscribe to data streams:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "topic_name",
"type": "message_type",
"filters": "optional_filter_string",
"gamma_auth": {
"address": "wallet_address"
}
}
]
}
```
To unsubscribe, send the same structure with `"action": "unsubscribe"`.
Subscriptions can be added, removed, and modified without disconnecting. Send `PING` messages every 5 seconds to maintain the connection.
<Note>Only the subscription types documented below are supported.</Note>
## Message Structure
All messages follow this structure:
```json theme={null}
{
"topic": "string",
"type": "string",
"timestamp": "number",
"payload": "object"
}
```
| Field | Type | Description |
| ----------- | ------ | --------------------------------------------------------------------------- |
| `topic` | string | The subscription topic (e.g., `crypto_prices`, `equity_prices`, `comments`) |
| `type` | string | The message type/event (e.g., `update`, `reaction_created`) |
| `timestamp` | number | Unix timestamp in milliseconds when the message was sent |
| `payload` | object | Event-specific data object |
## Crypto Prices
Real-time cryptocurrency price data from two sources: **Binance** and **Chainlink**. No authentication required.
### Binance Source
Subscribe to all symbols:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices",
"type": "update"
}
]
}
```
Subscribe to specific symbols with a comma-separated filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices",
"type": "update",
"filters": "solusdt,btcusdt,ethusdt"
}
]
}
```
Symbols use lowercase concatenated format (e.g., `solusdt`, `btcusdt`).
**Solana price update:**
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "solusdt",
"timestamp": 1753314064213,
"value": 189.55
}
}
```
**Bitcoin price update:**
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btcusdt",
"timestamp": 1753314088395,
"value": 67234.50
}
}
```
### Chainlink Source
<Tip>
**Trading 15m Crypto Markets?** Get a sponsored Chainlink API key with onboarding support from Chainlink. Fill out [this form](https://pm-ds-request.streams.chain.link/).
</Tip>
Subscribe to all symbols:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices_chainlink",
"type": "*",
"filters": ""
}
]
}
```
Subscribe to a specific symbol with a JSON filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices_chainlink",
"type": "*",
"filters": "{\"symbol\":\"eth/usd\"}"
}
]
}
```
Symbols use slash-separated format (e.g., `eth/usd`, `btc/usd`).
**Ethereum price update:**
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "eth/usd",
"timestamp": 1753314064213,
"value": 3456.78
}
}
```
**Bitcoin price update:**
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btc/usd",
"timestamp": 1753314088395,
"value": 67234.50
}
}
```
### Price Payload Fields
| Field | Type | Description |
| ----------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `symbol` | string | Trading pair symbol. **Binance**: lowercase concatenated (e.g., `solusdt`, `btcusdt`). **Chainlink**: slash-separated (e.g., `eth/usd`, `btc/usd`) |
| `timestamp` | number | When the price was recorded, in Unix milliseconds |
| `value` | number | Current price value in the quote currency |
### Supported Symbols
**Binance Source** — lowercase concatenated format:
* `btcusdt` — Bitcoin to USDT
* `ethusdt` — Ethereum to USDT
* `solusdt` — Solana to USDT
* `xrpusdt` — XRP to USDT
**Chainlink Source** — slash-separated format:
* `btc/usd` — Bitcoin to USD
* `eth/usd` — Ethereum to USD
* `sol/usd` — Solana to USD
* `xrp/usd` — XRP to USD
## Equity Prices
Real-time price data for stocks, ETFs, forex pairs, precious metals, and commodities sourced from **Pyth Network**. No authentication required.
<Tip>
**Trading Equity Markets?** Get a Pyth Network data feed - first 30 days free, then \$99/month. [Subscribe here](https://buy.stripe.com/cNi8wPeiq76FgQrbsD4ZG09).
</Tip>
All asset classes stream through a single `equity_prices` topic. When you subscribe with a symbol filter, the server sends a historical snapshot (last 2 minutes of data), then continues streaming live updates.
### Subscribe
Subscribe to a specific symbol with a JSON filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "equity_prices",
"type": "update",
"filters": "{\"symbol\":\"AAPL\"}"
}
]
}
```
Subscribe to multiple symbols across asset classes:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"AAPL\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"EURUSD\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"XAUUSD\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"WTI\"}" }
]
}
```
Use `type: "*"` to receive all message types (live updates and snapshots):
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "equity_prices",
"type": "*",
"filters": "{\"symbol\":\"GOOGL\"}"
}
]
}
```
Filter values are case-insensitive on subscribe, but the `symbol` field in payloads is always returned lowercase.
<Tip>
**Need the price-to-beat value?** Pass the market slug to the price-to-beat endpoint:
`GET https://polymarket.com/api/equity/price-to-beat/{slug}`
Example: `https://polymarket.com/api/equity/price-to-beat/wti-up-or-down-on-april-7-2026`
</Tip>
### Live Price Update
**Apple stock update:**
```json theme={null}
{
"topic": "equity_prices",
"type": "update",
"timestamp": 1711382400000,
"payload": {
"symbol": "aapl",
"value": 198.45,
"full_accuracy_value": "198.4523",
"timestamp": 1711382400000,
"received_at": 1711382400005
}
}
```
**Gold price update (market closed):**
```json theme={null}
{
"topic": "equity_prices",
"type": "update",
"timestamp": 1711400000000,
"payload": {
"symbol": "xauusd",
"value": 2175.30,
"full_accuracy_value": "2175.3012",
"timestamp": 1711399000000,
"received_at": 1711400000002,
"is_carried_forward": true
}
}
```
### Historical Snapshot
On subscribe, the server delivers a backfill of the last 2 minutes of price data. Use the `type` field to distinguish: `"subscribe"` for the initial snapshot vs `"update"` for live ticks.
```json theme={null}
{
"topic": "equity_prices",
"type": "subscribe",
"timestamp": 1711382400000,
"payload": {
"symbol": "aapl",
"data": [
{ "timestamp": 1711382280000, "value": 198.30 },
{ "timestamp": 1711382281000, "value": 198.32 },
{ "timestamp": 1711382340000, "value": 198.41 }
]
}
}
```
### Equity Price Payload Fields
| Field | Type | Description |
| --------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| `symbol` | string | Lowercase symbol identifier (e.g., `aapl`, `eurusd`, `xauusd`) |
| `value` | number | Spot price as a float |
| `full_accuracy_value` | string | Full-precision price as a string |
| `timestamp` | number | Price measurement timestamp in Unix milliseconds |
| `received_at` | number | When the system received the price, in Unix milliseconds. Only present when non-zero. |
| `is_carried_forward` | boolean | `true` when the market session is closed and the value is the last known price. Only present when `true`. |
### Supported Symbols
**Stocks:**
| Symbol | Name |
| ------- | -------------- |
| `AAPL` | Apple |
| `TSLA` | Tesla |
| `MSFT` | Microsoft |
| `GOOGL` | Alphabet |
| `AMZN` | Amazon |
| `META` | Meta Platforms |
| `NVDA` | NVIDIA |
| `NFLX` | Netflix |
| `PLTR` | Palantir |
| `OPEN` | Opendoor |
| `RKLB` | Rocket Lab |
| `ABNB` | Airbnb |
| `COIN` | Coinbase |
| `HOOD` | Robinhood |
**ETFs:**
| Symbol | Name |
| ------ | ------------------------------------ |
| `QQQ` | Invesco QQQ ETF |
| `SPY` | S\&P 500 ETF |
| `EWY` | iShares MSCI South Korea ETF |
| `VXX` | Barclays iPath Series B S\&P 500 VIX |
**Forex:**
| Symbol | Pair |
| -------- | ---------------------------- |
| `EURUSD` | Euro / US Dollar |
| `GBPUSD` | British Pound / US Dollar |
| `USDCAD` | US Dollar / Canadian Dollar |
| `USDJPY` | US Dollar / Japanese Yen |
| `USDKRW` | US Dollar / South Korean Won |
**Precious Metals:**
| Symbol | Name |
| -------- | ------ |
| `XAUUSD` | Gold |
| `XAGUSD` | Silver |
**Commodities** (rolling front-month futures):
| Symbol | Name |
| ------ | --------------- |
| `WTI` | Crude Oil (WTI) |
| `CC` | Cocoa |
| `NGD` | Natural Gas |
### Market Hours
When a market session is closed, the stream continues with the last known price and `is_carried_forward: true`. This lets you distinguish stale prices from live ticks. Update frequency is sub-second (up to 5 per second per feed) during market hours.
## Comments
Real-time comment events on the Polymarket platform, including new comments, replies, reactions, and removals. May require Gamma authentication for user-specific data.
### Subscribe
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "comments",
"type": "comment_created"
}
]
}
```
### Message Types
| Type | Description |
| ------------------ | ------------------------------------- |
| `comment_created` | A user creates a new comment or reply |
| `comment_removed` | A comment is removed or deleted |
| `reaction_created` | A user adds a reaction to a comment |
| `reaction_removed` | A reaction is removed from a comment |
### comment\_created
Emitted when a user posts a new comment or replies to an existing one.
```json theme={null}
{
"topic": "comments",
"type": "comment_created",
"timestamp": 1753454975808,
"payload": {
"body": "That's a good point about the definition.",
"createdAt": "2025-07-25T14:49:35.801298Z",
"id": "1763355",
"parentCommentID": "1763325",
"parentEntityID": 18396,
"parentEntityType": "Event",
"profile": {
"baseAddress": "0xce533188d53a16ed580fd5121dedf166d3482677",
"displayUsernamePublic": true,
"name": "salted.caramel",
"proxyWallet": "0x4ca749dcfa93c87e5ee23e2d21ff4422c7a4c1ee",
"pseudonym": "Adored-Disparity"
},
"reactionCount": 0,
"replyAddress": "0x0bda5d16f76cd1d3485bcc7a44bc6fa7db004cdd",
"reportCount": 0,
"userAddress": "0xce533188d53a16ed580fd5121dedf166d3482677"
}
}
```
A reply to the above comment — note `parentCommentID` references the parent:
```json theme={null}
{
"topic": "comments",
"type": "comment_created",
"timestamp": 1753454985123,
"payload": {
"body": "I agree, the resolution criteria should be clearer.",
"createdAt": "2025-07-25T14:49:45.120000Z",
"id": "1763356",
"parentCommentID": "1763355",
"parentEntityID": 18396,
"parentEntityType": "Event",
"profile": {
"baseAddress": "0x1234567890abcdef1234567890abcdef12345678",
"displayUsernamePublic": true,
"name": "trader",
"proxyWallet": "0x9876543210fedcba9876543210fedcba98765432",
"pseudonym": "Bright-Analysis"
},
"reactionCount": 0,
"replyAddress": "0x0bda5d16f76cd1d3485bcc7a44bc6fa7db004cdd",
"reportCount": 0,
"userAddress": "0x1234567890abcdef1234567890abcdef12345678"
}
}
```
### Comment Payload Fields
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------------------- |
| `body` | string | The text content of the comment |
| `createdAt` | string | ISO 8601 timestamp when the comment was created |
| `id` | string | Unique identifier for this comment |
| `parentCommentID` | string | ID of the parent comment if this is a reply (null for top-level comments) |
| `parentEntityID` | number | ID of the parent entity (event, market, etc.) |
| `parentEntityType` | string | Type of parent entity (`Event`, `Market`) |
| `profile` | object | Profile information of the comment author |
| `reactionCount` | number | Current number of reactions on this comment |
| `replyAddress` | string | Polygon address for replies (may differ from userAddress) |
| `reportCount` | number | Current number of reports on this comment |
| `userAddress` | string | Polygon address of the comment author |
### Profile Object Fields
| Field | Type | Description |
| ----------------------- | ------- | ------------------------------------------ |
| `baseAddress` | string | User profile address |
| `displayUsernamePublic` | boolean | Whether the username is displayed publicly |
| `name` | string | User's display name |
| `proxyWallet` | string | Proxy wallet address used for transactions |
| `pseudonym` | string | Generated pseudonym for the user |
### Comment Hierarchy
Comments support nested threading:
* **Top-level comments**: `parentCommentID` is null or empty
* **Reply comments**: `parentCommentID` contains the ID of the parent comment
* All comments are associated with a `parentEntityID` and `parentEntityType` (`Event` or `Market`)
## Troubleshooting
<Accordion title="Connection drops unexpectedly">
Send `PING` messages every 5 seconds to keep the connection alive. Connection errors will trigger automatic reconnection attempts.
</Accordion>
<Accordion title="Not receiving messages after subscribing">
Verify your subscription message is valid JSON with the correct `action`, `topic`, and `type` fields. Invalid subscription messages may result in connection closure.
</Accordion>
<Accordion title="Authentication failures">
If subscribing to user-specific streams, ensure your `gamma_auth` object includes a valid wallet `address`. Authentication failures will prevent subscription to protected topics.
</Accordion>
Built with [Mintlify](https://mintlify.com).
-552
View File
@@ -1,552 +0,0 @@
# Real-Time Data Socket
> Stream comments, crypto prices, and equity prices via WebSocket
The Polymarket Real-Time Data Socket (RTDS) is a WebSocket-based streaming service that provides real-time updates for **comments**, **crypto prices**, and **equity prices**.
<Card title="TypeScript client" icon="github" href="https://github.com/Polymarket/real-time-data-client">
Official RTDS TypeScript client (`real-time-data-client`).
</Card>
## Endpoint
```
wss://ws-live-data.polymarket.com
```
Some user-specific streams may require `gamma_auth` with your wallet address.
## Subscribing
Send a JSON message to subscribe to data streams:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "topic_name",
"type": "message_type",
"filters": "optional_filter_string",
"gamma_auth": {
"address": "wallet_address"
}
}
]
}
```
To unsubscribe, send the same structure with `"action": "unsubscribe"`.
Subscriptions can be added, removed, and modified without disconnecting. Send `PING` messages every 5 seconds to maintain the connection.
<Note>Only the subscription types documented below are supported.</Note>
## Message Structure
All messages follow this structure:
```json theme={null}
{
"topic": "string",
"type": "string",
"timestamp": "number",
"payload": "object"
}
```
| Field | Type | Description |
| ----------- | ------ | --------------------------------------------------------------------------- |
| `topic` | string | The subscription topic (e.g., `crypto_prices`, `equity_prices`, `comments`) |
| `type` | string | The message type/event (e.g., `update`, `reaction_created`) |
| `timestamp` | number | Unix timestamp in milliseconds when the message was sent |
| `payload` | object | Event-specific data object |
## Crypto Prices
Real-time cryptocurrency price data from two sources: **Binance** and **Chainlink**. No authentication required.
### Binance Source
Subscribe to all symbols:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices",
"type": "update"
}
]
}
```
Subscribe to specific symbols with a comma-separated filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices",
"type": "update",
"filters": "solusdt,btcusdt,ethusdt"
}
]
}
```
Symbols use lowercase concatenated format (e.g., `solusdt`, `btcusdt`).
**Solana price update:**
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "solusdt",
"timestamp": 1753314064213,
"value": 189.55
}
}
```
**Bitcoin price update:**
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btcusdt",
"timestamp": 1753314088395,
"value": 67234.50
}
}
```
### Chainlink Source
<Tip>
**Trading 15m Crypto Markets?** Get a sponsored Chainlink API key with onboarding support from Chainlink. Fill out [this form](https://pm-ds-request.streams.chain.link/).
</Tip>
Subscribe to all symbols:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices_chainlink",
"type": "*",
"filters": ""
}
]
}
```
Subscribe to a specific symbol with a JSON filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices_chainlink",
"type": "*",
"filters": "{\"symbol\":\"eth/usd\"}"
}
]
}
```
Symbols use slash-separated format (e.g., `eth/usd`, `btc/usd`).
**Ethereum price update:**
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "eth/usd",
"timestamp": 1753314064213,
"value": 3456.78
}
}
```
**Bitcoin price update:**
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btc/usd",
"timestamp": 1753314088395,
"value": 67234.50
}
}
```
### Price Payload Fields
| Field | Type | Description |
| ----------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `symbol` | string | Trading pair symbol. **Binance**: lowercase concatenated (e.g., `solusdt`, `btcusdt`). **Chainlink**: slash-separated (e.g., `eth/usd`, `btc/usd`) |
| `timestamp` | number | When the price was recorded, in Unix milliseconds |
| `value` | number | Current price value in the quote currency |
### Supported Symbols
**Binance Source** — lowercase concatenated format:
* `btcusdt` — Bitcoin to USDT
* `ethusdt` — Ethereum to USDT
* `solusdt` — Solana to USDT
* `xrpusdt` — XRP to USDT
**Chainlink Source** — slash-separated format:
* `btc/usd` — Bitcoin to USD
* `eth/usd` — Ethereum to USD
* `sol/usd` — Solana to USD
* `xrp/usd` — XRP to USD
## Equity Prices
Real-time price data for stocks, ETFs, forex pairs, precious metals, and commodities sourced from **Pyth Network**. No authentication required.
<Tip>
**Trading Equity Markets?** Get a Pyth Network data feed - first 30 days free, then \$99/month. [Subscribe here](https://buy.stripe.com/cNi8wPeiq76FgQrbsD4ZG09).
</Tip>
All asset classes stream through a single `equity_prices` topic. When you subscribe with a symbol filter, the server sends a historical snapshot (last 2 minutes of data), then continues streaming live updates.
### Subscribe
Subscribe to a specific symbol with a JSON filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "equity_prices",
"type": "update",
"filters": "{\"symbol\":\"AAPL\"}"
}
]
}
```
Subscribe to multiple symbols across asset classes:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"AAPL\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"EURUSD\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"XAUUSD\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"WTI\"}" }
]
}
```
Use `type: "*"` to receive all message types (live updates and snapshots):
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "equity_prices",
"type": "*",
"filters": "{\"symbol\":\"GOOGL\"}"
}
]
}
```
Filter values are case-insensitive on subscribe, but the `symbol` field in payloads is always returned lowercase.
<Tip>
**Need the price-to-beat value?** Pass the market slug to the price-to-beat endpoint:
`GET https://polymarket.com/api/equity/price-to-beat/{slug}`
Example: `https://polymarket.com/api/equity/price-to-beat/wti-up-or-down-on-april-7-2026`
</Tip>
### Live Price Update
**Apple stock update:**
```json theme={null}
{
"topic": "equity_prices",
"type": "update",
"timestamp": 1711382400000,
"payload": {
"symbol": "aapl",
"value": 198.45,
"full_accuracy_value": "198.4523",
"timestamp": 1711382400000,
"received_at": 1711382400005
}
}
```
**Gold price update (market closed):**
```json theme={null}
{
"topic": "equity_prices",
"type": "update",
"timestamp": 1711400000000,
"payload": {
"symbol": "xauusd",
"value": 2175.30,
"full_accuracy_value": "2175.3012",
"timestamp": 1711399000000,
"received_at": 1711400000002,
"is_carried_forward": true
}
}
```
### Historical Snapshot
On subscribe, the server delivers a backfill of the last 2 minutes of price data. Use the `type` field to distinguish: `"subscribe"` for the initial snapshot vs `"update"` for live ticks.
```json theme={null}
{
"topic": "equity_prices",
"type": "subscribe",
"timestamp": 1711382400000,
"payload": {
"symbol": "aapl",
"data": [
{ "timestamp": 1711382280000, "value": 198.30 },
{ "timestamp": 1711382281000, "value": 198.32 },
{ "timestamp": 1711382340000, "value": 198.41 }
]
}
}
```
### Equity Price Payload Fields
| Field | Type | Description |
| --------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| `symbol` | string | Lowercase symbol identifier (e.g., `aapl`, `eurusd`, `xauusd`) |
| `value` | number | Spot price as a float |
| `full_accuracy_value` | string | Full-precision price as a string |
| `timestamp` | number | Price measurement timestamp in Unix milliseconds |
| `received_at` | number | When the system received the price, in Unix milliseconds. Only present when non-zero. |
| `is_carried_forward` | boolean | `true` when the market session is closed and the value is the last known price. Only present when `true`. |
### Supported Symbols
**Stocks:**
| Symbol | Name |
| ------- | -------------- |
| `AAPL` | Apple |
| `TSLA` | Tesla |
| `MSFT` | Microsoft |
| `GOOGL` | Alphabet |
| `AMZN` | Amazon |
| `META` | Meta Platforms |
| `NVDA` | NVIDIA |
| `NFLX` | Netflix |
| `PLTR` | Palantir |
| `OPEN` | Opendoor |
| `RKLB` | Rocket Lab |
| `ABNB` | Airbnb |
| `COIN` | Coinbase |
| `HOOD` | Robinhood |
**ETFs:**
| Symbol | Name |
| ------ | ------------------------------------ |
| `QQQ` | Invesco QQQ ETF |
| `SPY` | S\&P 500 ETF |
| `EWY` | iShares MSCI South Korea ETF |
| `VXX` | Barclays iPath Series B S\&P 500 VIX |
**Forex:**
| Symbol | Pair |
| -------- | ---------------------------- |
| `EURUSD` | Euro / US Dollar |
| `GBPUSD` | British Pound / US Dollar |
| `USDCAD` | US Dollar / Canadian Dollar |
| `USDJPY` | US Dollar / Japanese Yen |
| `USDKRW` | US Dollar / South Korean Won |
**Precious Metals:**
| Symbol | Name |
| -------- | ------ |
| `XAUUSD` | Gold |
| `XAGUSD` | Silver |
**Commodities** (rolling front-month futures):
| Symbol | Name |
| ------ | --------------- |
| `WTI` | Crude Oil (WTI) |
| `CC` | Cocoa |
| `NGD` | Natural Gas |
### Market Hours
When a market session is closed, the stream continues with the last known price and `is_carried_forward: true`. This lets you distinguish stale prices from live ticks. Update frequency is sub-second (up to 5 per second per feed) during market hours.
## Comments
Real-time comment events on the Polymarket platform, including new comments, replies, reactions, and removals. May require Gamma authentication for user-specific data.
### Subscribe
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "comments",
"type": "comment_created"
}
]
}
```
### Message Types
| Type | Description |
| ------------------ | ------------------------------------- |
| `comment_created` | A user creates a new comment or reply |
| `comment_removed` | A comment is removed or deleted |
| `reaction_created` | A user adds a reaction to a comment |
| `reaction_removed` | A reaction is removed from a comment |
### comment\_created
Emitted when a user posts a new comment or replies to an existing one.
```json theme={null}
{
"topic": "comments",
"type": "comment_created",
"timestamp": 1753454975808,
"payload": {
"body": "That's a good point about the definition.",
"createdAt": "2025-07-25T14:49:35.801298Z",
"id": "1763355",
"parentCommentID": "1763325",
"parentEntityID": 18396,
"parentEntityType": "Event",
"profile": {
"baseAddress": "0xce533188d53a16ed580fd5121dedf166d3482677",
"displayUsernamePublic": true,
"name": "salted.caramel",
"proxyWallet": "0x4ca749dcfa93c87e5ee23e2d21ff4422c7a4c1ee",
"pseudonym": "Adored-Disparity"
},
"reactionCount": 0,
"replyAddress": "0x0bda5d16f76cd1d3485bcc7a44bc6fa7db004cdd",
"reportCount": 0,
"userAddress": "0xce533188d53a16ed580fd5121dedf166d3482677"
}
}
```
A reply to the above comment — note `parentCommentID` references the parent:
```json theme={null}
{
"topic": "comments",
"type": "comment_created",
"timestamp": 1753454985123,
"payload": {
"body": "I agree, the resolution criteria should be clearer.",
"createdAt": "2025-07-25T14:49:45.120000Z",
"id": "1763356",
"parentCommentID": "1763355",
"parentEntityID": 18396,
"parentEntityType": "Event",
"profile": {
"baseAddress": "0x1234567890abcdef1234567890abcdef12345678",
"displayUsernamePublic": true,
"name": "trader",
"proxyWallet": "0x9876543210fedcba9876543210fedcba98765432",
"pseudonym": "Bright-Analysis"
},
"reactionCount": 0,
"replyAddress": "0x0bda5d16f76cd1d3485bcc7a44bc6fa7db004cdd",
"reportCount": 0,
"userAddress": "0x1234567890abcdef1234567890abcdef12345678"
}
}
```
### Comment Payload Fields
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------------------- |
| `body` | string | The text content of the comment |
| `createdAt` | string | ISO 8601 timestamp when the comment was created |
| `id` | string | Unique identifier for this comment |
| `parentCommentID` | string | ID of the parent comment if this is a reply (null for top-level comments) |
| `parentEntityID` | number | ID of the parent entity (event, market, etc.) |
| `parentEntityType` | string | Type of parent entity (`Event`, `Market`) |
| `profile` | object | Profile information of the comment author |
| `reactionCount` | number | Current number of reactions on this comment |
| `replyAddress` | string | Polygon address for replies (may differ from userAddress) |
| `reportCount` | number | Current number of reports on this comment |
| `userAddress` | string | Polygon address of the comment author |
### Profile Object Fields
| Field | Type | Description |
| ----------------------- | ------- | ------------------------------------------ |
| `baseAddress` | string | User profile address |
| `displayUsernamePublic` | boolean | Whether the username is displayed publicly |
| `name` | string | User's display name |
| `proxyWallet` | string | Proxy wallet address used for transactions |
| `pseudonym` | string | Generated pseudonym for the user |
### Comment Hierarchy
Comments support nested threading:
* **Top-level comments**: `parentCommentID` is null or empty
* **Reply comments**: `parentCommentID` contains the ID of the parent comment
* All comments are associated with a `parentEntityID` and `parentEntityType` (`Event` or `Market`)
## Troubleshooting
<Accordion title="Connection drops unexpectedly">
Send `PING` messages every 5 seconds to keep the connection alive. Connection errors will trigger automatic reconnection attempts.
</Accordion>
<Accordion title="Not receiving messages after subscribing">
Verify your subscription message is valid JSON with the correct `action`, `topic`, and `type` fields. Invalid subscription messages may result in connection closure.
</Accordion>
<Accordion title="Authentication failures">
If subscribing to user-specific streams, ensure your `gamma_auth` object includes a valid wallet `address`. Authentication failures will prevent subscription to protected topics.
</Accordion>
Built with [Mintlify](https://mintlify.com).
-552
View File
@@ -1,552 +0,0 @@
# Real-Time Data Socket
> Stream comments, crypto prices, and equity prices via WebSocket
The Polymarket Real-Time Data Socket (RTDS) is a WebSocket-based streaming service that provides real-time updates for **comments**, **crypto prices**, and **equity prices**.
<Card title="TypeScript client" icon="github" href="https://github.com/Polymarket/real-time-data-client">
Official RTDS TypeScript client (`real-time-data-client`).
</Card>
## Endpoint
```
wss://ws-live-data.polymarket.com
```
Some user-specific streams may require `gamma_auth` with your wallet address.
## Subscribing
Send a JSON message to subscribe to data streams:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "topic_name",
"type": "message_type",
"filters": "optional_filter_string",
"gamma_auth": {
"address": "wallet_address"
}
}
]
}
```
To unsubscribe, send the same structure with `"action": "unsubscribe"`.
Subscriptions can be added, removed, and modified without disconnecting. Send `PING` messages every 5 seconds to maintain the connection.
<Note>Only the subscription types documented below are supported.</Note>
## Message Structure
All messages follow this structure:
```json theme={null}
{
"topic": "string",
"type": "string",
"timestamp": "number",
"payload": "object"
}
```
| Field | Type | Description |
| ----------- | ------ | --------------------------------------------------------------------------- |
| `topic` | string | The subscription topic (e.g., `crypto_prices`, `equity_prices`, `comments`) |
| `type` | string | The message type/event (e.g., `update`, `reaction_created`) |
| `timestamp` | number | Unix timestamp in milliseconds when the message was sent |
| `payload` | object | Event-specific data object |
## Crypto Prices
Real-time cryptocurrency price data from two sources: **Binance** and **Chainlink**. No authentication required.
### Binance Source
Subscribe to all symbols:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices",
"type": "update"
}
]
}
```
Subscribe to specific symbols with a comma-separated filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices",
"type": "update",
"filters": "solusdt,btcusdt,ethusdt"
}
]
}
```
Symbols use lowercase concatenated format (e.g., `solusdt`, `btcusdt`).
**Solana price update:**
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "solusdt",
"timestamp": 1753314064213,
"value": 189.55
}
}
```
**Bitcoin price update:**
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btcusdt",
"timestamp": 1753314088395,
"value": 67234.50
}
}
```
### Chainlink Source
<Tip>
**Trading 15m Crypto Markets?** Get a sponsored Chainlink API key with onboarding support from Chainlink. Fill out [this form](https://pm-ds-request.streams.chain.link/).
</Tip>
Subscribe to all symbols:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices_chainlink",
"type": "*",
"filters": ""
}
]
}
```
Subscribe to a specific symbol with a JSON filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices_chainlink",
"type": "*",
"filters": "{\"symbol\":\"eth/usd\"}"
}
]
}
```
Symbols use slash-separated format (e.g., `eth/usd`, `btc/usd`).
**Ethereum price update:**
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "eth/usd",
"timestamp": 1753314064213,
"value": 3456.78
}
}
```
**Bitcoin price update:**
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btc/usd",
"timestamp": 1753314088395,
"value": 67234.50
}
}
```
### Price Payload Fields
| Field | Type | Description |
| ----------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `symbol` | string | Trading pair symbol. **Binance**: lowercase concatenated (e.g., `solusdt`, `btcusdt`). **Chainlink**: slash-separated (e.g., `eth/usd`, `btc/usd`) |
| `timestamp` | number | When the price was recorded, in Unix milliseconds |
| `value` | number | Current price value in the quote currency |
### Supported Symbols
**Binance Source** — lowercase concatenated format:
* `btcusdt` — Bitcoin to USDT
* `ethusdt` — Ethereum to USDT
* `solusdt` — Solana to USDT
* `xrpusdt` — XRP to USDT
**Chainlink Source** — slash-separated format:
* `btc/usd` — Bitcoin to USD
* `eth/usd` — Ethereum to USD
* `sol/usd` — Solana to USD
* `xrp/usd` — XRP to USD
## Equity Prices
Real-time price data for stocks, ETFs, forex pairs, precious metals, and commodities sourced from **Pyth Network**. No authentication required.
<Tip>
**Trading Equity Markets?** Get a Pyth Network data feed - first 30 days free, then \$99/month. [Subscribe here](https://buy.stripe.com/cNi8wPeiq76FgQrbsD4ZG09).
</Tip>
All asset classes stream through a single `equity_prices` topic. When you subscribe with a symbol filter, the server sends a historical snapshot (last 2 minutes of data), then continues streaming live updates.
### Subscribe
Subscribe to a specific symbol with a JSON filter:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "equity_prices",
"type": "update",
"filters": "{\"symbol\":\"AAPL\"}"
}
]
}
```
Subscribe to multiple symbols across asset classes:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"AAPL\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"EURUSD\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"XAUUSD\"}" },
{ "topic": "equity_prices", "type": "update", "filters": "{\"symbol\":\"WTI\"}" }
]
}
```
Use `type: "*"` to receive all message types (live updates and snapshots):
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "equity_prices",
"type": "*",
"filters": "{\"symbol\":\"GOOGL\"}"
}
]
}
```
Filter values are case-insensitive on subscribe, but the `symbol` field in payloads is always returned lowercase.
<Tip>
**Need the price-to-beat value?** Pass the market slug to the price-to-beat endpoint:
`GET https://polymarket.com/api/equity/price-to-beat/{slug}`
Example: `https://polymarket.com/api/equity/price-to-beat/wti-up-or-down-on-april-7-2026`
</Tip>
### Live Price Update
**Apple stock update:**
```json theme={null}
{
"topic": "equity_prices",
"type": "update",
"timestamp": 1711382400000,
"payload": {
"symbol": "aapl",
"value": 198.45,
"full_accuracy_value": "198.4523",
"timestamp": 1711382400000,
"received_at": 1711382400005
}
}
```
**Gold price update (market closed):**
```json theme={null}
{
"topic": "equity_prices",
"type": "update",
"timestamp": 1711400000000,
"payload": {
"symbol": "xauusd",
"value": 2175.30,
"full_accuracy_value": "2175.3012",
"timestamp": 1711399000000,
"received_at": 1711400000002,
"is_carried_forward": true
}
}
```
### Historical Snapshot
On subscribe, the server delivers a backfill of the last 2 minutes of price data. Use the `type` field to distinguish: `"subscribe"` for the initial snapshot vs `"update"` for live ticks.
```json theme={null}
{
"topic": "equity_prices",
"type": "subscribe",
"timestamp": 1711382400000,
"payload": {
"symbol": "aapl",
"data": [
{ "timestamp": 1711382280000, "value": 198.30 },
{ "timestamp": 1711382281000, "value": 198.32 },
{ "timestamp": 1711382340000, "value": 198.41 }
]
}
}
```
### Equity Price Payload Fields
| Field | Type | Description |
| --------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| `symbol` | string | Lowercase symbol identifier (e.g., `aapl`, `eurusd`, `xauusd`) |
| `value` | number | Spot price as a float |
| `full_accuracy_value` | string | Full-precision price as a string |
| `timestamp` | number | Price measurement timestamp in Unix milliseconds |
| `received_at` | number | When the system received the price, in Unix milliseconds. Only present when non-zero. |
| `is_carried_forward` | boolean | `true` when the market session is closed and the value is the last known price. Only present when `true`. |
### Supported Symbols
**Stocks:**
| Symbol | Name |
| ------- | -------------- |
| `AAPL` | Apple |
| `TSLA` | Tesla |
| `MSFT` | Microsoft |
| `GOOGL` | Alphabet |
| `AMZN` | Amazon |
| `META` | Meta Platforms |
| `NVDA` | NVIDIA |
| `NFLX` | Netflix |
| `PLTR` | Palantir |
| `OPEN` | Opendoor |
| `RKLB` | Rocket Lab |
| `ABNB` | Airbnb |
| `COIN` | Coinbase |
| `HOOD` | Robinhood |
**ETFs:**
| Symbol | Name |
| ------ | ------------------------------------ |
| `QQQ` | Invesco QQQ ETF |
| `SPY` | S\&P 500 ETF |
| `EWY` | iShares MSCI South Korea ETF |
| `VXX` | Barclays iPath Series B S\&P 500 VIX |
**Forex:**
| Symbol | Pair |
| -------- | ---------------------------- |
| `EURUSD` | Euro / US Dollar |
| `GBPUSD` | British Pound / US Dollar |
| `USDCAD` | US Dollar / Canadian Dollar |
| `USDJPY` | US Dollar / Japanese Yen |
| `USDKRW` | US Dollar / South Korean Won |
**Precious Metals:**
| Symbol | Name |
| -------- | ------ |
| `XAUUSD` | Gold |
| `XAGUSD` | Silver |
**Commodities** (rolling front-month futures):
| Symbol | Name |
| ------ | --------------- |
| `WTI` | Crude Oil (WTI) |
| `CC` | Cocoa |
| `NGD` | Natural Gas |
### Market Hours
When a market session is closed, the stream continues with the last known price and `is_carried_forward: true`. This lets you distinguish stale prices from live ticks. Update frequency is sub-second (up to 5 per second per feed) during market hours.
## Comments
Real-time comment events on the Polymarket platform, including new comments, replies, reactions, and removals. May require Gamma authentication for user-specific data.
### Subscribe
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "comments",
"type": "comment_created"
}
]
}
```
### Message Types
| Type | Description |
| ------------------ | ------------------------------------- |
| `comment_created` | A user creates a new comment or reply |
| `comment_removed` | A comment is removed or deleted |
| `reaction_created` | A user adds a reaction to a comment |
| `reaction_removed` | A reaction is removed from a comment |
### comment\_created
Emitted when a user posts a new comment or replies to an existing one.
```json theme={null}
{
"topic": "comments",
"type": "comment_created",
"timestamp": 1753454975808,
"payload": {
"body": "That's a good point about the definition.",
"createdAt": "2025-07-25T14:49:35.801298Z",
"id": "1763355",
"parentCommentID": "1763325",
"parentEntityID": 18396,
"parentEntityType": "Event",
"profile": {
"baseAddress": "0xce533188d53a16ed580fd5121dedf166d3482677",
"displayUsernamePublic": true,
"name": "salted.caramel",
"proxyWallet": "0x4ca749dcfa93c87e5ee23e2d21ff4422c7a4c1ee",
"pseudonym": "Adored-Disparity"
},
"reactionCount": 0,
"replyAddress": "0x0bda5d16f76cd1d3485bcc7a44bc6fa7db004cdd",
"reportCount": 0,
"userAddress": "0xce533188d53a16ed580fd5121dedf166d3482677"
}
}
```
A reply to the above comment — note `parentCommentID` references the parent:
```json theme={null}
{
"topic": "comments",
"type": "comment_created",
"timestamp": 1753454985123,
"payload": {
"body": "I agree, the resolution criteria should be clearer.",
"createdAt": "2025-07-25T14:49:45.120000Z",
"id": "1763356",
"parentCommentID": "1763355",
"parentEntityID": 18396,
"parentEntityType": "Event",
"profile": {
"baseAddress": "0x1234567890abcdef1234567890abcdef12345678",
"displayUsernamePublic": true,
"name": "trader",
"proxyWallet": "0x9876543210fedcba9876543210fedcba98765432",
"pseudonym": "Bright-Analysis"
},
"reactionCount": 0,
"replyAddress": "0x0bda5d16f76cd1d3485bcc7a44bc6fa7db004cdd",
"reportCount": 0,
"userAddress": "0x1234567890abcdef1234567890abcdef12345678"
}
}
```
### Comment Payload Fields
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------------------- |
| `body` | string | The text content of the comment |
| `createdAt` | string | ISO 8601 timestamp when the comment was created |
| `id` | string | Unique identifier for this comment |
| `parentCommentID` | string | ID of the parent comment if this is a reply (null for top-level comments) |
| `parentEntityID` | number | ID of the parent entity (event, market, etc.) |
| `parentEntityType` | string | Type of parent entity (`Event`, `Market`) |
| `profile` | object | Profile information of the comment author |
| `reactionCount` | number | Current number of reactions on this comment |
| `replyAddress` | string | Polygon address for replies (may differ from userAddress) |
| `reportCount` | number | Current number of reports on this comment |
| `userAddress` | string | Polygon address of the comment author |
### Profile Object Fields
| Field | Type | Description |
| ----------------------- | ------- | ------------------------------------------ |
| `baseAddress` | string | User profile address |
| `displayUsernamePublic` | boolean | Whether the username is displayed publicly |
| `name` | string | User's display name |
| `proxyWallet` | string | Proxy wallet address used for transactions |
| `pseudonym` | string | Generated pseudonym for the user |
### Comment Hierarchy
Comments support nested threading:
* **Top-level comments**: `parentCommentID` is null or empty
* **Reply comments**: `parentCommentID` contains the ID of the parent comment
* All comments are associated with a `parentEntityID` and `parentEntityType` (`Event` or `Market`)
## Troubleshooting
<Accordion title="Connection drops unexpectedly">
Send `PING` messages every 5 seconds to keep the connection alive. Connection errors will trigger automatic reconnection attempts.
</Accordion>
<Accordion title="Not receiving messages after subscribing">
Verify your subscription message is valid JSON with the correct `action`, `topic`, and `type` fields. Invalid subscription messages may result in connection closure.
</Accordion>
<Accordion title="Authentication failures">
If subscribing to user-specific streams, ensure your `gamma_auth` object includes a valid wallet `address`. Authentication failures will prevent subscription to protected topics.
</Accordion>
Built with [Mintlify](https://mintlify.com).
@@ -1,68 +0,0 @@
# Data Resources
> Access Polymarket on-chain activity for data & analytics
Polymarket data that lands on the blockchain, such as trades, balances, positions, and redeems, is available through various on-chain analytics platforms and blockchain data providers. Polymarket also provides its own APIs and WebSockets. See the [API Endpoints reference](/quickstart/reference/endpoints) for more information.
The purpose of this page is to serve as a public good for Polymarket builders, researches, and analysts alike.
***
## Data
### Goldsky
[Goldsky](https://docs.goldsky.com/chains/polymarket) provides real-time streaming pipelines for Polymarket on-chain activity (i.e. trades, balances, positions, etc...) into your own database/data warehouse.
Goldsky also partnered with [ClickHouse](https://clickhouse.com) to create [CryptoHouse](https://crypto.clickhouse.com), where you can query Polymarket on-chain data using SQL.
### Dune
[Dune](https://dune.com) is a blockchain analytics platform that has Polymarket on-chain activity (i.e. trades, balances, positions, etc...). Query Polymarket data using SQL, create custom dashboards, and more.
Here are a few simple queries to get started:
| Query | Description | Link |
| ------------- | --------------------------------------------- | --------------------------------------------------- |
| Volume | Notional Volume and Maker & Taker USDC Volume | [View Dune Query](https://dune.com/queries/6545441) |
| TVL | USDC locked in Polymarket smart contracts | [View Dune Query](https://dune.com/queries/6588784) |
| Open Interest | Estimated market open interest, and over time | [View Dune Query](https://dune.com/queries/6555478) |
### Allium
[Allium](https://docs.allium.so/historical-data/predictions) is a blockchain analytics platform that has Polymarket on-chain activity (i.e. trades, balances, positions, etc...). Query Polymarket data using SQL, create custom dashboards, and more.
\--
## Dashboards
Third-party blockchain analytics platforms that aggregate and visualize Polymarket data:
<CardGroup cols={4}>
<Card title="Blockworks" img="https://pbs.twimg.com/profile_images/1651677302634483712/7s2FxV2K_400x400.jpg" href="https://blockworks.com/analytics/polymarket" />
<Card title="Artemis" img="https://pbs.twimg.com/profile_images/1896982195723546624/2XeO9mPb_400x400.png" href="https://app.artemisanalytics.com/asset/polymarket?from=assets" />
<Card title="Dune" img="https://pbs.twimg.com/profile_images/1986458079248986112/qq80s3hx_400x400.jpg" href="https://dune.com/discover/content/popular?q=polymarket&resource-type=dashboards" />
<Card title="DeFiLlama" img="https://pbs.twimg.com/profile_images/1915756547705036800/rAeLzZqs_400x400.jpg" href="https://defillama.com/protocol/polymarket" />
<Card title="The Block" img="https://pbs.twimg.com/profile_images/1944749695525425152/9babG7Df_400x400.jpg" href="https://www.theblock.co/data/decentralized-finance/prediction-markets-and-betting" />
<Card title="Token Terminal" img="https://pbs.twimg.com/profile_images/1594678659222306817/SMum_RcQ_400x400.jpg" href="https://tokenterminal.com/explorer/projects/polymarket" />
<Card title="Allium" img="https://pbs.twimg.com/profile_images/1778926940407132160/UEwR3lHt_400x400.jpg" href="https://predictions.allium.so" />
</CardGroup>
### Community Dashboards
Community-created Dune dashboards of Polymarket on-chain analytics:
| Dashboard | Created By | Link |
| ------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------- |
| Polymarket Overview | [@datadashboards](https://x.com/datadashboards) | [View Dashboard](https://dune.com/datadashboards/polymarket-overview) |
| Polymarket Volume, OI, Markets, Addresses and TVL | [@hildobby](https://x.com/hildobby) | [View Dashboard](https://dune.com/hildobby/polymarket) |
| Polymarket Historical Accuracy | [@alexmccullaaa](https://x.com/alexmccullaaa) | [View Dashboard](https://dune.com/alexmccullough/how-accurate-is-polymarket) |
| Polymarket Builders Dashboard | [@defioasis](https://x.com/defioasis) | [View Dashboard](https://dune.com/gateresearch/pmbuilders) |
Built with [Mintlify](https://mintlify.com).
-211
View File
@@ -1,211 +0,0 @@
# Builder Program
> Build applications that route orders through Polymarket
A **builder** is a person, group, or organization that routes orders from users to Polymarket. If you've created a platform that allows users to trade on Polymarket through your system, this program is for you.
## Program Benefits
<CardGroup cols={2}>
<Card title="Gasless Transactions" icon="gas-pump">
All onchain operations are gas-free through our relayer
</Card>
<Card title="Order Attribution" icon="tag">
Get credit for orders and compete for grants on the Builder Leaderboard
</Card>
</CardGroup>
### What You Get
| Benefit | Description |
| ------------------- | ------------------------------------------------------------------------------- |
| **Relayer Access** | Gas-free wallet deployment, approvals, order execution and CTF operations |
| **Volume Tracking** | All orders attributed to your builder profile |
| **Leaderboard** | Public visibility on [builders.polymarket.com](https://builders.polymarket.com) |
| **Support** | Telegram channel and engineering support (Verified+) |
<Warning>
EOA wallets do not have relayer access. Users trading directly from an EOA pay
their own gas fees.
</Warning>
## How It Works
<Steps>
<Step title="User Places Order">
User places an order through your application.
</Step>
<Step title="Sign Request">
Your app signs the request with Builder API credentials.
</Step>
<Step title="Submit to CLOB">
Order is submitted to Polymarket's CLOB with attribution headers.
</Step>
<Step title="Trade Execution">
Polymarket matches the order and covers gas fees for onchain operations.
</Step>
<Step title="Volume Attribution">
Volume is credited to your builder account.
</Step>
</Steps>
## Getting Started
<Steps>
<Step title="Create Builder Profile">
Go to
[polymarket.com/settings?tab=builder](https://polymarket.com/settings?tab=builder)
and generate your API keys.
</Step>
<Step title="Configure Attribution">
Set up your CLOB client to include builder authentication headers with every
order.
</Step>
<Step title="Enable Gasless Transactions">
Use the Relayer Client for gas-free wallet deployment and onchain
operations.
</Step>
<Step title="Track Performance">
Monitor your volume on the [Builder
Leaderboard](https://builders.polymarket.com).
</Step>
</Steps>
## SDKs and Libraries
<CardGroup cols={2}>
<Card title="CLOB Client (TypeScript)" icon="github" href="https://github.com/Polymarket/clob-client">
Place orders with builder attribution
</Card>
<Card title="CLOB Client (Python)" icon="github" href="https://github.com/Polymarket/py-clob-client">
Place orders with builder attribution
</Card>
<Card title="Relayer Client (TypeScript)" icon="github" href="https://github.com/Polymarket/builder-relayer-client">
Gasless onchain transactions
</Card>
<Card title="Relayer Client (Python)" icon="github" href="https://github.com/Polymarket/py-builder-relayer-client">
Gasless onchain transactions
</Card>
<Card title="CLOB Client (Rust)" icon="github" href="https://github.com/Polymarket/rs-clob-client">
Place orders with builder attribution
</Card>
<Card title="Signing SDK (TypeScript)" icon="github" href="https://github.com/Polymarket/builder-signing-sdk">
Sign builder authentication headers
</Card>
<Card title="Signing SDK (Python)" icon="github" href="https://github.com/Polymarket/py-builder-signing-sdk">
Sign builder authentication headers
</Card>
</CardGroup>
## Examples
These open-source demo applications show how to integrate Polymarket's CLOB Client and Builder Relayer Client for gasless trading with builder order attribution.
<CardGroup cols={3}>
<Card title="Authentication" icon="user-check">
Multiple wallet providers
</Card>
<Card title="Gasless Trading" icon="gas-pump">
Safe & Proxy wallet support
</Card>
<Card title="Full Integration" icon="puzzle-piece">
Orders, positions, CTF ops
</Card>
</CardGroup>
### Safe Wallet Examples
Deploy Gnosis Safe wallets for your users:
<CardGroup cols={2}>
<Card title="wagmi + Safe" icon="wallet" href="https://github.com/Polymarket/wagmi-safe-builder-example">
MetaMask, Phantom, Rabby, and other browser wallets
</Card>
<Card title="Privy + Safe" icon="shield-check" href="https://github.com/Polymarket/privy-safe-builder-example">
Privy embedded wallets
</Card>
<Card title="Magic Link + Safe" icon="wand-magic-sparkles" href="https://github.com/Polymarket/magic-safe-builder-example">
Magic Link email/social authentication
</Card>
<Card title="Turnkey + Safe" icon="key" href="https://github.com/Polymarket/turnkey-safe-builder-example">
Turnkey embedded wallets
</Card>
</CardGroup>
### Proxy Wallet Examples
For existing Magic Link users from Polymarket.com:
<CardGroup cols={1}>
<Card title="Magic Link + Proxy" icon="wand-magic-sparkles" href="https://github.com/Polymarket/magic-proxy-builder-example">
Auto-deploying proxy wallets for Polymarket.com Magic users
</Card>
</CardGroup>
### What Each Demo Covers
<Tabs>
<Tab title="Authentication">
* User sign-in via wallet provider
* User API credential derivation (L2 auth)
* Builder config with remote signing
* Signature types for Safe vs Proxy wallets
</Tab>
<Tab title="Wallet Operations">
* Safe wallet deployment via Relayer
* Batch token approvals (USDC.e + outcome tokens)
* CTF operations (split, merge, redeem)
* Transaction monitoring
</Tab>
<Tab title="Trading">
* CLOB client initialization
* Order placement with builder attribution
* Position and order management
* Market discovery via Gamma API
</Tab>
</Tabs>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Get API Keys" icon="key" href="/builders/api-keys">
Create and manage your Builder API credentials.
</Card>
<Card title="Understand Tiers" icon="layer-group" href="/builders/tiers">
Learn about rate limits and how to upgrade.
</Card>
<Card title="Attribute Orders" icon="tag" href="/trading/orders/attribution">
Configure your client to credit trades to your account.
</Card>
<Card title="Gasless Guide" icon="gas-pump" href="/trading/gasless">
Set up gasless transactions for your users.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-211
View File
@@ -1,211 +0,0 @@
# Builder Program
> Build applications that route orders through Polymarket
A **builder** is a person, group, or organization that routes orders from users to Polymarket. If you've created a platform that allows users to trade on Polymarket through your system, this program is for you.
## Program Benefits
<CardGroup cols={2}>
<Card title="Gasless Transactions" icon="gas-pump">
All onchain operations are gas-free through our relayer
</Card>
<Card title="Order Attribution" icon="tag">
Get credit for orders and compete for grants on the Builder Leaderboard
</Card>
</CardGroup>
### What You Get
| Benefit | Description |
| ------------------- | ------------------------------------------------------------------------------- |
| **Relayer Access** | Gas-free wallet deployment, approvals, order execution and CTF operations |
| **Volume Tracking** | All orders attributed to your builder profile |
| **Leaderboard** | Public visibility on [builders.polymarket.com](https://builders.polymarket.com) |
| **Support** | Telegram channel and engineering support (Verified+) |
<Warning>
EOA wallets do not have relayer access. Users trading directly from an EOA pay
their own gas fees.
</Warning>
## How It Works
<Steps>
<Step title="User Places Order">
User places an order through your application.
</Step>
<Step title="Sign Request">
Your app signs the request with Builder API credentials.
</Step>
<Step title="Submit to CLOB">
Order is submitted to Polymarket's CLOB with attribution headers.
</Step>
<Step title="Trade Execution">
Polymarket matches the order and covers gas fees for onchain operations.
</Step>
<Step title="Volume Attribution">
Volume is credited to your builder account.
</Step>
</Steps>
## Getting Started
<Steps>
<Step title="Create Builder Profile">
Go to
[polymarket.com/settings?tab=builder](https://polymarket.com/settings?tab=builder)
and generate your API keys.
</Step>
<Step title="Configure Attribution">
Set up your CLOB client to include builder authentication headers with every
order.
</Step>
<Step title="Enable Gasless Transactions">
Use the Relayer Client for gas-free wallet deployment and onchain
operations.
</Step>
<Step title="Track Performance">
Monitor your volume on the [Builder
Leaderboard](https://builders.polymarket.com).
</Step>
</Steps>
## SDKs and Libraries
<CardGroup cols={2}>
<Card title="CLOB Client (TypeScript)" icon="github" href="https://github.com/Polymarket/clob-client">
Place orders with builder attribution
</Card>
<Card title="CLOB Client (Python)" icon="github" href="https://github.com/Polymarket/py-clob-client">
Place orders with builder attribution
</Card>
<Card title="Relayer Client (TypeScript)" icon="github" href="https://github.com/Polymarket/builder-relayer-client">
Gasless onchain transactions
</Card>
<Card title="Relayer Client (Python)" icon="github" href="https://github.com/Polymarket/py-builder-relayer-client">
Gasless onchain transactions
</Card>
<Card title="CLOB Client (Rust)" icon="github" href="https://github.com/Polymarket/rs-clob-client">
Place orders with builder attribution
</Card>
<Card title="Signing SDK (TypeScript)" icon="github" href="https://github.com/Polymarket/builder-signing-sdk">
Sign builder authentication headers
</Card>
<Card title="Signing SDK (Python)" icon="github" href="https://github.com/Polymarket/py-builder-signing-sdk">
Sign builder authentication headers
</Card>
</CardGroup>
## Examples
These open-source demo applications show how to integrate Polymarket's CLOB Client and Builder Relayer Client for gasless trading with builder order attribution.
<CardGroup cols={3}>
<Card title="Authentication" icon="user-check">
Multiple wallet providers
</Card>
<Card title="Gasless Trading" icon="gas-pump">
Safe & Proxy wallet support
</Card>
<Card title="Full Integration" icon="puzzle-piece">
Orders, positions, CTF ops
</Card>
</CardGroup>
### Safe Wallet Examples
Deploy Gnosis Safe wallets for your users:
<CardGroup cols={2}>
<Card title="wagmi + Safe" icon="wallet" href="https://github.com/Polymarket/wagmi-safe-builder-example">
MetaMask, Phantom, Rabby, and other browser wallets
</Card>
<Card title="Privy + Safe" icon="shield-check" href="https://github.com/Polymarket/privy-safe-builder-example">
Privy embedded wallets
</Card>
<Card title="Magic Link + Safe" icon="wand-magic-sparkles" href="https://github.com/Polymarket/magic-safe-builder-example">
Magic Link email/social authentication
</Card>
<Card title="Turnkey + Safe" icon="key" href="https://github.com/Polymarket/turnkey-safe-builder-example">
Turnkey embedded wallets
</Card>
</CardGroup>
### Proxy Wallet Examples
For existing Magic Link users from Polymarket.com:
<CardGroup cols={1}>
<Card title="Magic Link + Proxy" icon="wand-magic-sparkles" href="https://github.com/Polymarket/magic-proxy-builder-example">
Auto-deploying proxy wallets for Polymarket.com Magic users
</Card>
</CardGroup>
### What Each Demo Covers
<Tabs>
<Tab title="Authentication">
* User sign-in via wallet provider
* User API credential derivation (L2 auth)
* Builder config with remote signing
* Signature types for Safe vs Proxy wallets
</Tab>
<Tab title="Wallet Operations">
* Safe wallet deployment via Relayer
* Batch token approvals (USDC.e + outcome tokens)
* CTF operations (split, merge, redeem)
* Transaction monitoring
</Tab>
<Tab title="Trading">
* CLOB client initialization
* Order placement with builder attribution
* Position and order management
* Market discovery via Gamma API
</Tab>
</Tabs>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Get API Keys" icon="key" href="/builders/api-keys">
Create and manage your Builder API credentials.
</Card>
<Card title="Understand Tiers" icon="layer-group" href="/builders/tiers">
Learn about rate limits and how to upgrade.
</Card>
<Card title="Attribute Orders" icon="tag" href="/trading/orders/attribution">
Configure your client to credit trades to your account.
</Card>
<Card title="Gasless Guide" icon="gas-pump" href="/trading/gasless">
Set up gasless transactions for your users.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-168
View File
@@ -1,168 +0,0 @@
# Tiers
> Rate limits, rewards, and how to upgrade
The Builder Program uses a tiered system to manage rate limits while rewarding high-performing integrations. Higher tiers unlock increased limits, weekly rewards, and priority support.
## Feature Definitions
| Feature | Description |
| --------------------------- | ------------------------------------------------------------------------- |
| **Daily Relayer Txn Limit** | Maximum Relayer transactions per day for Safe/Proxy wallet operations |
| **API Rate Limits** | Rate limits for non-relayer endpoints (CLOB, Gamma, etc.) |
| **Gasless Trading** | Gas fees subsidized for trading via Safe/Proxy wallets |
| **Order Attribution** | Orders tracked and attributed to your Builder profile |
| **Builder Fees** | Builders who route orders can charge fees and monetize on flow |
| **Leaderboard Visibility** | Visibility on the [Builder Leaderboard](https://builders.polymarket.com/) |
| **Telegram Channel** | Private Builders channel for announcements and support |
| **Engineering Support** | Direct access to engineering team |
| **Marketing Support** | Promotion via official Polymarket social accounts |
| **Priority Access** | Early access to new features and products |
***
## Tier Comparison
| Feature | Unverified | Verified | Partner |
| --------------------------- | :--------: | :--------: | :-------: |
| **Daily Relayer Txn Limit** | 100/day | 10,000/day | Unlimited |
| **API Rate Limits** | Standard | Standard | Highest |
| **Gasless Trading**\* | Yes | Yes | Yes |
| **Order Attribution** | Yes | Yes | Yes |
| **Builder Fees** | Yes | Yes | Yes |
| **Leaderboard Visibility** | — | Yes | Yes |
| **Telegram Channel** | — | Yes | Yes |
| **Engineering Support** | — | Standard | Elevated |
| **Marketing Support** | — | Standard | Elevated |
| **Priority Access** | — | — | Yes |
***
## Unverified
<Card title="100 Relay transactions/day" icon="seedling">
The default tier for all new builders. Start immediately with no approval
required.
</Card>
**How to get started:**
1. Go to [polymarket.com/settings?tab=builder](https://polymarket.com/settings?tab=builder)
2. Create a builder profile
3. Click **"+ Create New"** to generate API keys
4. Implement [builder signing](/trading/orders/attribution) — required for Relayer access and CLOB order attribution
**What's included:**
* Gasless trading on all CLOB orders through Safe/Proxy wallets
* Gas subsidized on all Relayer transactions up to daily limit (through Safe/Proxy wallets)
* Access to all client libraries and documentation
***
## Verified
<Card title="10,000 Relay transactions/day" icon="badge-check">
For builders who need higher throughput. Requires manual approval.
</Card>
**How to upgrade:**
Contact us at [builder@polymarket.com](mailto:builder@polymarket.com) with:
* Your Builder API Key
* Use case description
* Expected volume
* Other relevant information (links, docs, decks, etc.)
**Unlocks over Unverified:**
* 100x daily Relayer transaction limit
* Monetize with Builder fees
* Leaderboard visibility at [builders.polymarket.com](https://builders.polymarket.com)
* Private Telegram channel for announcements and support
* Weekly USDC rewards based on volume (subject to approval)
* Grants (subject to approval)
***
## Partner
<Card title="Unlimited Relay transactions/day" icon="handshake">
Enterprise tier for high-volume integrations and strategic partners.
</Card>
**Unlocks over Verified:**
* Unlimited Relayer transactions
* Highest API rate limits
* Elevated engineering support
* Elevated and coordinated marketing support
* Priority access to new features and products
***
## How to Upgrade
<Steps>
<Step title="Build and Launch">
Start with the Unverified tier and build your integration.
</Step>
<Step title="Generate Volume">
Route orders through Polymarket and demonstrate consistent usage.
</Step>
<Step title="Apply for Verification">
Email [builder@polymarket.com](mailto:builder@polymarket.com) with your
builder key and use case.
</Step>
<Step title="Get Approved">
The Polymarket team reviews applications and responds within a few business
days.
</Step>
</Steps>
## Contact
Ready to upgrade or have questions?
<Card title="builder@polymarket.com" icon="envelope" href="mailto:builder@polymarket.com">
Email us with your Builder API Key and use case details.
</Card>
## FAQ
<AccordionGroup>
<Accordion title="How do I know if I am verified">
Verification is displayed in your [Builder Profile](https://polymarket.com/settings?tab=builder) settings.
</Accordion>
<Accordion title="What happens if I exceed my daily limit">
Relayer requests beyond your daily limit will be rate-limited and return an
error. Consider upgrading to Verified or Partner tier if you're hitting
limits.
</Accordion>
<Accordion title="What if I just need more daily Relay transaction limits for my own wallet">
If you're not routing orders for other users (wallets), you can get unlimited
daily Relay transactions by obtaining a [Relayer API key](https://polymarket.com/settings?tab=api-keys).
</Accordion>
</AccordionGroup>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Get API Keys" icon="key" href="/builders/api-keys">
Create your Builder API credentials.
</Card>
<Card title="Attribute Orders" icon="tag" href="/trading/orders/attribution">
Configure your client to credit trades to your account.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-211
View File
@@ -1,211 +0,0 @@
# Builder Program
> Build applications that route orders through Polymarket
A **builder** is a person, group, or organization that routes orders from users to Polymarket. If you've created a platform that allows users to trade on Polymarket through your system, this program is for you.
## Program Benefits
<CardGroup cols={2}>
<Card title="Gasless Transactions" icon="gas-pump">
All onchain operations are gas-free through our relayer
</Card>
<Card title="Order Attribution" icon="tag">
Get credit for orders and compete for grants on the Builder Leaderboard
</Card>
</CardGroup>
### What You Get
| Benefit | Description |
| ------------------- | ------------------------------------------------------------------------------- |
| **Relayer Access** | Gas-free wallet deployment, approvals, order execution and CTF operations |
| **Volume Tracking** | All orders attributed to your builder profile |
| **Leaderboard** | Public visibility on [builders.polymarket.com](https://builders.polymarket.com) |
| **Support** | Telegram channel and engineering support (Verified+) |
<Warning>
EOA wallets do not have relayer access. Users trading directly from an EOA pay
their own gas fees.
</Warning>
## How It Works
<Steps>
<Step title="User Places Order">
User places an order through your application.
</Step>
<Step title="Sign Request">
Your app signs the request with Builder API credentials.
</Step>
<Step title="Submit to CLOB">
Order is submitted to Polymarket's CLOB with attribution headers.
</Step>
<Step title="Trade Execution">
Polymarket matches the order and covers gas fees for onchain operations.
</Step>
<Step title="Volume Attribution">
Volume is credited to your builder account.
</Step>
</Steps>
## Getting Started
<Steps>
<Step title="Create Builder Profile">
Go to
[polymarket.com/settings?tab=builder](https://polymarket.com/settings?tab=builder)
and generate your API keys.
</Step>
<Step title="Configure Attribution">
Set up your CLOB client to include builder authentication headers with every
order.
</Step>
<Step title="Enable Gasless Transactions">
Use the Relayer Client for gas-free wallet deployment and onchain
operations.
</Step>
<Step title="Track Performance">
Monitor your volume on the [Builder
Leaderboard](https://builders.polymarket.com).
</Step>
</Steps>
## SDKs and Libraries
<CardGroup cols={2}>
<Card title="CLOB Client (TypeScript)" icon="github" href="https://github.com/Polymarket/clob-client">
Place orders with builder attribution
</Card>
<Card title="CLOB Client (Python)" icon="github" href="https://github.com/Polymarket/py-clob-client">
Place orders with builder attribution
</Card>
<Card title="Relayer Client (TypeScript)" icon="github" href="https://github.com/Polymarket/builder-relayer-client">
Gasless onchain transactions
</Card>
<Card title="Relayer Client (Python)" icon="github" href="https://github.com/Polymarket/py-builder-relayer-client">
Gasless onchain transactions
</Card>
<Card title="CLOB Client (Rust)" icon="github" href="https://github.com/Polymarket/rs-clob-client">
Place orders with builder attribution
</Card>
<Card title="Signing SDK (TypeScript)" icon="github" href="https://github.com/Polymarket/builder-signing-sdk">
Sign builder authentication headers
</Card>
<Card title="Signing SDK (Python)" icon="github" href="https://github.com/Polymarket/py-builder-signing-sdk">
Sign builder authentication headers
</Card>
</CardGroup>
## Examples
These open-source demo applications show how to integrate Polymarket's CLOB Client and Builder Relayer Client for gasless trading with builder order attribution.
<CardGroup cols={3}>
<Card title="Authentication" icon="user-check">
Multiple wallet providers
</Card>
<Card title="Gasless Trading" icon="gas-pump">
Safe & Proxy wallet support
</Card>
<Card title="Full Integration" icon="puzzle-piece">
Orders, positions, CTF ops
</Card>
</CardGroup>
### Safe Wallet Examples
Deploy Gnosis Safe wallets for your users:
<CardGroup cols={2}>
<Card title="wagmi + Safe" icon="wallet" href="https://github.com/Polymarket/wagmi-safe-builder-example">
MetaMask, Phantom, Rabby, and other browser wallets
</Card>
<Card title="Privy + Safe" icon="shield-check" href="https://github.com/Polymarket/privy-safe-builder-example">
Privy embedded wallets
</Card>
<Card title="Magic Link + Safe" icon="wand-magic-sparkles" href="https://github.com/Polymarket/magic-safe-builder-example">
Magic Link email/social authentication
</Card>
<Card title="Turnkey + Safe" icon="key" href="https://github.com/Polymarket/turnkey-safe-builder-example">
Turnkey embedded wallets
</Card>
</CardGroup>
### Proxy Wallet Examples
For existing Magic Link users from Polymarket.com:
<CardGroup cols={1}>
<Card title="Magic Link + Proxy" icon="wand-magic-sparkles" href="https://github.com/Polymarket/magic-proxy-builder-example">
Auto-deploying proxy wallets for Polymarket.com Magic users
</Card>
</CardGroup>
### What Each Demo Covers
<Tabs>
<Tab title="Authentication">
* User sign-in via wallet provider
* User API credential derivation (L2 auth)
* Builder config with remote signing
* Signature types for Safe vs Proxy wallets
</Tab>
<Tab title="Wallet Operations">
* Safe wallet deployment via Relayer
* Batch token approvals (USDC.e + outcome tokens)
* CTF operations (split, merge, redeem)
* Transaction monitoring
</Tab>
<Tab title="Trading">
* CLOB client initialization
* Order placement with builder attribution
* Position and order management
* Market discovery via Gamma API
</Tab>
</Tabs>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Get API Keys" icon="key" href="/builders/api-keys">
Create and manage your Builder API credentials.
</Card>
<Card title="Understand Tiers" icon="layer-group" href="/builders/tiers">
Learn about rate limits and how to upgrade.
</Card>
<Card title="Attribute Orders" icon="tag" href="/trading/orders/attribution">
Configure your client to credit trades to your account.
</Card>
<Card title="Gasless Guide" icon="gas-pump" href="/trading/gasless">
Set up gasless transactions for your users.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,389 +0,0 @@
# Order Attribution
> Attribute orders to your builder key for volume credit
Order attribution adds builder authentication headers when placing orders through the CLOB, enabling Polymarket to credit trades to your builder account. This allows you to:
* Track volume on the [Builder Leaderboard](https://builders.polymarket.com/)
* Earn rewards through the [Builder Program](/builders/overview)
* Monitor performance via the Data API
***
## Builder API Credentials
Each builder receives API credentials from their [Builder Profile](https://polymarket.com/settings?tab=builder):
| Credential | Description |
| ------------ | ------------------------------------ |
| `key` | Your builder API key identifier |
| `secret` | Secret key for signing requests |
| `passphrase` | Additional authentication passphrase |
<Warning>
Builder API credentials are **not** the same as user API credentials. Builder
credentials are for order attribution only — you still need user credentials
for authentication. Never expose builder credentials in client-side code or
commit them to version control.
</Warning>
***
## Remote Signing
Remote signing keeps your builder credentials secure on a server you control. The user's client sends order details to your server, which adds the builder headers before forwarding to the CLOB.
### Server Implementation
Your signing server receives request details and returns the authentication headers:
<CodeGroup>
```typescript TypeScript theme={null}
import {
buildHmacSignature,
BuilderApiKeyCreds,
} from "@polymarket/builder-signing-sdk";
const BUILDER_CREDENTIALS: BuilderApiKeyCreds = {
key: process.env.POLY_BUILDER_API_KEY!,
secret: process.env.POLY_BUILDER_SECRET!,
passphrase: process.env.POLY_BUILDER_PASSPHRASE!,
};
// POST /sign - receives { method, path, body } from the client SDK
export async function handleSignRequest(request) {
const { method, path, body } = await request.json();
const timestamp = Date.now().toString();
const signature = buildHmacSignature(
BUILDER_CREDENTIALS.secret,
parseInt(timestamp),
method,
path,
body,
);
return {
POLY_BUILDER_SIGNATURE: signature,
POLY_BUILDER_TIMESTAMP: timestamp,
POLY_BUILDER_API_KEY: BUILDER_CREDENTIALS.key,
POLY_BUILDER_PASSPHRASE: BUILDER_CREDENTIALS.passphrase,
};
}
```
```python Python theme={null}
import os
import time
from py_builder_signing_sdk.signing.hmac import build_hmac_signature
from py_builder_signing_sdk import BuilderApiKeyCreds
BUILDER_CREDENTIALS = BuilderApiKeyCreds(
key=os.environ["POLY_BUILDER_API_KEY"],
secret=os.environ["POLY_BUILDER_SECRET"],
passphrase=os.environ["POLY_BUILDER_PASSPHRASE"],
)
# POST /sign - receives { method, path, body } from the client SDK
def handle_sign_request(method: str, path: str, body: str):
timestamp = str(int(time.time()))
signature = build_hmac_signature(
BUILDER_CREDENTIALS.secret,
timestamp,
method,
path,
body
)
return {
"POLY_BUILDER_SIGNATURE": signature,
"POLY_BUILDER_TIMESTAMP": timestamp,
"POLY_BUILDER_API_KEY": BUILDER_CREDENTIALS.key,
"POLY_BUILDER_PASSPHRASE": BUILDER_CREDENTIALS.passphrase,
}
```
</CodeGroup>
### Client Configuration
Point the CLOB client to your signing server:
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { BuilderConfig } from "@polymarket/builder-signing-sdk";
const builderConfig = new BuilderConfig({
remoteBuilderConfig: {
url: "https://your-server.com/sign",
token: "optional-auth-token", // optional
},
});
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
2, // signature type
funderAddress,
undefined,
false,
builderConfig,
);
// Orders automatically include builder headers
const response = await client.createAndPostOrder(/* ... */);
```
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_builder_signing_sdk import BuilderConfig, RemoteBuilderConfig
builder_config = BuilderConfig(
remote_builder_config=RemoteBuilderConfig(
url="https://your-server.com/sign",
token="optional-auth-token", # optional
)
)
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=private_key,
creds=api_creds,
signature_type=2,
funder=funder_address,
builder_config=builder_config
)
# Orders automatically include builder headers
response = client.create_and_post_order(...)
```
```rust Rust theme={null}
use polymarket_client_sdk::auth::builder::Config as BuilderConfig;
use polymarket_client_sdk::clob::types::SignatureType;
// First, authenticate as a normal user
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::GnosisSafe)
.authenticate()
.await?;
// Then promote to builder with remote signing
let builder_config = BuilderConfig::remote(
"https://your-server.com/sign",
Some("optional-auth-token".to_owned()),
)?;
let client = client.promote_to_builder(builder_config).await?;
// Orders automatically include builder headers
```
</CodeGroup>
***
## Local Signing
Sign orders locally when you control the entire order placement flow (e.g., your backend places orders on behalf of users):
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import {
BuilderConfig,
BuilderApiKeyCreds,
} from "@polymarket/builder-signing-sdk";
const builderCreds: BuilderApiKeyCreds = {
key: process.env.POLY_BUILDER_API_KEY!,
secret: process.env.POLY_BUILDER_SECRET!,
passphrase: process.env.POLY_BUILDER_PASSPHRASE!,
};
const builderConfig = new BuilderConfig({
localBuilderCreds: builderCreds,
});
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
2,
funderAddress,
undefined,
false,
builderConfig,
);
// Orders automatically include builder headers
const response = await client.createAndPostOrder(/* ... */);
```
```python Python theme={null}
import os
from py_clob_client.client import ClobClient
from py_builder_signing_sdk import BuilderConfig, BuilderApiKeyCreds
builder_creds = BuilderApiKeyCreds(
key=os.environ["POLY_BUILDER_API_KEY"],
secret=os.environ["POLY_BUILDER_SECRET"],
passphrase=os.environ["POLY_BUILDER_PASSPHRASE"],
)
builder_config = BuilderConfig(
local_builder_creds=builder_creds,
)
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=private_key,
creds=api_creds,
signature_type=2,
funder=funder_address,
builder_config=builder_config
)
# Orders automatically include builder headers
response = client.create_and_post_order(...)
```
```rust Rust theme={null}
use polymarket_client_sdk::auth::{Credentials, builder::Config as BuilderConfig};
let builder_creds = Credentials::new(
std::env::var("POLY_BUILDER_API_KEY")?.parse()?,
std::env::var("POLY_BUILDER_SECRET")?,
std::env::var("POLY_BUILDER_PASSPHRASE")?,
);
let builder_config = BuilderConfig::local(builder_creds);
let client = client.promote_to_builder(builder_config).await?;
// Orders automatically include builder headers
```
</CodeGroup>
***
## Authentication Headers
The SDK automatically generates and attaches these headers to each request:
| Header | Description |
| ------------------------- | ------------------------------------ |
| `POLY_BUILDER_API_KEY` | Your builder API key |
| `POLY_BUILDER_TIMESTAMP` | Unix timestamp of signature creation |
| `POLY_BUILDER_PASSPHRASE` | Your builder passphrase |
| `POLY_BUILDER_SIGNATURE` | HMAC signature of the request |
<Info>
With **local signing**, the SDK constructs and attaches these headers
automatically. With **remote signing**, your server returns these headers and
the SDK attaches them.
</Info>
***
## Verifying Attribution
### Get Builder Trades
Query trades attributed to your builder account to verify attribution is working:
<CodeGroup>
```typescript TypeScript theme={null}
const trades = await client.getBuilderTrades();
// Filtered by market
const marketTrades = await client.getBuilderTrades({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
trades = client.get_builder_trades()
market_trades = client.get_builder_trades(
market="0xbd31dc8a..."
)
```
```rust Rust theme={null}
use polymarket_client_sdk::clob::types::request::TradesRequest;
let trades = client.builder_trades(&TradesRequest::default(), None).await?;
// Filtered by market
let request = TradesRequest::builder()
.market("0xbd31dc8a...".parse()?)
.build();
let market_trades = client.builder_trades(&request, None).await?;
```
</CodeGroup>
Each `BuilderTrade` includes: `id`, `market`, `assetId`, `side`, `size`, `price`, `status`, `outcome`, `owner`, `maker`, `transactionHash`, `matchTime`, `fee`, and `feeUsdc`.
### Revoke Builder API Key
If your credentials are compromised, revoke them immediately:
<CodeGroup>
```typescript TypeScript theme={null}
await client.revokeBuilderApiKey();
```
```python Python theme={null}
client.revoke_builder_api_key()
```
```rust Rust theme={null}
client.revoke_builder_api_key().await?;
```
</CodeGroup>
After revoking, generate new credentials from your [Builder Profile](https://polymarket.com/settings?tab=builder).
***
## Troubleshooting
<AccordionGroup>
<Accordion title="Invalid Signature Errors">
* Verify the request body is passed correctly as JSON - Check that `path`,
`body`, and `method` match what the client sends - Ensure your server and
client use the same Builder API credentials
</Accordion>
<Accordion title="Missing Credentials">
Ensure your environment variables are set: - `POLY_BUILDER_API_KEY` -
`POLY_BUILDER_SECRET` - `POLY_BUILDER_PASSPHRASE`
</Accordion>
<Accordion title="Volume not appearing on leaderboard">
* Confirm your builder credentials are valid and not revoked - Check that
orders are being placed with the builder config attached - Allow up to 24
hours for volume to appear on the leaderboard
</Accordion>
</AccordionGroup>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Builder Program" icon="hammer" href="/builders/overview">
Learn about the Builder Program tiers and rewards
</Card>
<Card title="Create Orders" icon="plus" href="/trading/orders/create">
Build, sign, and submit orders
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-575
View File
@@ -1,575 +0,0 @@
# Gasless Transactions
> Execute onchain operations without paying gas fees
Polymarket's **Relayer Client** enables gasless transactions for your users. Instead of requiring users to hold POL for gas, Polymarket's infrastructure pays all transaction fees. This creates a seamless experience where users only need USDC.e to trade.
## How It Works
The relayer acts as a transaction sponsor:
1. Your app creates a transaction
2. The user signs it with their private key
3. Your app sends it to Polymarket's relayer
4. The relayer submits it onchain and pays the gas fee
5. The transaction executes from the user's wallet
<Note>
Gasless transactions require authentication with **Builder API Keys** or **Relayer API Keys**.
</Note>
## What Is Covered
Polymarket pays gas for all operations routed through the relayer:
| Operation | Description |
| --------------------- | --------------------------------------------------- |
| **Wallet deployment** | Deploy Safe or Proxy wallets for new users |
| **Token approvals** | Approve contracts to spend USDC.e or outcome tokens |
| **CTF operations** | Split, merge, and redeem positions |
| **Transfers** | Move tokens between addresses |
## Authentication
The relayer supports two authentication methods. Choose the one that fits your use case.
### Using Builder API Keys
Builder API Keys are for [Builder Program](/builders/overview) members. They authenticate via HMAC-SHA256 signed headers and are required to use the relayer SDKs.
All requests must include these headers:
| Header | Description |
| ------------------------- | ----------------------- |
| `POLY_BUILDER_API_KEY` | Your Builder API key |
| `POLY_BUILDER_TIMESTAMP` | Unix timestamp |
| `POLY_BUILDER_PASSPHRASE` | Your Builder passphrase |
| `POLY_BUILDER_SIGNATURE` | HMAC-SHA256 signature |
The SDKs handle header generation automatically when you provide your credentials via `BuilderConfig`.
### Using Relayer API Keys
Relayer API Keys are for market makers and anyone who needs a simpler alternative. You can create them from [Settings > API Keys](https://polymarket.com/settings?tab=api-keys) on the Polymarket website.
Include these headers with your requests:
| Header | Description |
| ------------------------- | ----------------------------- |
| `RELAYER_API_KEY` | Your Relayer API key |
| `RELAYER_API_KEY_ADDRESS` | The address that owns the key |
<Info>
If you want to use the Relayer API Key directly without the SDK, see the [Relayer API Reference](/api-reference/relayer).
</Info>
## Prerequisites
Before using the relayer, you need:
| Requirement | Source |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Builder API credentials **or** Relayer API key | [Builder Profile](https://polymarket.com/settings?tab=builder) or [Settings > API Keys](https://polymarket.com/settings?tab=api-keys) |
| User's private key or signer | Your wallet integration |
| USDC.e balance | For trading (not for gas) |
> The below section is for the Builder SDKs only. If you want to use the Relayer API Key directly without the SDK, see the [Relayer API Reference](/api-reference/relayer).
## Installation
<CodeGroup>
```bash npm theme={null}
npm install @polymarket/builder-relayer-client @polymarket/builder-signing-sdk
```
```bash pip theme={null}
pip install py-builder-relayer-client py-builder-signing-sdk
```
</CodeGroup>
## Client Setup
Initialize the relayer client with your signing configuration:
<Tabs>
<Tab title="Local Signing">
Use local signing when your backend handles all transactions securely.
<CodeGroup>
```typescript TypeScript theme={null}
import { createWalletClient, http, Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygon } from "viem/chains";
import { RelayClient } from "@polymarket/builder-relayer-client";
import { BuilderConfig } from "@polymarket/builder-signing-sdk";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const wallet = createWalletClient({
account,
chain: polygon,
transport: http(process.env.RPC_URL),
});
const builderConfig = new BuilderConfig({
localBuilderCreds: {
key: process.env.POLY_BUILDER_API_KEY!,
secret: process.env.POLY_BUILDER_SECRET!,
passphrase: process.env.POLY_BUILDER_PASSPHRASE!,
},
});
const client = new RelayClient(
"https://relayer-v2.polymarket.com/",
137,
wallet,
builderConfig,
);
```
```python Python theme={null}
import os
from py_builder_relayer_client.client import RelayClient
from py_builder_signing_sdk import BuilderConfig, BuilderApiKeyCreds
builder_config = BuilderConfig(
local_builder_creds=BuilderApiKeyCreds(
key=os.getenv("POLY_BUILDER_API_KEY"),
secret=os.getenv("POLY_BUILDER_SECRET"),
passphrase=os.getenv("POLY_BUILDER_PASSPHRASE"),
)
)
client = RelayClient(
"https://relayer-v2.polymarket.com",
137,
os.getenv("PRIVATE_KEY"),
builder_config
)
```
</CodeGroup>
</Tab>
<Tab title="Remote Signing">
Use remote signing to keep credentials on a secure server you control.
**Your signing server** receives request details and returns authentication headers:
<CodeGroup>
```typescript Server (TypeScript) theme={null}
import {
buildHmacSignature,
BuilderApiKeyCreds,
} from "@polymarket/builder-signing-sdk";
const BUILDER_CREDENTIALS: BuilderApiKeyCreds = {
key: process.env.POLY_BUILDER_API_KEY!,
secret: process.env.POLY_BUILDER_SECRET!,
passphrase: process.env.POLY_BUILDER_PASSPHRASE!,
};
// POST /sign endpoint
export async function handleSignRequest(request) {
const { method, path, body } = await request.json();
const timestamp = Date.now().toString();
const signature = buildHmacSignature(
BUILDER_CREDENTIALS.secret,
parseInt(timestamp),
method,
path,
body,
);
return {
POLY_BUILDER_SIGNATURE: signature,
POLY_BUILDER_TIMESTAMP: timestamp,
POLY_BUILDER_API_KEY: BUILDER_CREDENTIALS.key,
POLY_BUILDER_PASSPHRASE: BUILDER_CREDENTIALS.passphrase,
};
}
```
```python Server (Python) theme={null}
import os
import time
from py_builder_signing_sdk.signing.hmac import build_hmac_signature
from py_builder_signing_sdk import BuilderApiKeyCreds
BUILDER_CREDENTIALS = BuilderApiKeyCreds(
key=os.environ["POLY_BUILDER_API_KEY"],
secret=os.environ["POLY_BUILDER_SECRET"],
passphrase=os.environ["POLY_BUILDER_PASSPHRASE"],
)
# POST /sign endpoint
def handle_sign_request(method: str, path: str, body: str):
timestamp = str(int(time.time()))
signature = build_hmac_signature(
BUILDER_CREDENTIALS.secret,
timestamp,
method,
path,
body
)
return {
"POLY_BUILDER_SIGNATURE": signature,
"POLY_BUILDER_TIMESTAMP": timestamp,
"POLY_BUILDER_API_KEY": BUILDER_CREDENTIALS.key,
"POLY_BUILDER_PASSPHRASE": BUILDER_CREDENTIALS.passphrase,
}
```
</CodeGroup>
**Your client** points to your signing server:
<CodeGroup>
```typescript Client (TypeScript) theme={null}
import { RelayClient } from "@polymarket/builder-relayer-client";
import { BuilderConfig } from "@polymarket/builder-signing-sdk";
const builderConfig = new BuilderConfig({
remoteBuilderConfig: {
url: "https://your-server.com/sign",
},
});
const client = new RelayClient(
"https://relayer-v2.polymarket.com/",
137,
wallet,
builderConfig,
);
```
```python Client (Python) theme={null}
from py_builder_relayer_client.client import RelayClient
from py_builder_signing_sdk import BuilderConfig, RemoteBuilderConfig
builder_config = BuilderConfig(
remote_builder_config=RemoteBuilderConfig(
url="https://your-server.com/sign"
)
)
client = RelayClient(
"https://relayer-v2.polymarket.com",
137,
private_key,
builder_config
)
```
</CodeGroup>
</Tab>
</Tabs>
<Warning>
Never expose Builder API credentials in client-side code. Use environment
variables or a secrets manager.
</Warning>
## Wallet Types
Choose a wallet type when initializing the client:
| Type | Deployment | Best For |
| --------- | ---------------------------------------- | ------------------------- |
| **Safe** | Call `deploy()` before first transaction | Most builder integrations |
| **Proxy** | Auto-deploys on first transaction | Magic Link users |
<CodeGroup>
```typescript Safe Wallet (TypeScript) theme={null}
import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client";
const client = new RelayClient(
"https://relayer-v2.polymarket.com/",
137,
wallet,
builderConfig,
RelayerTxType.SAFE,
);
// Deploy before first transaction
const response = await client.deploy();
const result = await response.wait();
console.log("Safe Address:", result?.proxyAddress);
```
```python Safe Wallet (Python) theme={null}
from py_builder_relayer_client.client import RelayClient
# client initialized with builder_config (see Client Setup above)
# Deploy before first transaction
response = client.deploy()
result = response.wait()
print("Safe Address:", result.get("proxyAddress"))
```
```typescript Proxy Wallet (TypeScript) theme={null}
import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client";
const client = new RelayClient(
"https://relayer-v2.polymarket.com/",
137,
wallet,
builderConfig,
RelayerTxType.PROXY,
);
// No deploy needed - auto-deploys on first transaction
```
```python Proxy Wallet (Python) theme={null}
from py_builder_relayer_client.client import RelayClient
# client initialized with builder_config (see Client Setup above)
# No deploy needed - auto-deploys on first transaction
```
</CodeGroup>
## Executing Transactions
Use the `execute` method to send transactions through the relayer:
```typescript theme={null}
interface Transaction {
to: string; // Target contract address
data: string; // Encoded function call
value: string; // POL to send (usually "0")
}
const response = await client.execute(transactions, "Description");
const result = await response.wait();
```
### Token Approval
Approve contracts to spend tokens:
<CodeGroup>
```typescript TypeScript theme={null}
import { encodeFunctionData, maxUint256 } from "viem";
const USDC = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045";
const approveTx = {
to: USDC,
data: encodeFunctionData({
abi: [
{
name: "approve",
type: "function",
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ type: "bool" }],
},
],
functionName: "approve",
args: [CTF, maxUint256],
}),
value: "0",
};
const response = await client.execute([approveTx], "Approve USDC.e for CTF");
await response.wait();
```
```python Python theme={null}
from web3 import Web3
USDC = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
MAX_UINT256 = 2**256 - 1
approve_tx = {
"to": USDC,
"data": Web3().eth.contract(
address=USDC,
abi=[{
"name": "approve",
"type": "function",
"inputs": [
{"name": "spender", "type": "address"},
{"name": "amount", "type": "uint256"}
],
"outputs": [{"type": "bool"}]
}]
).encode_abi(abi_element_identifier="approve", args=[CTF, MAX_UINT256]),
"value": "0"
}
response = client.execute([approve_tx], "Approve USDC.e for CTF")
response.wait()
```
</CodeGroup>
### Redeem Positions
Exchange winning tokens for USDC.e after market resolution:
<CodeGroup>
```typescript TypeScript theme={null}
import { encodeFunctionData } from "viem";
const redeemTx = {
to: CTF_ADDRESS,
data: encodeFunctionData({
abi: [
{
name: "redeemPositions",
type: "function",
inputs: [
{ name: "collateralToken", type: "address" },
{ name: "parentCollectionId", type: "bytes32" },
{ name: "conditionId", type: "bytes32" },
{ name: "indexSets", type: "uint256[]" },
],
outputs: [],
},
],
functionName: "redeemPositions",
args: [collateralToken, parentCollectionId, conditionId, indexSets],
}),
value: "0",
};
const response = await client.execute([redeemTx], "Redeem positions");
await response.wait();
```
```python Python theme={null}
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
redeem_tx = {
"to": CTF,
"data": Web3().eth.contract(
address=CTF,
abi=[{
"name": "redeemPositions",
"type": "function",
"inputs": [
{"name": "collateralToken", "type": "address"},
{"name": "parentCollectionId", "type": "bytes32"},
{"name": "conditionId", "type": "bytes32"},
{"name": "indexSets", "type": "uint256[]"}
],
"outputs": []
}]
).encode_abi(
abi_element_identifier="redeemPositions",
args=[collateral_token, parent_collection_id, condition_id, index_sets]
),
"value": "0"
}
response = client.execute([redeem_tx], "Redeem positions")
response.wait()
```
</CodeGroup>
### Batch Transactions
Execute multiple operations atomically in a single call:
<CodeGroup>
```typescript TypeScript theme={null}
const approveTx = {
to: USDC,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "approve",
args: [CTF, maxUint256],
}),
value: "0",
};
const transferTx = {
to: USDC,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [recipientAddress, parseUnits("50", 6)],
}),
value: "0",
};
// Both execute atomically
const response = await client.execute(
[approveTx, transferTx],
"Approve and transfer",
);
await response.wait();
```
```python Python theme={null}
approve_tx = {
"to": USDC,
"data": contract.encode_abi(
abi_element_identifier="approve",
args=[CTF, MAX_UINT256]
),
"value": "0"
}
transfer_tx = {
"to": USDC,
"data": contract.encode_abi(
abi_element_identifier="transfer",
args=[recipient_address, 50 * 10**6]
),
"value": "0"
}
# Both execute atomically
response = client.execute([approve_tx, transfer_tx], "Approve and transfer")
response.wait()
```
</CodeGroup>
<Tip>
Batching reduces latency and ensures all transactions succeed or fail
together.
</Tip>
## Transaction States
Track transaction progress through these states:
| State | Terminal | Description |
| ----------------- | -------- | ------------------------------- |
| `STATE_NEW` | No | Transaction received by relayer |
| `STATE_EXECUTED` | No | Submitted onchain |
| `STATE_MINED` | No | Included in a block |
| `STATE_CONFIRMED` | Yes | Finalized successfully |
| `STATE_FAILED` | Yes | Failed permanently |
| `STATE_INVALID` | Yes | Rejected as invalid |
## Contract Addresses
See [Contract Addresses](/resources/contract-addresses) for all Polymarket smart contract addresses on Polygon.
## Resources
* [Builder Relayer Client (TypeScript)](https://github.com/Polymarket/builder-relayer-client)
* [Builder Relayer Client (Python)](https://github.com/Polymarket/py-builder-relayer-client)
* [Builder Signing SDK (TypeScript)](https://github.com/Polymarket/builder-signing-sdk)
* [Builder Signing SDK (Python)](https://github.com/Polymarket/py-builder-signing-sdk)
## Next Steps
<CardGroup cols={2}>
<Card title="Negative Risk Markets" icon="scale-balanced" href="/advanced/neg-risk">
Learn about capital-efficient trading for multi-outcome events.
</Card>
<Card title="Positions & Tokens" icon="coins" href="/concepts/positions-tokens">
Understand token operations like split, merge, and redeem.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,154 +0,0 @@
# Fetching Markets
> Three strategies for discovering and querying markets
<Tip>
Both the events and markets endpoints are paginated. See
[pagination](#pagination) for details.
</Tip>
There are three main strategies for retrieving market data, each optimized for different use cases:
1. **By Slug** — Best for fetching specific individual markets or events
2. **By Tags** — Ideal for filtering markets by category or sport
3. **Via Events Endpoint** — Most efficient for retrieving all active markets
***
## Fetch by Slug
**Use case:** When you need to retrieve a specific market or event that you already know about.
Individual markets and events are best fetched using their unique slug identifier. The slug can be found directly in the Polymarket frontend URL.
### How to Extract the Slug
From any Polymarket URL, the slug is the path segment after `/event/`:
```
https://polymarket.com/event/fed-decision-in-october
Slug: fed-decision-in-october
```
### Examples
```bash theme={null}
# Fetch an event by slug (query parameter)
curl "https://gamma-api.polymarket.com/events?slug=fed-decision-in-october"
# Or use the path endpoint
curl "https://gamma-api.polymarket.com/events/slug/fed-decision-in-october"
```
```bash theme={null}
# Fetch a market by slug (query parameter)
curl "https://gamma-api.polymarket.com/markets?slug=fed-decision-in-october"
# Or use the path endpoint
curl "https://gamma-api.polymarket.com/markets/slug/fed-decision-in-october"
```
***
## Fetch by Tags
**Use case:** When you want to filter markets by category, sport, or topic.
Tags provide a way to categorize and filter markets. You can discover available tags and then use them to filter your requests.
### Discover Available Tags
**General tags:** `GET /tags` (Gamma API)
**Sports tags and metadata:** `GET /sports` (Gamma API)
The `/sports` endpoint returns metadata for sports including tag IDs, images, resolution sources, and series information.
### Filter by Tag
Once you have tag IDs, use the `tag_id` parameter in both events and markets endpoints:
```bash theme={null}
# Fetch events for a specific tag
curl "https://gamma-api.polymarket.com/events?tag_id=100381&limit=10&active=true&closed=false"
```
### Additional Tag Filtering
You can also:
* Use `related_tags=true` to include related tag markets
* Exclude specific tags with `exclude_tag_id`
```bash theme={null}
# Include related tags
curl "https://gamma-api.polymarket.com/events?tag_id=100381&related_tags=true&active=true&closed=false"
```
***
## Fetch All Active Markets
**Use case:** When you need to retrieve all available active markets, typically for broader analysis or market discovery.
The most efficient approach is to use the events endpoint with `active=true&closed=false`, as events contain their associated markets.
```bash theme={null}
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=100"
```
### Key Parameters
| Parameter | Description |
| ----------- | ---------------------------------------------------------------------------------------------------------------- |
| `order` | Field to order by (`volume_24hr`, `volume`, `liquidity`, `start_date`, `end_date`, `competitive`, `closed_time`) |
| `ascending` | Sort direction (`true` for ascending, `false` for descending). Default: `false` |
| `active` | Filter by active status (`true` for live tradable events) |
| `closed` | Filter by closed status. Default: `false` |
| `limit` | Results per page |
| `offset` | Number of results to skip for pagination |
```bash theme={null}
# Get the highest volume active events
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&order=volume_24hr&ascending=false&limit=100"
```
***
## Pagination
All list endpoints return paginated responses with `limit` and `offset` parameters:
```bash theme={null}
# Page 1: First 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=0"
# Page 2: Next 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=50"
# Page 3: Next 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=100"
```
***
## Best Practices
1. **For individual markets:** Use the slug method for direct lookups
2. **For category browsing:** Use tag filtering to reduce API calls
3. **For complete market discovery:** Use the events endpoint with pagination
4. **Always include `active=true`** when fetching live markets. The `closed` parameter now defaults to `false`, so closed markets are excluded automatically — pass `closed=true` only if you need historical data
5. **Use the events endpoint** and work backwards — events contain their associated markets, reducing the number of API calls needed
***
## Next Steps
<CardGroup cols={2}>
<Card title="API Reference" icon="code" href="/api-reference/introduction">
Full endpoint documentation with parameters and response schemas.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,106 +0,0 @@
# Markets & Events
> Understanding the fundamental building blocks of Polymarket
Every prediction on Polymarket is structured around two core concepts: **markets** and **events**. Understanding how they relate is essential for building on the platform.
<Frame>
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event-market.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=4c62bd08a405868307cdd6799b368ca5" alt="" className="dark:hidden" width="1540" height="952" data-path="images/core-concepts/event-market.png" />
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event-market.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=2eb5c9b0f8a2afe52bc2e717b7b796a2" alt="" className="hidden dark:block" width="1540" height="952" data-path="images/dark/core-concepts/event-market.png" />
</Frame>
## Markets
A **market** is the fundamental tradable unit on Polymarket. Each market represents a single binary question with Yes/No outcomes.
<Frame>
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=0c9a264aec9a22ce5a20c4cc7980806d" alt="" className="dark:hidden" width="1540" height="952" data-path="images/core-concepts/event.png" />
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=912e41bebfe8c1a43ef53b89685ca3d2" alt="" className="hidden dark:block" width="1540" height="952" data-path="images/dark/core-concepts/event.png" />
</Frame>
Every market has:
| Identifier | Description |
| ---------------- | ------------------------------------------------------------------------ |
| **Condition ID** | Unique identifier for the market's condition in the CTF contracts |
| **Question ID** | Hash of the market question used for resolution |
| **Token IDs** | ERC1155 token IDs used for trading on the CLOB — one for Yes, one for No |
<Note>
Markets can only be traded via the CLOB if `enableOrderBook` is `true`. Some
markets may exist onchain but not be available for order book trading.
</Note>
### Market Example
A simple market might be:
> **"Will Bitcoin reach \$150,000 by December 2026?"**
This creates two outcome tokens:
* **Yes token** - Redeemable for `$1` if Bitcoin reaches `$150k`
* **No token** - Redeemable for `$1` if Bitcoin doesn't reach `$100k`
## Events
An **event** is a container that groups one or more related markets together. Events provide organizational structure and enable multi-outcome predictions.
### Single-Market Events
When an event contains just one market, it creates a simple market pair. The event and market are essentially equivalent.
```
Event: Will Bitcoin reach $100,000 by December 2024?
└── Market: Will Bitcoin reach $100,000 by December 2024? (Yes/No)
```
### Multi-Market Events
When an event contains two or more markets, it creates a grouped market pair. This enables mutually exclusive multi-outcome predictions.
```
Event: Who will win the 2024 Presidential Election?
├── Market: Donald Trump? (Yes/No)
├── Market: Joe Biden? (Yes/No)
├── Market: Kamala Harris? (Yes/No)
└── Market: Other? (Yes/No)
```
## Identifying Markets
Every market and event has a unique **slug** that appears in the Polymarket URL:
```
https://polymarket.com/event/fed-decision-in-october
└── slug: fed-decision-in-october
```
You can use slugs to fetch specific markets or events from the API:
```bash theme={null}
# Fetch event by slug
curl "https://gamma-api.polymarket.com/events?slug=fed-decision-in-october"
```
## Sports Markets
Specifically for sports markets, outstanding limit orders are **automatically cancelled** once the game begins, clearing the order book at the official start time. However, game start times can shift — if a game starts earlier than scheduled, orders may not be cleared in time. Always monitor your orders closely around game start times.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Prices & Orderbook" icon="chart-line" href="/concepts/prices-orderbook">
Learn how prices are determined and how the order book works.
</Card>
<Card title="Fetching Market Data" icon="code" href="/market-data/overview">
Start querying markets and events from the API.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,109 +0,0 @@
# Overview
> Fetch market data with no authentication required
All market data is available through public REST endpoints. No API key, no authentication, no wallet required.
```bash theme={null}
curl "https://gamma-api.polymarket.com/events?limit=5"
```
***
## Data Model
Polymarket structures data using two organizational models. The most fundamental element is always markets—events simply provide additional organization.
<Steps>
<Step title="Event">
A top-level object representing a question (e.g., "Who will win the 2024
Presidential Election?"). Contains one or more markets.
</Step>
<Step title="Market">
A specific tradable binary outcome within an event. Maps to a pair of CLOB
token IDs, a market address, a question ID, and a condition ID.
</Step>
</Steps>
### Single-Market Events vs Multi-Market Events
| Type | Example |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| Single-market event | "Will Bitcoin reach \$100k?" → 1 market (Yes/No) |
| Multi-market event | "Where will Barron Trump attend College?" → Markets for Georgetown, NYU, UPenn, Harvard, Other |
### Outcomes and Prices
Each market has `outcomes` and `outcomePrices` arrays that map 1:1. Prices represent implied probabilities:
```json theme={null}
{
"outcomes": "[\"Yes\", \"No\"]",
"outcomePrices": "[\"0.20\", \"0.80\"]"
}
// Index 0: "Yes" → 0.20 (20% probability)
// Index 1: "No" → 0.80 (80% probability)
```
<Info>Markets can be traded via the CLOB if `enableOrderBook` is `true`.</Info>
***
## Available Data
Endpoints are split across three APIs. See the [API Reference](/api-reference/introduction) for full endpoint documentation with parameters and response schemas.
### Gamma API - Events Markets and Discovery
| Endpoint | Description |
| -------------------- | ------------------------------------------- |
| `GET /events` | List events with filtering and pagination |
| `GET /events/{id}` | Get a single event by ID |
| `GET /markets` | List markets with filtering and pagination |
| `GET /markets/{id}` | Get a single market by ID |
| `GET /public-search` | Search across events, markets, and profiles |
| `GET /tags` | Ranked tags/categories |
| `GET /series` | Series (grouped events) |
| `GET /sports` | Sports metadata |
| `GET /teams` | Teams |
### CLOB API - Prices and Orderbooks
| Endpoint | Description |
| --------------------- | --------------------------------- |
| `GET /price` | Price for a single token |
| `GET /prices` | Prices for multiple tokens |
| `GET /book` | Order book for a token |
| `POST /books` | Order books for multiple tokens |
| `GET /prices-history` | Historical price data for a token |
| `GET /midpoint` | Midpoint price for a token |
| `GET /spread` | Spread for a token |
### Data API - Positions Trades and Analytics
| Endpoint | Description |
| -------------------------------------- | ---------------------------- |
| `GET /positions?user={address}` | Current positions for a user |
| `GET /closed-positions?user={address}` | Closed positions for a user |
| `GET /activity?user={address}` | Onchain activity for a user |
| `GET /value?user={address}` | Total position value |
| `GET /oi` | Open interest for a market |
| `GET /holders` | Top holders of a market |
| `GET /trades` | Trade history |
***
## Next Steps
<CardGroup cols={2}>
<Card title="Fetching Markets" icon="magnifying-glass" href="/market-data/fetching-markets">
Three strategies for discovering and querying markets.
</Card>
<Card title="API Reference" icon="code" href="/api-reference/introduction">
Full endpoint documentation with parameters and response schemas.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-154
View File
@@ -1,154 +0,0 @@
# Fetching Markets
> Three strategies for discovering and querying markets
<Tip>
Both the events and markets endpoints are paginated. See
[pagination](#pagination) for details.
</Tip>
There are three main strategies for retrieving market data, each optimized for different use cases:
1. **By Slug** — Best for fetching specific individual markets or events
2. **By Tags** — Ideal for filtering markets by category or sport
3. **Via Events Endpoint** — Most efficient for retrieving all active markets
***
## Fetch by Slug
**Use case:** When you need to retrieve a specific market or event that you already know about.
Individual markets and events are best fetched using their unique slug identifier. The slug can be found directly in the Polymarket frontend URL.
### How to Extract the Slug
From any Polymarket URL, the slug is the path segment after `/event/`:
```
https://polymarket.com/event/fed-decision-in-october
Slug: fed-decision-in-october
```
### Examples
```bash theme={null}
# Fetch an event by slug (query parameter)
curl "https://gamma-api.polymarket.com/events?slug=fed-decision-in-october"
# Or use the path endpoint
curl "https://gamma-api.polymarket.com/events/slug/fed-decision-in-october"
```
```bash theme={null}
# Fetch a market by slug (query parameter)
curl "https://gamma-api.polymarket.com/markets?slug=fed-decision-in-october"
# Or use the path endpoint
curl "https://gamma-api.polymarket.com/markets/slug/fed-decision-in-october"
```
***
## Fetch by Tags
**Use case:** When you want to filter markets by category, sport, or topic.
Tags provide a way to categorize and filter markets. You can discover available tags and then use them to filter your requests.
### Discover Available Tags
**General tags:** `GET /tags` (Gamma API)
**Sports tags and metadata:** `GET /sports` (Gamma API)
The `/sports` endpoint returns metadata for sports including tag IDs, images, resolution sources, and series information.
### Filter by Tag
Once you have tag IDs, use the `tag_id` parameter in both events and markets endpoints:
```bash theme={null}
# Fetch events for a specific tag
curl "https://gamma-api.polymarket.com/events?tag_id=100381&limit=10&active=true&closed=false"
```
### Additional Tag Filtering
You can also:
* Use `related_tags=true` to include related tag markets
* Exclude specific tags with `exclude_tag_id`
```bash theme={null}
# Include related tags
curl "https://gamma-api.polymarket.com/events?tag_id=100381&related_tags=true&active=true&closed=false"
```
***
## Fetch All Active Markets
**Use case:** When you need to retrieve all available active markets, typically for broader analysis or market discovery.
The most efficient approach is to use the events endpoint with `active=true&closed=false`, as events contain their associated markets.
```bash theme={null}
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=100"
```
### Key Parameters
| Parameter | Description |
| ----------- | ---------------------------------------------------------------------------------------------------------------- |
| `order` | Field to order by (`volume_24hr`, `volume`, `liquidity`, `start_date`, `end_date`, `competitive`, `closed_time`) |
| `ascending` | Sort direction (`true` for ascending, `false` for descending). Default: `false` |
| `active` | Filter by active status (`true` for live tradable events) |
| `closed` | Filter by closed status. Default: `false` |
| `limit` | Results per page |
| `offset` | Number of results to skip for pagination |
```bash theme={null}
# Get the highest volume active events
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&order=volume_24hr&ascending=false&limit=100"
```
***
## Pagination
All list endpoints return paginated responses with `limit` and `offset` parameters:
```bash theme={null}
# Page 1: First 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=0"
# Page 2: Next 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=50"
# Page 3: Next 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=100"
```
***
## Best Practices
1. **For individual markets:** Use the slug method for direct lookups
2. **For category browsing:** Use tag filtering to reduce API calls
3. **For complete market discovery:** Use the events endpoint with pagination
4. **Always include `active=true`** when fetching live markets. The `closed` parameter now defaults to `false`, so closed markets are excluded automatically — pass `closed=true` only if you need historical data
5. **Use the events endpoint** and work backwards — events contain their associated markets, reducing the number of API calls needed
***
## Next Steps
<CardGroup cols={2}>
<Card title="API Reference" icon="code" href="/api-reference/introduction">
Full endpoint documentation with parameters and response schemas.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,81 +0,0 @@
# Overview
> Market making on Polymarket
A Market Maker (MM) on Polymarket is a trader who provides liquidity to prediction markets by continuously posting bid and ask orders. By laying the spread, market makers enable other users to trade efficiently while earning the spread as compensation for the risk they take.
Market makers are essential to Polymarket's ecosystem — they provide liquidity across markets, tighten spreads for better user experience, enable price discovery through continuous quoting, and absorb trading flow from retail and institutional users.
<Note>
**Not a Market Maker?** If you're building an application that routes orders
for your users, see the [Builder Program](/builders/overview) instead.
</Note>
***
## Getting Started
<Steps>
<Step title="Complete Setup">
Deploy wallets, fund with USDC.e, and set token approvals. See the [Getting
Started](/market-makers/getting-started) guide.
</Step>
<Step title="Connect to Data Feeds">
WebSocket for real-time orderbook updates, Gamma API for market metadata.
See [Market Data](/market-data/overview).
</Step>
<Step title="Start Quoting">
Post orders via the CLOB REST API. See [Trading ](/market-makers/trading).
</Step>
</Steps>
***
## Quick Reference
| Action | Tool | Documentation |
| ---------------------- | -------------- | ------------------------------------------------- |
| Deposit USDC.e | Bridge API | [Bridge](/trading/bridge/deposit) |
| Approve tokens | Relayer Client | [Getting Started](/market-makers/getting-started) |
| Post limit orders | CLOB REST API | [Create Orders](/trading/orders/create) |
| Monitor orderbook | WebSocket | [WebSocket](/market-data/websocket/overview) |
| Split USDC.e to tokens | CTF / Relayer | [Inventory](/market-makers/inventory) |
| Merge tokens to USDC.e | CTF / Relayer | [Inventory](/market-makers/inventory) |
***
## What Is in This Section
<CardGroup cols={2}>
<Card title="Getting Started" icon="gear" href="/market-makers/getting-started">
Deposits, token approvals, wallet deployment, API keys
</Card>
<Card title="Trading" icon="chart-line" href="/market-makers/trading">
Quoting best practices, strategies, and risk controls
</Card>
<Card title="Inventory Management" icon="boxes-stacked" href="/market-makers/inventory">
Split, merge, and redeem outcome tokens
</Card>
<Card title="Liquidity Rewards" icon="gift" href="/market-makers/liquidity-rewards">
Earn rewards for providing liquidity
</Card>
</CardGroup>
## Risks
<Warning>
Be careful with spread management — if your bid price is higher than your ask
price (a "negative spread" or "crossed market"), you will lose money on every
fill. Always validate your quote prices before submission.
</Warning>
## Support
For market maker onboarding and support, contact [support@polymarket.com](mailto:support@polymarket.com).
Built with [Mintlify](https://mintlify.com).
-225
View File
@@ -1,225 +0,0 @@
# Getting Started
> One-time setup for market making on Polymarket
Before you can start market making, you need to complete these one-time setup steps — deposit USDC.e to Polygon, deploy a wallet, approve tokens for trading, and generate API credentials.
<Steps>
<Step title="Deposit USDC.e">
Market makers need USDC.e on Polygon to fund their trading operations.
| Method | Best For | Documentation |
| ----------------------- | ------------------------------------ | ---------------------------------------------------- |
| Bridge API | Automated deposits from other chains | [Bridge Deposit](/trading/bridge/deposit) |
| Direct Polygon transfer | Already have USDC.e on Polygon | N/A |
| Cross-chain bridge | Large deposits from Ethereum | [Supported Assets](/trading/bridge/supported-assets) |
### Using the Bridge API
```typescript theme={null}
// Get deposit addresses for your Polymarket wallet
const deposit = await fetch("https://bridge.polymarket.com/deposit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
address: "YOUR_POLYMARKET_WALLET_ADDRESS",
}),
});
// Returns deposit addresses for EVM, SVM, and BTC networks
const addresses = await deposit.json();
// Send USDC to the appropriate address for your source chain
```
</Step>
<Step title="Deploy a Wallet">
### EOA
Standard Ethereum wallet. You pay for all onchain transactions (approvals, splits, merges, trade execution).
### Safe Wallet
Gnosis Safe-based wallet deployed via Polymarket's relayer. Benefits:
* **Gasless transactions** — Polymarket pays gas fees for onchain operations
* **Contract wallet** — Enables advanced features like batched transactions
Deploy a Safe wallet using the Relayer Client:
<CodeGroup>
```typescript TypeScript theme={null}
import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client";
const client = new RelayClient(
"https://relayer-v2.polymarket.com/",
137, // Polygon mainnet
signer,
builderConfig,
RelayerTxType.SAFE,
);
// Deploy the Safe wallet
const response = await client.deploy();
const result = await response.wait();
console.log("Safe Address:", result?.proxyAddress);
```
```python Python theme={null}
from py_builder_relayer_client.client import RelayClient
# client initialized with builder_config
# Deploy the Safe wallet
response = client.deploy()
result = response.wait()
print("Safe Address:", result.get("proxyAddress"))
```
</CodeGroup>
<Info>
See [Gasless Transactions](/trading/gasless) for full Relayer Client setup
including local and remote signing configurations.
</Info>
</Step>
<Step title="Approve Tokens">
Before trading, you must approve the exchange contracts to spend your tokens.
### Required Approvals
| Token | Spender | Purpose |
| -------------------- | --------------------- | -------------------------------- |
| USDC.e | CTF Contract | Split USDC.e into outcome tokens |
| CTF (outcome tokens) | CTF Exchange | Trade outcome tokens |
| CTF (outcome tokens) | Neg Risk CTF Exchange | Trade neg-risk market tokens |
### Contract Addresses
```typescript theme={null}
const ADDRESSES = {
USDCe: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
CTF: "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045",
CTF_EXCHANGE: "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E",
NEG_RISK_CTF_EXCHANGE: "0xC5d563A36AE78145C45a50134d48A1215220f80a",
NEG_RISK_ADAPTER: "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296",
};
```
### Approve via Relayer Client
<CodeGroup>
```typescript TypeScript theme={null}
import { ethers } from "ethers";
import { Interface } from "ethers/lib/utils";
const erc20Interface = new Interface([
"function approve(address spender, uint256 amount) returns (bool)",
]);
// Approve USDCe for CTF contract
const approveTx = {
to: ADDRESSES.USDCe,
data: erc20Interface.encodeFunctionData("approve", [
ADDRESSES.CTF,
ethers.constants.MaxUint256,
]),
value: "0",
};
const response = await client.execute([approveTx], "Approve USDCe for CTF");
await response.wait();
```
```python Python theme={null}
from web3 import Web3
USDC = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
MAX_UINT256 = 2**256 - 1
approve_tx = {
"to": USDC,
"data": Web3().eth.contract(
address=USDC,
abi=[{
"name": "approve",
"type": "function",
"inputs": [
{"name": "spender", "type": "address"},
{"name": "amount", "type": "uint256"}
],
"outputs": [{"type": "bool"}]
}]
).encode_abi(abi_element_identifier="approve", args=[CTF, MAX_UINT256]),
"value": "0"
}
response = client.execute([approve_tx], "Approve USDC for CTF")
response.wait()
```
</CodeGroup>
</Step>
<Step title="Generate API Credentials">
To place orders and access authenticated endpoints, you need L2 API credentials derived from your wallet.
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
const client = new ClobClient("https://clob.polymarket.com", 137, signer);
// Derive API credentials from your wallet
const credentials = await client.createOrDeriveApiKey();
console.log("API Key:", credentials.key);
console.log("Secret:", credentials.secret);
console.log("Passphrase:", credentials.passphrase);
```
```python Python theme={null}
from py_clob_client.client import ClobClient
import os
private_key = os.getenv("PRIVATE_KEY")
temp_client = ClobClient("https://clob.polymarket.com", key=private_key, chain_id=137)
credentials = temp_client.create_or_derive_api_creds()
```
```rust Rust theme={null}
use std::str::FromStr;
use polymarket_client_sdk::POLYGON;
use polymarket_client_sdk::auth::{LocalSigner, Signer};
use polymarket_client_sdk::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// The Rust SDK derives credentials and initializes in one step
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
```
</CodeGroup>
See [Authentication](/trading/overview#authentication) for full details on signature types and REST API headers.
</Step>
</Steps>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Trading" icon="chart-line" href="/market-makers/trading">
Post limit orders and manage quotes
</Card>
<Card title="Market Data" icon="database" href="/market-data/overview">
Connect to real-time market data
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,103 +0,0 @@
# Deposit
> Bridge assets from any supported chain to fund your Polymarket account
Polymarket uses **USDC.e** (Bridged USDC) on Polygon as collateral for all trading. The Bridge API lets you deposit assets from Ethereum, Solana, Bitcoin, and other chains—they're automatically converted to USDC.e on Polygon.
## How It Works
1. Request deposit addresses for your Polymarket wallet
2. Send assets to the appropriate address for your source chain
3. Assets are bridged and swapped to USDC.e automatically
4. USDC.e is credited to your wallet for trading
## Create Deposit Addresses
Generate unique deposit addresses linked to your Polymarket wallet. See the [Bridge API Reference](/api-reference/introduction) for full request and response schemas.
```bash theme={null}
curl -X POST https://bridge.polymarket.com/deposit \
-H "Content-Type: application/json" \
-d '{"address": "0x56687bf447db6ffa42ffe2204a05edaa20f55839"}'
```
### Address Types
| Address | Use For |
| ------- | -------------------------------------------------------- |
| `evm` | Ethereum, Arbitrum, Base, Optimism, and other EVM chains |
| `svm` | Solana |
| `btc` | Bitcoin |
| `tvm` | Tron |
<Warning>
Each address is unique to your wallet. Only send assets from supported chains
to the correct address type.
</Warning>
## Deposit Flow
<Steps>
<Step title="Get Your Deposit Address">
Call `POST /deposit` with your Polymarket wallet address to get deposit
addresses.
</Step>
<Step title="Check Supported Assets">
Verify your token is supported and meets the minimum deposit amount via
`/supported-assets`.
</Step>
<Step title="Send Assets">
Transfer tokens to the appropriate deposit address from your source chain.
</Step>
<Step title="Track Status">
Monitor your deposit progress using `/status/{address}`.
</Step>
</Steps>
## USDC vs USDC.e
You can deposit either USDC (native) or USDC.e (bridged) to your Polymarket wallet. If you deposit native USDC, you will be prompted to "activate funds," which swaps it to USDC.e via the lowest-fee Uniswap pool (less than 10bp slippage).
## Large Deposits
For deposits over \$50,000 originating from a chain other than Polygon, we recommend using a third-party bridge to minimize slippage:
* [DeBridge](https://app.debridge.finance/)
* [Across](https://app.across.to/bridge)
* [Portal](https://portalbridge.com/)
Bridge directly to your Polymarket USDC (Polygon) deposit address. Polymarket is not affiliated with or responsible for any third-party bridge.
## Minimum Deposits
Each asset has a minimum deposit amount. Deposits below the minimum will not be processed. Check `/supported-assets` for current minimums.
## Deposit Recovery
If you deposited the wrong token on Ethereum or Polygon, use these tools to recover your funds:
* **Ethereum deposits**: [recovery.polymarket.com](https://recovery.polymarket.com/)
* **Polygon deposits**: [matic-recovery.polymarket.com](https://matic-recovery.polymarket.com/)
<Warning>
Sending unsupported tokens may cause **irrecoverable loss**. Always verify
your token is listed in [Supported Assets](/trading/bridge/supported-assets)
before depositing.
</Warning>
## Next Steps
<CardGroup cols={2}>
<Card title="Supported Assets" icon="coins" href="/trading/bridge/supported-assets">
See all supported chains and tokens with minimum amounts.
</Card>
<Card title="Check Status" icon="clock" href="/trading/bridge/status">
Track your deposit progress through completion.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-143
View File
@@ -1,143 +0,0 @@
# Negative Risk Markets
> Capital-efficient trading for multi-outcome events
**Negative risk** is a mechanism for multi-outcome events where only one outcome can win. It enables capital-efficient trading by allowing positions across all outcomes within an event to be related through a **conversion** operation.
## How It Works
In a standard multi-outcome event, each market is independent. If you want to bet against one outcome, you must buy that outcome's No tokens—but those No tokens have no relationship to the other outcomes.
Negative risk changes this. In a neg risk event:
* A **No share** in any market can be converted into **1 Yes share in every other market**
* This conversion happens through the Neg Risk Adapter contract
### Example
Consider an event: "Who will win the 2024 Presidential Election?" with three outcomes:
| Outcome | Your Position |
| ------- | ------------- |
| Trump | — |
| Harris | — |
| Other | 1 No |
With negative risk, that 1 No on "Other" can be converted into:
| Outcome | After Conversion |
| ------- | ---------------- |
| Trump | 1 Yes |
| Harris | 1 Yes |
| Other | — |
This is capital-efficient because betting against one outcome is economically equivalent to betting *for* all other outcomes.
## Identifying Neg Risk Markets
The Gamma API includes a `negRisk` boolean on events and markets:
```json theme={null}
{
"id": "123",
"title": "Who will win the 2024 Presidential Election?",
"negRisk": true,
"markets": [...]
}
```
When placing orders on neg risk markets, you must specify this in your order options:
```typescript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 100,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for neg risk markets
},
);
```
## Contract Addresses
Neg risk markets use different contracts than standard markets:
See [Contract Addresses](/resources/contract-addresses) for the Neg Risk Adapter and Neg Risk CTF Exchange addresses.
## Augmented Negative Risk
Standard negative risk requires the complete set of outcomes to be known at market creation. But sometimes new outcomes emerge after trading begins (e.g., a new candidate enters a race).
**Augmented negative risk** solves this with:
| Outcome Type | Description |
| ------------------------ | ------------------------------------------------------------- |
| **Named outcomes** | Known outcomes (e.g., "Trump", "Harris") |
| **Placeholder outcomes** | Reserved slots that can be clarified later (e.g., "Person A") |
| **Explicit Other** | Catches any outcome not explicitly named |
### How Placeholders Work
1. Event launches with named outcomes + placeholders + "Other"
2. When a new outcome emerges, a placeholder is clarified via the bulletin board
3. The "Other" definition narrows as placeholders are assigned
### Trading Rules for Augmented Neg Risk
<Warning>
Only trade on **named outcomes**. Placeholder outcomes should be ignored until
they are named or until resolution occurs. The Polymarket UI does not display
unnamed outcomes.
</Warning>
* If the correct outcome at resolution is not named, the market resolves to "Other"
* The "Other" outcome's definition changes as placeholders are clarified—avoid trading it directly
### Identifying Augmented Neg Risk
An event is augmented neg risk when both flags are true:
```json theme={null}
{
"enableNegRisk": true,
"negRiskAugmented": true
}
```
<Note>
The Gamma API includes a boolean field `negRisk` on events and markets, which indicates whether the event uses negative risk. For augmented neg risk events, an additional `enableNegRisk` field is also `true`. When placing orders, the SDK option is always `negRisk: true` / `neg_risk: True` regardless of whether the market is standard or augmented neg risk.
</Note>
## Technical Details
### Conversion Mechanics
The conversion operation is atomic and happens through the Neg Risk Adapter:
1. You hold 1 No token for Outcome A
2. Call the convert function on the adapter
3. You receive 1 Yes token for every other outcome in the event
## Resources
* [Neg Risk Adapter Source Code](https://github.com/Polymarket/neg-risk-ctf-adapter)
* [Gamma API Documentation](/market-data/overview)
## Next Steps
<CardGroup cols={2}>
<Card title="Markets & Events" icon="calendar" href="/concepts/markets-events">
Understand how multi-market events are structured.
</Card>
<Card title="Positions & Tokens" icon="coins" href="/concepts/positions-tokens">
Learn about token operations like split, merge, and redeem.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-422
View File
@@ -1,422 +0,0 @@
# Authentication
> How to authenticate requests to the CLOB API
The CLOB API uses two levels of authentication: **L1 (Private Key)** and **L2 (API Key)**. Either can be accomplished using the CLOB client or REST API.
## Public vs Authenticated
<CardGroup cols={1}>
<Card title="Public (No Auth)" icon="unlock">
The **Gamma API**, **Data API**, and CLOB read endpoints (orderbook, prices, spreads) require no authentication.
</Card>
<Card title="Authenticated (CLOB)" icon="lock">
CLOB trading endpoints (placing orders, cancellations, heartbeat) require all 5 `POLY_*` L2 HTTP headers.
</Card>
</CardGroup>
***
## Two-Level Authentication Model
The CLOB uses two levels of authentication: L1 (Private Key) and L2 (API Key). Either can be accomplished using the CLOB client or REST API
### L1 Authentication
L1 authentication uses the wallet's private key to sign an EIP-712 message used in the request header. It proves ownership and control over the private key. The private key stays in control of the user and all trading activity remains non-custodial.
**Used for:**
* Creating API credentials
* Deriving existing API credentials
* Signing and creating user's orders locally
### L2 Authentication
L2 uses API credentials (apiKey, secret, passphrase) generated from L1 authentication. These are used solely to authenticate requests made to the CLOB API. Requests are signed using HMAC-SHA256.
**Used for:**
* Cancel or get user's open orders
* Check user's balances and allowances
* Post user's signed orders
<Info>
Even with L2 authentication headers, methods that create user orders still
require the user to sign the order payload.
</Info>
***
## Getting API Credentials
Before making authenticated requests, you need to obtain API credentials using L1 authentication.
### Using the SDK
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const client = new ClobClient(
"https://clob.polymarket.com",
137, // Polygon mainnet
new Wallet(process.env.PRIVATE_KEY)
);
// Creates new credentials or derives existing ones
const credentials = await client.createOrDeriveApiKey();
console.log(credentials);
// {
// apiKey: "550e8400-e29b-41d4-a716-446655440000",
// secret: "base64EncodedSecretString",
// passphrase: "randomPassphraseString"
// }
```
</Tab>
<Tab title="Python">
```python theme={null}
from py_clob_client.client import ClobClient
import os
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137, # Polygon mainnet
key=os.getenv("PRIVATE_KEY")
)
# Creates new credentials or derives existing ones
credentials = client.create_or_derive_api_creds()
print(credentials)
# {
# "apiKey": "550e8400-e29b-41d4-a716-446655440000",
# "secret": "base64EncodedSecretString",
# "passphrase": "randomPassphraseString"
# }
```
</Tab>
<Tab title="Rust">
```rust theme={null}
use std::str::FromStr;
use polymarket_client_sdk::POLYGON;
use polymarket_client_sdk::auth::{LocalSigner, Signer};
use polymarket_client_sdk::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// Creates new credentials or derives existing ones,
// then initializes the authenticated client — all in one step
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
let credentials = client.credentials();
println!("API Key: {}", credentials.key());
```
</Tab>
</Tabs>
<Warning>
**Never commit private keys to version control.** Always use environment
variables or secure key management systems.
</Warning>
### Using the REST API
While we highly recommend using our provided clients to handle signing and authentication, the following is for developers who choose NOT to use our [Python](https://github.com/Polymarket/py-clob-client) or [TypeScript](https://github.com/Polymarket/clob-client) clients.
**Create API Credentials**
```bash theme={null}
POST https://clob.polymarket.com/auth/api-key
```
**Derive API Credentials**
```bash theme={null}
GET https://clob.polymarket.com/auth/derive-api-key
```
Required L1 headers:
| Header | Description |
| ---------------- | ---------------------- |
| `POLY_ADDRESS` | Polygon signer address |
| `POLY_SIGNATURE` | CLOB EIP-712 signature |
| `POLY_TIMESTAMP` | Current UNIX timestamp |
| `POLY_NONCE` | Nonce (default: 0) |
The `POLY_SIGNATURE` is generated by signing the following EIP-712 struct:
<Accordion title="EIP-712 Signing Example">
<CodeGroup>
```typescript TypeScript theme={null}
const domain = {
name: "ClobAuthDomain",
version: "1",
chainId: chainId, // Polygon Chain ID 137
};
const types = {
ClobAuth: [
{ name: "address", type: "address" },
{ name: "timestamp", type: "string" },
{ name: "nonce", type: "uint256" },
{ name: "message", type: "string" },
],
};
const value = {
address: signingAddress, // The Signing address
timestamp: ts, // The CLOB API server timestamp
nonce: nonce, // The nonce used
message: "This message attests that I control the given wallet",
};
const sig = await signer._signTypedData(domain, types, value);
```
```python Python theme={null}
domain = {
"name": "ClobAuthDomain",
"version": "1",
"chainId": chainId, # Polygon Chain ID 137
}
types = {
"ClobAuth": [
{"name": "address", "type": "address"},
{"name": "timestamp", "type": "string"},
{"name": "nonce", "type": "uint256"},
{"name": "message", "type": "string"},
]
}
value = {
"address": signingAddress, # The signing address
"timestamp": ts, # The CLOB API server timestamp
"nonce": nonce, # The nonce used
"message": "This message attests that I control the given wallet",
}
sig = signer.sign_typed_data(domain, types, value)
```
</CodeGroup>
</Accordion>
Reference implementations:
* [TypeScript](https://github.com/Polymarket/clob-client/blob/main/src/signing/eip712.ts)
* [Python](https://github.com/Polymarket/py-clob-client/blob/main/py_clob_client/signing/eip712.py)
Response:
```json theme={null}
{
"apiKey": "550e8400-e29b-41d4-a716-446655440000",
"secret": "base64EncodedSecretString",
"passphrase": "randomPassphraseString"
}
```
**You'll need all three values for L2 authentication.**
***
## L2 Authentication Headers
All trading endpoints require these 5 headers:
| Header | Description |
| ----------------- | ----------------------------- |
| `POLY_ADDRESS` | Polygon signer address |
| `POLY_SIGNATURE` | HMAC signature for request |
| `POLY_TIMESTAMP` | Current UNIX timestamp |
| `POLY_API_KEY` | User's API `apiKey` value |
| `POLY_PASSPHRASE` | User's API `passphrase` value |
The `POLY_SIGNATURE` for L2 is an HMAC-SHA256 signature created using the user's API credentials `secret` value. Reference implementations can be found in the [TypeScript](https://github.com/Polymarket/clob-client/blob/main/src/signing/hmac.ts) and [Python](https://github.com/Polymarket/py-clob-client/blob/main/py_clob_client/signing/hmac.py) clients.
### CLOB Client
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
const client = new ClobClient(
"https://clob.polymarket.com",
137,
new Wallet(process.env.PRIVATE_KEY),
apiCreds, // Generated from L1 auth, API credentials enable L2 methods
1, // signatureType explained below
funderAddress // funder explained below
);
// Now you can trade!
const order = await client.createAndPostOrder(
{ tokenID: "123456", price: 0.65, size: 100, side: "BUY" },
{ tickSize: "0.01", negRisk: false }
);
```
</Tab>
<Tab title="Python">
```python theme={null}
from py_clob_client.client import ClobClient
import os
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=api_creds, # Generated from L1 auth, API credentials enable L2 methods
signature_type=1, # signatureType explained below
funder=os.getenv("FUNDER_ADDRESS") # funder explained below
)
# Now you can trade!
order = client.create_and_post_order(
{"token_id": "123456", "price": 0.65, "size": 100, "side": "BUY"},
{"tick_size": "0.01", "neg_risk": False}
)
```
</Tab>
<Tab title="Rust">
```rust theme={null}
use polymarket_client_sdk::clob::types::{Side, SignatureType};
use polymarket_client_sdk::types::dec;
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::Proxy) // signatureType explained below
// Funder auto-derived via CREATE2 for Proxy/GnosisSafe
.authenticate()
.await?;
// Now you can trade!
let order = client.limit_order()
.token_id("123456".parse()?)
.price(dec!(0.65))
.size(dec!(100))
.side(Side::Buy)
.build().await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;
```
</Tab>
</Tabs>
<Info>
Even with L2 authentication headers, methods that create user orders still
require the user to sign the order payload.
</Info>
***
## Signature Types and Funder
When initializing the L2 client, you must specify your wallet **signatureType** and the **funder** address which holds the funds:
| Signature Type | Value | Description |
| -------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| EOA | `0` | Standard Ethereum wallet (MetaMask). Funder is the EOA address and will need POL to pay gas on transactions. |
| POLY\_PROXY | `1` | A custom proxy wallet only used with users who logged in via Magic Link email/Google. Using this requires the user to have exported their PK from Polymarket.com and imported into your app. |
| GNOSIS\_SAFE | `2` | Gnosis Safe multisig proxy wallet (most common). Use this for any new or returning user who does not fit the other 2 types. |
<Tip>
The wallet address displayed to the user on Polymarket.com is the proxy wallet
and should be used as the funder. These can be deterministically derived or
you can deploy them on behalf of the user. These proxy wallets are
automatically deployed for the user on their first login to Polymarket.com.
</Tip>
***
## Security Best Practices
<AccordionGroup>
<Accordion title="Never expose private keys">
Store private keys in environment variables or secure key management systems. Never commit them to version control.
```bash theme={null}
# .env (never commit this file)
PRIVATE_KEY=0x...
```
</Accordion>
<Accordion title="Implement request signing on the server">
Never expose your API secret in client-side code. All authenticated requests should originate from your backend.
</Accordion>
</AccordionGroup>
***
## Troubleshooting
<AccordionGroup>
<Accordion title="Error - INVALID_SIGNATURE">
Your wallet's private key is incorrect or improperly formatted.
**Solutions:**
* Verify your private key is a valid hex string (starts with "0x")
* Ensure you're using the correct key for the intended address
* Check that the key has proper permissions
</Accordion>
<Accordion title="Error - NONCE_ALREADY_USED">
The nonce you provided has already been used to create an API key.
**Solutions:**
* Use `deriveApiKey()` with the same nonce to retrieve existing credentials
* Or use a different nonce with `createApiKey()`
</Accordion>
<Accordion title="Error - Invalid Funder Address">
Your funder address is incorrect or doesn't match your wallet.
**Solution:** Check your Polymarket profile address at [polymarket.com/settings](https://polymarket.com/settings).
If it does not exist or user has never logged into Polymarket.com, deploy it first before creating L2 authentication.
</Accordion>
<Accordion title="Lost both credentials and nonce">
Unfortunately, there's no way to recover lost API credentials without the nonce. You'll need to create new credentials:
```typescript theme={null}
// Create fresh credentials with a new nonce
const newCreds = await client.createApiKey();
// Save the nonce this time!
```
</Accordion>
</AccordionGroup>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Place Your First Order" icon="plus" href="/trading/quickstart">
Learn how to create and submit orders.
</Card>
<Card title="Geographic Restrictions" icon="globe" href="/api-reference/geoblock">
Check trading availability by region.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
-149
View File
@@ -1,149 +0,0 @@
# Resolution
> How markets are resolved and winning positions redeemed
When the outcome of an event becomes known, the market is **resolved**. Resolution determines which outcome won, allowing holders of winning tokens to redeem them for \$1 each. Losing tokens become worthless.
Polymarket uses the **UMA Optimistic Oracle** for decentralized, permissionless resolution. Anyone can propose an outcome, and anyone can dispute it if they believe it's incorrect.
<Frame>
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/resolution-lifecycle.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=6726569af3efd6f4fda54528c8eb0d0a" alt="" className="dark:hidden" width="1722" height="952" data-path="images/core-concepts/resolution-lifecycle.png" />
<img src="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/resolution-lifecycle.png?fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=36e91c655f7f50b18dea3a23b44f8c23" alt="" className="hidden dark:block" width="1722" height="952" data-path="images/dark/core-concepts/resolution-lifecycle.png" />
</Frame>
## Resolution Rules
Every market has pre-defined resolution rules that specify:
* **Resolution source** — Where the outcome will be determined from (e.g., official announcements, specific websites)
* **End date** — When the market is eligible for resolution
* **Edge cases** — How ambiguous situations should be handled
<Warning>
Always read the resolution rules before trading. The market title describes
the question, but the **rules** define how it resolves.
</Warning>
<Steps>
<Step title="Proposal">
Anyone can propose a resolution by:
1. Selecting the winning outcome
2. Posting a bond (typically \$750 USDC.e)
3. Submitting the proposal to the UMA Oracle
If the proposal is correct and undisputed, the proposer receives their bond back plus a reward.
<Warning>
If you propose incorrectly or too early, you lose your entire bond. Only
propose if you're confident in the outcome and understand the process.
</Warning>
</Step>
<Step title="Challenge Period">
After a proposal, there's a **2-hour challenge period** where anyone can dispute the outcome.
* **If no dispute**: The proposal is accepted and the market resolves
* **If disputed**: A new proposal round begins. If the second proposal is also disputed, the resolution escalates to UMA's DVM (Data Verification Mechanism) for a token holder vote.
There are three possible resolution flows:
1. **No dispute** — Propose then Resolve (fastest, \~2 hours)
2. **One dispute** — Propose, Challenge, second Propose, Resolve (second proposal accepted)
3. **Two disputes** — Propose, Challenge, second Propose, second Challenge, Resolve via DVM vote
</Step>
<Step title="Dispute - If Challenged">
To dispute a proposal:
1. Post a counter-bond (same amount as proposer, typically \$750)
2. The dispute triggers a new proposal round, or if already in the second round, a debate period
During the **24-48 hour debate period**, evidence can be submitted in UMA's Discord channels (`#evidence-rationale` and `#voting-discussion`).
</Step>
<Step title="UMA Vote">
After the debate period, UMA token holders vote on the correct outcome. The voting process takes approximately 48 hours.
| Outcome | Result | Bond Distribution |
| ----------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| **Proposer wins** | Original proposal accepted | Proposer gets bond back + half of disputer's bond |
| **Disputer wins** | Proposal rejected, new proposal needed | Disputer gets bond back + half of proposer's bond |
| **Too Early** | Event hasn't concluded yet | Disputer gets bond back + half of proposer's bond |
| **Unknown/50-50** | Neither outcome applicable (rare) | Market resolves 50/50 — each token redeems for \$0.50; disputer gets bond back + half of proposer's bond |
</Step>
</Steps>
## After Resolution
Once a market resolves:
* **Trading stops** — You can no longer buy or sell tokens for this market
* **Winning tokens** become redeemable for \$1.00 each
* **Losing tokens** become worthless (\$0.00)
### Redeeming Tokens
After resolution, call the `redeemPositions` function on the CTF contract to exchange winning tokens for USDC.e. The contract burns your tokens and returns the corresponding collateral.
```
100 winning tokens → $100 USDC.e
```
## Clarifications
In rare cases, unforeseen circumstances require clarification of the rules after trading begins. Polymarket may issue an **"Additional context"** update that proposers and voters should consider during resolution.
Clarifications:
* Cannot change the fundamental intent of the question
* Are published onchain via the bulletin board contract
* Should be considered by UMA voters when resolving disputes
<Tip>
If you believe a clarification is needed, request it in the [Polymarket
Discord](https://discord.com/invite/polymarket) `#market-review` channel.
</Tip>
## Resolution Timeline
| Phase | Duration |
| --------------------------- | ----------- |
| Challenge period | 2 hours |
| Debate period (if disputed) | 24-48 hours |
| UMA voting (if disputed) | \~48 hours |
**Undisputed resolution**: \~2 hours after proposal
**Disputed resolution**: 4-6 days total
## Contract Addresses
| Contract | Address | Network |
| ---------------------- | -------------------------------------------- | --------------- |
| **UmaCtfAdapter v3.0** | `0x157Ce2d672854c848c9b79C49a8Cc6cc89176a49` | Polygon Mainnet |
| **UmaCtfAdapter v2.0** | `0x6A9D222616C90FcA5754cd1333cFD9b7fb6a4F74` | Polygon Mainnet |
| **UmaCtfAdapter v1.0** | `0xCB1822859cEF82Cd2Eb4E6276C7916e692995130` | Polygon Mainnet |
## Resources
* [UMA Oracle Portal](https://oracle.uma.xyz/) — View and interact with proposals
* [UMA Documentation](https://docs.uma.xyz/) — Learn more about the Optimistic Oracle
* [Polymarket Discord](https://discord.com/invite/polymarket) — Discuss resolutions and request clarifications
* [UmaCtfAdapter Source Code](https://github.com/Polymarket/uma-ctf-adapter) — Smart contract source
* [UmaCtfAdapter Audit](https://github.com/Polymarket/uma-ctf-adapter/blob/main/audit/Polymarket_UMA_Optimistic_Oracle_Adapter_Audit.pdf) — Security audit report
## Next Steps
<CardGroup cols={2}>
<Card title="Positions & Tokens" icon="coins" href="/concepts/positions-tokens">
Learn how to redeem winning tokens after resolution.
</Card>
<Card title="Markets & Events" icon="calendar" href="/concepts/markets-events">
Understand how markets are structured.
</Card>
</CardGroup>
Built with [Mintlify](https://mintlify.com).
@@ -1,213 +0,0 @@
# Sports WebSocket
> Live sports scores and game state
The Sports WebSocket provides real-time sports results updates, including scores, periods, and game status. No authentication required.
## Endpoint
```
wss://sports-api.polymarket.com/ws
```
No subscription message required — connect and start receiving data for all active sports events.
## Heartbeat
The server sends `ping` every 5 seconds. Respond with `pong` within 10 seconds or the connection will close.
```javascript theme={null}
ws.onmessage = (event) => {
if (event.data === "ping") {
ws.send("pong");
return;
}
// Handle JSON messages...
};
```
## Message Type
Each message is a JSON object with game state fields.
### sport\_result
Emitted when:
* A match goes live
* The score changes
* The period changes (e.g., halftime, overtime)
* A match ends
* Possession changes (NFL and CFB only)
**NFL (in progress):**
```json theme={null}
{
"gameId": 19439,
"leagueAbbreviation": "nfl",
"slug": "nfl-lac-buf-2025-01-26",
"homeTeam": "LAC",
"awayTeam": "BUF",
"status": "InProgress",
"score": "3-16",
"period": "Q4",
"elapsed": "5:18",
"live": true,
"ended": false,
"turn": "lac"
}
```
**Esports — CS2 (finished):**
```json theme={null}
{
"gameId": 1317359,
"leagueAbbreviation": "cs2",
"slug": "cs2-arcred-the-glecs-2025-07-20",
"homeTeam": "ARCRED",
"awayTeam": "The glecs",
"status": "finished",
"score": "000-000|2-0|Bo3",
"period": "2/3",
"live": false,
"ended": true,
"finished_timestamp": "2025-07-20T18:30:00.000Z"
}
```
The `finished_timestamp` field is an ISO 8601 timestamp only present when `ended: true`.
The `slug` field follows the format `{league}-{team1}-{team2}-{date}` (e.g., `nfl-buf-kc-2025-01-26`).
## Period Values
| Period | Description |
| ---------------------- | --------------------------------------- |
| `1H` | First half |
| `2H` | Second half |
| `1Q`, `2Q`, `3Q`, `4Q` | Quarters (NFL, NBA) |
| `HT` | Halftime |
| `FT` | Full time (match ended in regulation) |
| `FT OT` | Full time with overtime |
| `FT NR` | Full time, no result (draw or canceled) |
| `End 1`, `End 2`, ... | End of inning (MLB) |
| `1/3`, `2/3`, `3/3` | Map number in Bo3 series (Esports) |
| `1/5`, `2/5`, ... | Map number in Bo5 series (Esports) |
## Game Status Values
Game status values vary by sport:
### NFL
| Status | Description |
| -------------- | ---------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed in regulation |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### NHL
| Status | Description |
| -------------- | ---------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed in regulation |
| `F/OT` | Final after overtime |
| `F/SO` | Final after shootout |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### MLB
| Status | Description |
| -------------- | ------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `Suspended` | Game suspended |
| `Delayed` | Game delayed |
| `Postponed` | Game postponed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### NBA and CBB
| Status | Description |
| -------------- | ------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### CFB
| Status | Description |
| ------------ | ---------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
### Soccer
| Status | Description |
| ----------------- | ------------------------------------ |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Break` | Halftime or other break |
| `Suspended` | Game suspended |
| `PenaltyShootout` | Penalty shootout in progress |
| `Final` | Game completed |
| `Awarded` | Result awarded due to ruling/forfeit |
| `Postponed` | Game postponed |
| `Canceled` | Game canceled |
### Esports
| Status | Description |
| ------------- | ----------------------- |
| `not_started` | Match not yet started |
| `running` | Match currently playing |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `canceled` | Match canceled |
### Tennis
| Status | Description |
| ------------ | ----------------------- |
| `scheduled` | Match not yet started |
| `inprogress` | Match currently playing |
| `suspended` | Match suspended |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `cancelled` | Match canceled |
Built with [Mintlify](https://mintlify.com).
@@ -1,213 +0,0 @@
# Sports WebSocket
> Live sports scores and game state
The Sports WebSocket provides real-time sports results updates, including scores, periods, and game status. No authentication required.
## Endpoint
```
wss://sports-api.polymarket.com/ws
```
No subscription message required — connect and start receiving data for all active sports events.
## Heartbeat
The server sends `ping` every 5 seconds. Respond with `pong` within 10 seconds or the connection will close.
```javascript theme={null}
ws.onmessage = (event) => {
if (event.data === "ping") {
ws.send("pong");
return;
}
// Handle JSON messages...
};
```
## Message Type
Each message is a JSON object with game state fields.
### sport\_result
Emitted when:
* A match goes live
* The score changes
* The period changes (e.g., halftime, overtime)
* A match ends
* Possession changes (NFL and CFB only)
**NFL (in progress):**
```json theme={null}
{
"gameId": 19439,
"leagueAbbreviation": "nfl",
"slug": "nfl-lac-buf-2025-01-26",
"homeTeam": "LAC",
"awayTeam": "BUF",
"status": "InProgress",
"score": "3-16",
"period": "Q4",
"elapsed": "5:18",
"live": true,
"ended": false,
"turn": "lac"
}
```
**Esports — CS2 (finished):**
```json theme={null}
{
"gameId": 1317359,
"leagueAbbreviation": "cs2",
"slug": "cs2-arcred-the-glecs-2025-07-20",
"homeTeam": "ARCRED",
"awayTeam": "The glecs",
"status": "finished",
"score": "000-000|2-0|Bo3",
"period": "2/3",
"live": false,
"ended": true,
"finished_timestamp": "2025-07-20T18:30:00.000Z"
}
```
The `finished_timestamp` field is an ISO 8601 timestamp only present when `ended: true`.
The `slug` field follows the format `{league}-{team1}-{team2}-{date}` (e.g., `nfl-buf-kc-2025-01-26`).
## Period Values
| Period | Description |
| ---------------------- | --------------------------------------- |
| `1H` | First half |
| `2H` | Second half |
| `1Q`, `2Q`, `3Q`, `4Q` | Quarters (NFL, NBA) |
| `HT` | Halftime |
| `FT` | Full time (match ended in regulation) |
| `FT OT` | Full time with overtime |
| `FT NR` | Full time, no result (draw or canceled) |
| `End 1`, `End 2`, ... | End of inning (MLB) |
| `1/3`, `2/3`, `3/3` | Map number in Bo3 series (Esports) |
| `1/5`, `2/5`, ... | Map number in Bo5 series (Esports) |
## Game Status Values
Game status values vary by sport:
### NFL
| Status | Description |
| -------------- | ---------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed in regulation |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### NHL
| Status | Description |
| -------------- | ---------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed in regulation |
| `F/OT` | Final after overtime |
| `F/SO` | Final after shootout |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### MLB
| Status | Description |
| -------------- | ------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `Suspended` | Game suspended |
| `Delayed` | Game delayed |
| `Postponed` | Game postponed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### NBA and CBB
| Status | Description |
| -------------- | ------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### CFB
| Status | Description |
| ------------ | ---------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
### Soccer
| Status | Description |
| ----------------- | ------------------------------------ |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Break` | Halftime or other break |
| `Suspended` | Game suspended |
| `PenaltyShootout` | Penalty shootout in progress |
| `Final` | Game completed |
| `Awarded` | Result awarded due to ruling/forfeit |
| `Postponed` | Game postponed |
| `Canceled` | Game canceled |
### Esports
| Status | Description |
| ------------- | ----------------------- |
| `not_started` | Match not yet started |
| `running` | Match currently playing |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `canceled` | Match canceled |
### Tennis
| Status | Description |
| ------------ | ----------------------- |
| `scheduled` | Match not yet started |
| `inprogress` | Match currently playing |
| `suspended` | Match suspended |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `cancelled` | Match canceled |
Built with [Mintlify](https://mintlify.com).
@@ -1,213 +0,0 @@
# Sports WebSocket
> Live sports scores and game state
The Sports WebSocket provides real-time sports results updates, including scores, periods, and game status. No authentication required.
## Endpoint
```
wss://sports-api.polymarket.com/ws
```
No subscription message required — connect and start receiving data for all active sports events.
## Heartbeat
The server sends `ping` every 5 seconds. Respond with `pong` within 10 seconds or the connection will close.
```javascript theme={null}
ws.onmessage = (event) => {
if (event.data === "ping") {
ws.send("pong");
return;
}
// Handle JSON messages...
};
```
## Message Type
Each message is a JSON object with game state fields.
### sport\_result
Emitted when:
* A match goes live
* The score changes
* The period changes (e.g., halftime, overtime)
* A match ends
* Possession changes (NFL and CFB only)
**NFL (in progress):**
```json theme={null}
{
"gameId": 19439,
"leagueAbbreviation": "nfl",
"slug": "nfl-lac-buf-2025-01-26",
"homeTeam": "LAC",
"awayTeam": "BUF",
"status": "InProgress",
"score": "3-16",
"period": "Q4",
"elapsed": "5:18",
"live": true,
"ended": false,
"turn": "lac"
}
```
**Esports — CS2 (finished):**
```json theme={null}
{
"gameId": 1317359,
"leagueAbbreviation": "cs2",
"slug": "cs2-arcred-the-glecs-2025-07-20",
"homeTeam": "ARCRED",
"awayTeam": "The glecs",
"status": "finished",
"score": "000-000|2-0|Bo3",
"period": "2/3",
"live": false,
"ended": true,
"finished_timestamp": "2025-07-20T18:30:00.000Z"
}
```
The `finished_timestamp` field is an ISO 8601 timestamp only present when `ended: true`.
The `slug` field follows the format `{league}-{team1}-{team2}-{date}` (e.g., `nfl-buf-kc-2025-01-26`).
## Period Values
| Period | Description |
| ---------------------- | --------------------------------------- |
| `1H` | First half |
| `2H` | Second half |
| `1Q`, `2Q`, `3Q`, `4Q` | Quarters (NFL, NBA) |
| `HT` | Halftime |
| `FT` | Full time (match ended in regulation) |
| `FT OT` | Full time with overtime |
| `FT NR` | Full time, no result (draw or canceled) |
| `End 1`, `End 2`, ... | End of inning (MLB) |
| `1/3`, `2/3`, `3/3` | Map number in Bo3 series (Esports) |
| `1/5`, `2/5`, ... | Map number in Bo5 series (Esports) |
## Game Status Values
Game status values vary by sport:
### NFL
| Status | Description |
| -------------- | ---------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed in regulation |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### NHL
| Status | Description |
| -------------- | ---------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed in regulation |
| `F/OT` | Final after overtime |
| `F/SO` | Final after shootout |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### MLB
| Status | Description |
| -------------- | ------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `Suspended` | Game suspended |
| `Delayed` | Game delayed |
| `Postponed` | Game postponed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### NBA and CBB
| Status | Description |
| -------------- | ------------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
| `NotNecessary` | Scheduled, but not needed |
### CFB
| Status | Description |
| ------------ | ---------------------- |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Final` | Game completed |
| `F/OT` | Final after overtime |
| `Suspended` | Game suspended |
| `Postponed` | Game postponed |
| `Delayed` | Game delayed |
| `Canceled` | Game canceled |
| `Forfeit` | Game forfeited |
### Soccer
| Status | Description |
| ----------------- | ------------------------------------ |
| `Scheduled` | Game not yet started |
| `InProgress` | Game currently playing |
| `Break` | Halftime or other break |
| `Suspended` | Game suspended |
| `PenaltyShootout` | Penalty shootout in progress |
| `Final` | Game completed |
| `Awarded` | Result awarded due to ruling/forfeit |
| `Postponed` | Game postponed |
| `Canceled` | Game canceled |
### Esports
| Status | Description |
| ------------- | ----------------------- |
| `not_started` | Match not yet started |
| `running` | Match currently playing |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `canceled` | Match canceled |
### Tennis
| Status | Description |
| ------------ | ----------------------- |
| `scheduled` | Match not yet started |
| `inprogress` | Match currently playing |
| `suspended` | Match suspended |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `cancelled` | Match canceled |
Built with [Mintlify](https://mintlify.com).
+1 -1
View File
@@ -1 +1 @@
null
null