Update Polymarket documentation (2026-02-19)

- Added new documentation URLs from llms.txt index
- Updated TARGET.md with 244 total documentation pages
- Scraped new pages for trading, concepts, and API reference sections
- Updated changelog and new index pages
This commit is contained in:
AI Agent
2026-02-19 14:31:02 +01:00
parent 81f77eff3c
commit b2a29fe51f
250 changed files with 33306 additions and 9659 deletions
+133 -164
View File
@@ -4,43 +4,60 @@
# Authentication
> Understanding authentication using Polymarket's CLOB
> How to authenticate requests to the CLOB API
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. Authentication is not
required to access client public methods and public endpoints.
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.
## Authentication Levels
## Public vs Authenticated
<CardGroup cols={2}>
<Card title="L1 Authentication" icon="key" href="#l1-authentication">
Use the private key of the users account to sign messages
<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="L2 Authentication" icon="lock" href="#l2-authentication">
Use API credentials (key, secret, passphrase) to authenticate requests to the CLOB
<Card title="Authenticated (CLOB)" icon="lock">
CLOB trading endpoints (placing orders, cancellations, heartbeat) require all 5 `POLY_*` L2 HTTP headers.
</Card>
</CardGroup>
***
## L1 Authentication
## Two-Level Authentication Model
### What is L1?
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 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.
### L1 Authentication (Private Key)
### What This Enables
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.
Access to L1 methods that create or derive L2 authentication headers.
**Used for:**
* Create user API credentials
* Derive existing user API credentials
* Sign/create user's orders locally
* Creating API credentials
* Deriving existing API credentials
* Signing and creating user's orders locally
### CLOB Client
### L2 Authentication (API Credentials)
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 (Recommended)
<Tabs>
<Tab title="TypeScript">
@@ -48,26 +65,21 @@ Access to L1 methods that create or derive L2 authentication headers.
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);
const client = new ClobClient(
HOST,
CHAIN_ID,
signer // Signer enables L1 methods
"https://clob.polymarket.com",
137, // Polygon mainnet
new Wallet(process.env.PRIVATE_KEY)
);
// Gets API key, or else creates
const apiCreds = await client.createOrDeriveApiKey();
// Creates new credentials or derives existing ones
const credentials = await client.createOrDeriveApiKey();
/*
apiCreds = {
"apiKey": "550e8400-e29b-41d4-a716-446655440000",
"secret": "base64EncodedSecretString",
"passphrase": "randomPassphraseString"
}
*/
console.log(credentials);
// {
// apiKey: "550e8400-e29b-41d4-a716-446655440000",
// secret: "base64EncodedSecretString",
// passphrase: "randomPassphraseString"
// }
```
</Tab>
@@ -76,20 +88,17 @@ Access to L1 methods that create or derive L2 authentication headers.
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")
client = ClobClient(
host=host,
chain_id=chaind_id,
key=private_key # Signer enables L1 methods
host="https://clob.polymarket.com",
chain_id=137, # Polygon mainnet
key=os.getenv("PRIVATE_KEY")
)
# Gets API key, or else creates
api_creds = await client.create_or_derive_api_key()
# Creates new credentials or derives existing ones
credentials = client.create_or_derive_api_creds()
# api_creds = {
print(credentials)
# {
# "apiKey": "550e8400-e29b-41d4-a716-446655440000",
# "secret": "base64EncodedSecretString",
# "passphrase": "randomPassphraseString"
@@ -103,29 +112,36 @@ Access to L1 methods that create or derive L2 authentication headers.
variables or secure key management systems.
</Warning>
***
### Using the REST API
### 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.
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**
When making direct REST API calls with L1 authentication, include these headers:
```bash theme={null}
POST https://clob.polymarket.com/auth/api-key
```
| Header | Required? | Description |
| ---------------- | --------- | ---------------------- |
| `POLY_ADDRESS` | yes | Polygon signer address |
| `POLY_SIGNATURE` | yes | CLOB EIP 712 signature |
| `POLY_TIMESTAMP` | yes | Current UNIX timestamp |
| `POLY_NONCE` | yes | Nonce. Default 0 |
**Derive API Credentials**
The `POLY_SIGNATURE` is generated by signing the following EIP-712 struct.
```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}
```typescript TypeScript theme={null}
const domain = {
name: "ClobAuthDomain",
version: "1",
@@ -174,7 +190,7 @@ The `POLY_SIGNATURE` is generated by signing the following EIP-712 struct.
"message": "This message attests that I control the given wallet",
}
sig = await signer._signTypedData(domain, types, value)
sig = signer.sign_typed_data(domain, types, value)
```
</CodeGroup>
</Accordion>
@@ -184,25 +200,7 @@ 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)
***
**Create API Credentials**
Create new API credentials for user.
```bash theme={null}
POST {clob-endpoint}/auth/api-key
```
**Derive API Credentials**
Derive API credentials for user.
```bash theme={null}
GET {clob-endpoint}/auth/derive-api-key
```
**Response**
Response:
```json theme={null}
{
@@ -216,25 +214,21 @@ GET {clob-endpoint}/auth/derive-api-key
***
## L2 Authentication
## L2 Authentication Headers
### What is L2?
All trading endpoints require these 5 headers:
The next level of authentication is called L2, and it consists of the
user's 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.
| 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 |
### What This Enables
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.
Access to L2 methods such as posting signed/created orders, viewing open
orders, cancelling open orders, getting trades
* Cancel or get user's open orders
* Check user's balances and allowances
* Post user's signed orders
### CLOB Client
### CLOB Client (L2)
<Tabs>
<Tab title="TypeScript">
@@ -242,20 +236,16 @@ orders, cancelling open orders, getting trades
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);
const client = new ClobClient(
HOST,
CHAIN_ID,
signer,
"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
FUNDER // funder explained below
funderAddress // funder explained below
);
// Now you can trade!*
// Now you can trade!
const order = await client.createAndPostOrder(
{ tokenID: "123456", price: 0.65, size: 100, side: "BUY" },
{ tickSize: "0.01", negRisk: false }
@@ -268,10 +258,6 @@ orders, cancelling open orders, getting trades
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")
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
@@ -281,8 +267,8 @@ orders, cancelling open orders, getting trades
funder=os.getenv("FUNDER_ADDRESS") # funder explained below
)
# Now you can trade!*
order = await client.create_and_post_order(
# 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}
)
@@ -291,59 +277,57 @@ orders, cancelling open orders, getting trades
</Tabs>
<Info>
Even with L2 authentication headers, methods that create user orders still require the user to sign the order payload.
Even with L2 authentication headers, methods that create user orders still
require the user to sign the order payload.
</Info>
***
### 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.
When making direct REST API calls with L2 authentication, include these headers:
| Header | Required? | Description |
| ----------------- | --------- | ----------------------------- |
| `POLY_ADDRESS` | yes | Polygon signer address |
| `POLY_SIGNATURE` | yes | HMAC signature for request |
| `POLY_TIMESTAMP` | yes | Current UNIX timestamp |
| `POLY_API_KEY` | yes | User's API `apiKey` value |
| `POLY_PASSPHRASE` | yes | 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.
***
## 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. |
| 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 addresses 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.
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.
**Solution:**
**Solutions:**
* Verify your private key is a valid hex string (starts with "0x")
* Ensure you're using the correct key for the intended address
@@ -353,7 +337,7 @@ When initializing the L2 client, you must specify your wallet **signatureType**
<Accordion title="Error: NONCE_ALREADY_USED">
The nonce you provided has already been used to create an API key.
**Solution:**
**Solutions:**
* Use `deriveApiKey()` with the same nonce to retrieve existing credentials
* Or use a different nonce with `createApiKey()`
@@ -367,13 +351,6 @@ When initializing the L2 client, you must specify your wallet **signatureType**
If it does not exist or user has never logged into Polymarket.com, deploy it first before creating L2 authentication.
</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">
Unfortunately, there's no way to recover lost API credentials without the nonce. You'll need to create new credentials:
@@ -387,22 +364,14 @@ When initializing the L2 client, you must specify your wallet **signatureType**
***
## See Client Methods
## Next Steps
<CardGroup cols={2}>
<Card title="Public Methods" icon="globe" href="/developers/CLOB/clients/methods-public">
Access market data, orderbooks, and prices.
<Card title="Place Your First Order" icon="plus" href="/trading/quickstart">
Learn how to create and submit orders.
</Card>
<Card title="L1 Methods" icon="key" href="/developers/CLOB/clients/methods-l1">
Private key authentication to create or derive API keys (L2 headers).
</Card>
<Card title="L2 Methods" icon="lock" href="/developers/CLOB/clients/methods-l2">
Manage and close orders. Creating orders requires signer.
</Card>
<Card title="Builder Program Methods" icon="hammer" href="/developers/CLOB/clients/methods-builder">
Builder-specific operations for those in the Builders Program.
<Card title="Geographic Restrictions" icon="globe" href="/api-reference/geoblock">
Check trading availability by region.
</Card>
</CardGroup>
+157 -65
View File
@@ -8,9 +8,7 @@
## Client Initialization
Builder methods require the client to initialize with a separate authentication setup using
builder configs acquired from [Polymarket.com](https://polymarket.com/settings?tab=builder)
and the `@polymarket/builder-signing-sdk` package.
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">
@@ -31,7 +29,7 @@ and the `@polymarket/builder-signing-sdk` package.
"https://clob.polymarket.com",
137,
signer,
apiCreds, // The user's API credentials generated from L1 authentication
apiCreds, // User's API credentials from L1 authentication
signatureType,
funderAddress,
undefined,
@@ -57,7 +55,7 @@ and the `@polymarket/builder-signing-sdk` package.
host="https://clob.polymarket.com",
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=creds, # The user's API credentials generated from L1 authentication
creds=creds, # User's API credentials from L1 authentication
signature_type=signature_type,
funder=funder,
builder_config=builder_config
@@ -73,14 +71,14 @@ and the `@polymarket/builder-signing-sdk` package.
import { BuilderConfig } from "@polymarket/builder-signing-sdk";
const builderConfig = new BuilderConfig({
remoteBuilderConfig: {url: "http://localhost:3000/sign"}
remoteBuilderConfig: { url: "http://localhost:3000/sign" }
});
const clobClient = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds, // The user's API credentials generated from L1 authentication
apiCreds, // User's API credentials from L1 authentication
signatureType,
funder,
undefined,
@@ -89,7 +87,7 @@ and the `@polymarket/builder-signing-sdk` package.
);
```
```typescript Python theme={null}
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_builder_signing_sdk.config import BuilderConfig, RemoteBuilderConfig
import os
@@ -104,7 +102,7 @@ and the `@polymarket/builder-signing-sdk` package.
host="https://clob.polymarket.com",
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=creds, # The user's API credentials generated from L1 authentication
creds=creds, # User's API credentials from L1 authentication
signature_type=signature_type,
funder=funder,
builder_config=builder_config
@@ -115,7 +113,7 @@ and the `@polymarket/builder-signing-sdk` package.
</Tabs>
<Info>
[More information on builder signing](/developers/builders/order-attribution)
See [Order Attribution](/trading/orders/attribution) for more information on builder signing.
</Info>
***
@@ -126,8 +124,7 @@ and the `@polymarket/builder-signing-sdk` package.
### getBuilderTrades()
Retrieves all trades attributed to your builder account.
This method allows builders to track which trades were routed through your platform.
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(
@@ -135,81 +132,176 @@ async getBuilderTrades(
): Promise<BuilderTradesPaginatedResponse>
```
```typescript Params theme={null}
interface TradeParams {
id?: string;
maker_address?: string;
market?: string;
asset_id?: string;
before?: string;
after?: string;
}
```
**Params (`TradeParams`)**
```typescript Response theme={null}
interface BuilderTradesPaginatedResponse {
trades: BuilderTrade[];
next_cursor: string;
limit: number;
count: number;
}
<ResponseField name="id" type="string">
Optional. Filter trades by trade ID.
</ResponseField>
interface BuilderTrade {
id: string;
tradeType: string;
takerOrderHash: string;
builder: string;
market: string;
assetId: string;
side: string;
size: string;
sizeUsdc: string;
price: string;
status: string;
outcome: string;
outcomeIndex: number;
owner: string;
maker: string;
transactionHash: string;
matchTime: string;
bucketIndex: number;
fee: string;
feeUsdc: string;
err_msg?: string | null;
createdAt: string | null;
updatedAt: string | null;
}
```
<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 to make builder-authenticated requests.
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 Introduction" icon="hammer" href="/developers/builders/builder-intro">
Learn the benefits, how to implement, and more.
<Card title="Builders Program" icon="hammer" href="/builders/overview">
Learn about the Builders Program and its benefits.
</Card>
<Card title="Implement Builders Signing" icon="key" href="/developers/builders/order-attribution">
Attribute orders to you, and pre-requisite to using the Relayer Client.
<Card title="Order Attribution" icon="key" href="/trading/orders/attribution">
Attribute orders to your builder account.
</Card>
<Card title="Relayer Client" icon="globe" href="/developers/builders/relayer-client">
The relayer executes other gasless transactions for your users, on your app.
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place and manage orders with API credentials.
</Card>
<Card title="Full Example Implementations" icon="puzzle" href="/developers/builders/examples">
Complete Next.js examples integrated with embedded wallets (Privy, Magic, Turnkey, wagmi)
<Card title="Gasless Transactions" icon="gas-pump" href="/trading/gasless">
Execute onchain operations without paying gas.
</Card>
</CardGroup>
+227 -117
View File
@@ -43,13 +43,13 @@ L1 methods require the client to initialize with a signer.
)
# Ready to create user API credentials
api_key = await client.create_api_key()
api_key = client.create_api_key()
```
</Tab>
</Tabs>
<Warning>
**Security:** Never commit private keys to version control. Always use environment variables or secure key management systems.
Never commit private keys to version control. Always use environment variables or a secure key management system.
</Warning>
***
@@ -60,68 +60,75 @@ L1 methods require the client to initialize with a signer.
### createApiKey()
Creates a new API key (L2 credentials) for the wallet signer. This generates a new set of credentials that can be used for L2 authenticated requests.
Each wallet can only have one active API key at a time. Creating a new key invalidates the previous one.
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>
```
```typescript Params theme={null}
`nonce` (optional): Custom nonce for deterministic key generation. If not provided, a default derivation is used.
```
<ResponseField name="nonce" type="number">
Optional custom nonce for deterministic key generation. Optional.
</ResponseField>
```typescript Response theme={null}
interface ApiKeyCreds {
apiKey: string;
secret: string;
passphrase: string;
}
```
<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 (L2 credentials) using a specific nonce. If you've already created API credentials with a particular nonce, this method will return the same credentials again.
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>
```
```typescript Params theme={null}
`nonce` (optional): Custom nonce for deterministic key generation. If not provided, a default derivation is used.
```
<ResponseField name="nonce" type="number">
The nonce used when originally creating the key. Optional.
</ResponseField>
```typescript Response theme={null}
interface ApiKeyCreds {
apiKey: string;
secret: string;
passphrase: string;
}
```
<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. This is the recommended method for initial setup if you're unsure if credentials already exist.
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>
```
```typescript Params theme={null}
`nonce` (optional): Custom nonce for deterministic key generation. If not provided, a default derivation is used.
```
<ResponseField name="apiKey" type="string">
The API key string, either derived or newly created.
</ResponseField>
```typescript Response theme={null}
interface ApiKeyCreds {
apiKey: string;
secret: string;
passphrase: string;
}
```
<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>
***
@@ -129,9 +136,7 @@ interface ApiKeyCreds {
### 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 order submission logic.
Place order via L2 methods postOrder or postOrders.
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(
@@ -140,49 +145,103 @@ async createOrder(
): Promise<SignedOrder>
```
```typescript Params theme={null}
interface UserOrder {
tokenID: string;
price: number;
size: number;
side: Side;
feeRateBps?: number;
nonce?: number;
expiration?: number;
taker?: string;
}
<ResponseField name="tokenID" type="string">
The token ID of the market outcome to trade.
</ResponseField>
interface CreateOrderOptions {
tickSize: TickSize;
negRisk?: boolean;
}
```
<ResponseField name="price" type="number">
The limit price for the order.
</ResponseField>
```typescript Response theme={null}
interface SignedOrder {
salt: string;
maker: string;
signer: string;
taker: string;
tokenId: string;
makerAmount: string;
takerAmount: string;
side: number; // 0 = BUY, 1 = SELL
expiration: string;
nonce: string;
feeRateBps: string;
signatureType: number;
signature: string;
}
```
<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.
Use this when you want to sign orders in advance or implement custom order submission logic.
Place orders via L2 methods postOrder or postOrders.
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(
@@ -191,36 +250,89 @@ async createMarketOrder(
): Promise<SignedOrder>
```
```typescript Params theme={null}
interface UserMarketOrder {
tokenID: string;
amount: number; // BUY: dollar amount, SELL: number of shares
side: Side;
price?: number; // Optional price limit
feeRateBps?: number;
nonce?: number;
taker?: string;
orderType?: OrderType.FOK | OrderType.FAK;
}
```
<ResponseField name="tokenID" type="string">
The token ID of the market outcome to trade.
</ResponseField>
```typescript Response theme={null}
interface SignedOrder {
salt: string;
maker: string;
signer: string;
taker: string;
tokenId: string;
makerAmount: string;
takerAmount: string;
side: number; // 0 = BUY, 1 = SELL
expiration: string;
nonce: string;
feeRateBps: string;
signatureType: number;
signature: string;
}
```
<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>
***
@@ -232,7 +344,7 @@ interface SignedOrder {
**Solution:**
* Verify your private key is a valid hex string (starts with "0x")
* 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>
@@ -249,9 +361,7 @@ interface SignedOrder {
<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.
**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">
@@ -262,7 +372,7 @@ interface SignedOrder {
</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:
There's no way to recover lost credentials without the nonce. Create new ones:
```typescript theme={null}
// Create fresh credentials with a new nonce
@@ -277,19 +387,19 @@ interface SignedOrder {
## See Also
<CardGroup cols={2}>
<Card title="Understand CLOB Authentication" icon="shield" href="/developers/CLOB/authentication">
Deep dive into L1 and L2 authentication
<Card title="Authentication" icon="shield" href="/api-reference/authentication">
Deep dive into L1 and L2 authentication.
</Card>
<Card title="CLOB Quickstart Guide" icon="hammer" href="/developers/CLOB/quickstart">
Initialize the CLOB quickly and place your first order.
<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="/developers/CLOB/clients/methods-l2">
Access market data, orderbooks, and prices.
<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="/developers/CLOB/clients/methods-l2">
Manage and close orders. Creating orders requires signer.
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place and manage orders with API credentials.
</Card>
</CardGroup>
+454 -332
View File
@@ -4,13 +4,11 @@
# L2 Methods
> These methods require user API credentials (L2 headers). Use these for placing trades and managing user's positions.
***
> 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 the signer, signatureType, user API credentials, and funder.
L2 methods require the client to initialize with a signer, signature type, API credentials, and funder address.
<Tabs>
<Tab title="TypeScript">
@@ -18,7 +16,7 @@ L2 methods require the client to initialize with the signer, signatureType, user
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers";
const signer = new Wallet(process.env.PRIVATE_KEY)
const signer = new Wallet(process.env.PRIVATE_KEY);
const apiCreds = {
apiKey: process.env.API_KEY,
@@ -31,11 +29,11 @@ L2 methods require the client to initialize with the signer, signatureType, user
137,
signer,
apiCreds,
2, // Deployed Safe proxy wallet
process.env.FUNDER_ADDRESS // Address of deployed Safe proxy wallet
2, // GNOSIS_SAFE
process.env.FUNDER_ADDRESS
);
// Ready to send authenticated requests to the CLOB API!
// Ready to send authenticated requests
const order = await client.postOrder(signedOrder);
```
</Tab>
@@ -57,12 +55,12 @@ L2 methods require the client to initialize with the signer, signatureType, user
chain_id=137,
key=os.getenv("PRIVATE_KEY"),
creds=api_creds,
signature_type=2, # Deployed Safe proxy wallet
funder=os.getenv("FUNDER_ADDRESS") # Address of deployed Safe proxy wallet
signature_type=2, # GNOSIS_SAFE
funder=os.getenv("FUNDER_ADDRESS")
)
# Ready to send authenticated requests to the CLOB API!
order = await client.post_order(signed_order)
# Ready to send authenticated requests
order = client.post_order(signed_order)
```
</Tab>
</Tabs>
@@ -75,8 +73,7 @@ L2 methods require the client to initialize with the signer, signatureType, user
### createAndPostOrder()
A convenience method that creates, prompts signature, and posts an order in a single call.
Use when you want to buy/sell at a specific price and can wait.
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(
@@ -86,44 +83,83 @@ async createAndPostOrder(
): Promise<OrderResponse>
```
```typescript Params theme={null}
interface UserOrder {
tokenID: string;
price: number;
size: number;
side: Side;
feeRateBps?: number;
nonce?: number;
expiration?: number;
taker?: string;
}
**Params**
type CreateOrderOptions = {
tickSize: TickSize;
negRisk?: boolean;
}
<ResponseField name="tokenID" type="string">
The token ID of the outcome to trade.
</ResponseField>
type TickSize = "0.1" | "0.01" | "0.001" | "0.0001";
```
<ResponseField name="price" type="number">
The limit price for the order.
</ResponseField>
```typescript Response theme={null}
interface OrderResponse {
success: boolean;
errorMsg: string;
orderID: string;
transactionsHashes: string[];
status: string;
takingAmount: string;
makingAmount: string;
}
```
<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()
A convenience method that creates, prompts signature, and posts an order in a single call.
Use when you want to buy/sell right now at whatever the market price is.
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(
@@ -133,103 +169,109 @@ async createAndPostMarketOrder(
): Promise<OrderResponse>
```
```typescript Params theme={null}
interface UserMarketOrder {
tokenID: string;
amount: number;
side: Side;
price?: number;
feeRateBps?: number;
nonce?: number;
taker?: string;
orderType?: OrderType.FOK | OrderType.FAK;
}
**Params**
type CreateOrderOptions = {
tickSize: TickSize;
negRisk?: boolean;
}
<ResponseField name="tokenID" type="string">
The token ID of the outcome to trade.
</ResponseField>
type TickSize = "0.1" | "0.01" | "0.001" | "0.0001";
```
<ResponseField name="amount" type="number">
The amount for the market order.
</ResponseField>
```typescript Response theme={null}
interface OrderResponse {
success: boolean;
errorMsg: string;
orderID: string;
transactionsHashes: string[];
status: string;
takingAmount: string;
makingAmount: string;
}
```
<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 and created order to the CLOB.
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
postOnly?: boolean, // Defaults to false
): Promise<OrderResponse>
```
```typescript Params theme={null}
order: SignedOrder // Pre-signed order from createOrder() or createMarketOrder()
orderType?: OrderType // Optional, defaults to GTC
postOnly?: boolean // Optional, defaults to false
```
```typescript Response theme={null}
interface OrderResponse {
success: boolean;
errorMsg: string;
orderID: string;
transactionsHashes: string[];
status: string;
takingAmount: string;
makingAmount: string;
}
```
***
### postOrders()
Posts up to 15 pre-signed and created orders in a single batch.
Posts up to 15 pre-signed orders in a single batch.
```typescript theme={null}
```typescript Signature theme={null}
async postOrders(
args: PostOrdersArgs[],
): Promise<OrderResponse[]>
```
```typescript Params theme={null}
interface PostOrdersArgs {
order: SignedOrder;
orderType: OrderType;
postOnly?: boolean; // Defaults to false
}
```
**Params**
```typescript Response theme={null}
OrderResponse[] // Array of OrderResponse objects
<ResponseField name="order" type="SignedOrder">
The pre-signed order to post.
</ResponseField>
interface OrderResponse {
success: boolean;
errorMsg: string;
orderID: string;
transactionsHashes: string[];
status: string;
takingAmount: string;
makingAmount: string;
}
```
<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>
***
@@ -241,12 +283,15 @@ Cancels a single open order.
async cancelOrder(orderID: string): Promise<CancelOrdersResponse>
```
```typescript Response theme={null}
interface CancelOrdersResponse {
canceled: string[];
not_canceled: Record<string, any>;
}
```
**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>
***
@@ -258,17 +303,6 @@ Cancels multiple orders in a single batch.
async cancelOrders(orderIDs: string[]): Promise<CancelOrdersResponse>
```
```typescript Params theme={null}
orderIDs: string[];
```
```typescript Response theme={null}
interface CancelOrdersResponse {
canceled: string[];
not_canceled: Record<string, any>;
}
```
***
### cancelAll()
@@ -276,14 +310,7 @@ interface CancelOrdersResponse {
Cancels all open orders.
```typescript Signature theme={null}
async cancelAll(): Promise<CancelResponse>
```
```typescript Response theme={null}
interface CancelOrdersResponse {
canceled: string[];
not_canceled: Record<string, any>;
}
async cancelAll(): Promise<CancelOrdersResponse>
```
***
@@ -298,19 +325,15 @@ async cancelMarketOrders(
): Promise<CancelOrdersResponse>
```
```typescript Parameters theme={null}
interface OrderMarketCancelParams {
market?: string;
asset_id?: string;
}
```
**Params**
```typescript Response theme={null}
interface CancelOrdersResponse {
canceled: string[];
not_canceled: Record<string, any>;
}
```
<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>
***
@@ -320,31 +343,73 @@ interface CancelOrdersResponse {
### getOrder()
Get details for a specific order.
Get details for a specific order by ID.
```typescript Signature theme={null}
async getOrder(orderID: string): Promise<OpenOrder>
```
```typescript Response theme={null}
interface OpenOrder {
id: string;
status: string;
owner: string;
maker_address: string;
market: string;
asset_id: string;
side: string;
original_size: string;
size_matched: string;
price: string;
associate_trades: string[];
outcome: string;
created_at: number;
expiration: string;
order_type: string;
}
```
**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>
***
@@ -356,40 +421,22 @@ Get all your open orders.
async getOpenOrders(
params?: OpenOrderParams,
only_first_page?: boolean,
): Promise<OpenOrdersResponse>
): Promise<OpenOrder[]>
```
```typescript Params theme={null}
interface OpenOrderParams {
id?: string; // Order ID
market?: string; // Market condition ID
asset_id?: string; // Token ID
}
**Params**
only_first_page?: boolean // Defaults to false
```
<ResponseField name="id" type="string">
Optional. Filter by order ID.
</ResponseField>
```typescript Response theme={null}
type OpenOrdersResponse = OpenOrder[];
<ResponseField name="market" type="string">
Optional. Filter by market condition ID.
</ResponseField>
interface OpenOrder {
id: string;
status: string;
owner: string;
maker_address: string;
market: string;
asset_id: string;
side: string;
original_size: string;
size_matched: string;
price: string;
associate_trades: string[];
outcome: string;
created_at: number;
expiration: string;
order_type: string;
}
```
<ResponseField name="asset_id" type="string">
Optional. Filter by token ID.
</ResponseField>
***
@@ -404,53 +451,141 @@ async getTrades(
): Promise<Trade[]>
```
```typescript Params theme={null}
interface TradeParams {
id?: string;
maker_address?: string;
market?: string;
asset_id?: string;
before?: string;
after?: string;
}
**Params**
only_first_page?: boolean // Defaults to false
```
<ResponseField name="id" type="string">
Optional. Filter by trade ID.
</ResponseField>
```typescript Response theme={null}
interface Trade {
id: string;
taker_order_id: string;
market: string;
asset_id: string;
side: Side;
size: string;
fee_rate_bps: string;
price: string;
status: string;
match_time: string;
last_update: string;
outcome: string;
bucket_index: number;
owner: string;
maker_address: string;
maker_orders: MakerOrder[];
transaction_hash: string;
trader_side: "TAKER" | "MAKER";
}
<ResponseField name="maker_address" type="string">
Optional. Filter by maker address.
</ResponseField>
interface MakerOrder {
order_id: string;
owner: string;
maker_address: string;
matched_amount: string;
price: string;
fee_rate_bps: string;
asset_id: string;
outcome: string;
side: Side;
}
```
<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>
***
@@ -464,24 +599,19 @@ async getTradesPaginated(
): Promise<TradesPaginatedResponse>
```
```typescript Params theme={null}
interface TradeParams {
id?: string;
maker_address?: string;
market?: string;
asset_id?: string;
before?: string;
after?: string;
}
```
**Response**
```typescript Response theme={null}
interface TradesPaginatedResponse {
trades: Trade[];
limit: number;
count: number;
}
```
<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>
***
@@ -499,24 +629,25 @@ async getBalanceAllowance(
): Promise<BalanceAllowanceResponse>
```
```typescript Params theme={null}
interface BalanceAllowanceParams {
asset_type: AssetType;
token_id?: string;
}
**Params**
enum AssetType {
COLLATERAL = "COLLATERAL",
CONDITIONAL = "CONDITIONAL",
}
```
<ResponseField name="asset_type" type="AssetType">
The type of asset to query. One of `"COLLATERAL"` or `"CONDITIONAL"`.
</ResponseField>
```typescript Response theme={null}
interface BalanceAllowanceResponse {
balance: string;
allowance: string;
}
```
<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>
***
@@ -530,21 +661,11 @@ async updateBalanceAllowance(
): Promise<void>
```
```typescript Params theme={null}
interface BalanceAllowanceParams {
asset_type: AssetType;
token_id?: string;
}
enum AssetType {
COLLATERAL = "COLLATERAL",
CONDITIONAL = "CONDITIONAL",
}
```
***
## API Key Management (L2)
## API Key Management
***
### getApiKeys()
@@ -554,17 +675,11 @@ Get all API keys associated with your account.
async getApiKeys(): Promise<ApiKeysResponse>
```
```typescript Response theme={null}
interface ApiKeysResponse {
apiKeys: ApiKeyCreds[];
}
**Response**
interface ApiKeyCreds {
key: string;
secret: string;
passphrase: string;
}
```
<ResponseField name="apiKeys" type="ApiKeyCreds[]">
Array of API key credential objects associated with the account.
</ResponseField>
***
@@ -572,9 +687,7 @@ interface ApiKeyCreds {
Deletes (revokes) the currently authenticated API key.
**TypeScript Signature:**
```typescript theme={null}
```typescript Signature theme={null}
async deleteApiKey(): Promise<any>
```
@@ -586,30 +699,39 @@ async deleteApiKey(): Promise<any>
### getNotifications()
Retrieves all event notifications for the L2 authenticated user.
Records are removed automatically after 48 hours or if manually removed via dropNotifications().
Retrieves all event notifications for the authenticated user. Records are automatically removed after 48 hours.
```typescript Signature theme={null}
public async getNotifications(): Promise<Notification[]>
async getNotifications(): Promise<Notification[]>
```
```typescript Response theme={null}
interface Notification {
id: number; // Unique notification ID
owner: string; // User's L2 credential apiKey or empty string for global notifications
payload: any; // Type-specific payload data
timestamp?: number; // Unix timestamp
type: number; // Notification type (see type mapping below)
}
```
**Response**
**Notification Type Mapping**
<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 |
| 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 |
***
@@ -618,33 +740,33 @@ interface Notification {
Mark notifications as read/dismissed.
```typescript Signature theme={null}
public async dropNotifications(params?: DropNotificationParams): Promise<void>
async dropNotifications(params?: DropNotificationParams): Promise<void>
```
```typescript Params theme={null}
interface DropNotificationParams {
ids: string[]; // Array of notification IDs to mark as read
}
```
**Params**
<ResponseField name="ids" type="string[]">
Array of notification IDs to dismiss.
</ResponseField>
***
## See Also
<CardGroup cols={2}>
<Card title="Understand CLOB Authentication" icon="shield" href="/developers/CLOB/authentication">
Deep dive into L1 and L2 authentication
<Card title="Authentication" icon="shield" href="/api-reference/authentication">
Deep dive into L1 and L2 authentication.
</Card>
<Card title="Public Methods" icon="globe" href="/developers/CLOB/clients/methods-l2">
Access market data, orderbooks, and prices.
<Card title="L1 Methods" icon="key" href="/trading/clients/l1">
Sign orders and derive API credentials with your private key.
</Card>
<Card title="L1 Methods" icon="lock" href="/developers/CLOB/clients/methods-l2">
Private key authentication to create or derive API keys (L2 headers)
<Card title="Public Methods" icon="globe" href="/trading/clients/public">
Read market data and orderbooks without auth.
</Card>
<Card title="Web Socket API" icon="hammer" href="/developers/CLOB/websocket/wss-overview">
Real-time market data streaming
<Card title="WebSocket" icon="bolt" href="/market-data/websocket/overview">
Real-time market data streaming.
</Card>
</CardGroup>
+86 -224
View File
@@ -2,234 +2,96 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Methods Overview
# Clients & SDKs
> CLOB client methods require different levels of authentication. This reference is organized by what credentials you need to call each method.
> 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()
```
</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="Public Methods" icon="globe" href="/developers/CLOB/clients/methods-public">
Access market data, orderbooks, and prices.
<Card title="Quickstart" icon="rocket" href="/quickstart">
Set up your client and place your first order.
</Card>
<Card title="L1 Methods" icon="key" href="/developers/CLOB/clients/methods-l1">
Private key authentication to create or derive API keys (L2 headers).
</Card>
<Card title="L2 Methods" icon="lock" href="/developers/CLOB/clients/methods-l2">
Manage and close orders. Creating orders requires signer.
</Card>
<Card title="Builder Program Methods" icon="hammer" href="/developers/CLOB/clients/methods-builder">
Builder-specific operations for those in the Builders Program.
</Card>
</CardGroup>
***
## Client Initialization by Use Case
<Tabs>
<Tab title="Get Market Data">
<CodeGroup>
```typescript TypeScript theme={null}
// No signer or credentials needed
const client = new ClobClient(
"https://clob.polymarket.com",
137
);
// All public methods available
const markets = await client.getMarkets();
const book = await client.getOrderBook(tokenId);
const price = await client.getPrice(tokenId, "BUY");
```
```python Python theme={null}
# No signer or credentials needed
client = new ClobClient(
host="https://clob.polymarket.com",
chain_id=137
)
# All public methods available
markets = client.get_markets()
book = client.get_order_book()
price = client.get_price()
```
</CodeGroup>
</Tab>
<Tab title="Generate User API Credentials">
<CodeGroup>
```typescript TypeScript theme={null}
// Create client with signer
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer
);
// All public and L1 methods available
const newCreds = createApiKey();
const derivedCreds = deriveApiKey();
const creds = createOrDeriveApiKey();
```
```python Python theme={null}
# Create client with signer
client = new ClobClient(
host="https://clob.polymarket.com",
chain_id=137
key="private_key"
)
# All public and L1 methods available
new_creds = client.create_api_key()
derived_creds = client.derive_api_key()
creds = client.create_or_derive_api_key()
```
</CodeGroup>
</Tab>
<Tab title="Create and Post Order">
<CodeGroup>
```typescript TypeScript theme={null}
// Create client with signer and creds
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
creds,
2, // Indicates Gnosis Safe proxy
funder // Safe wallet address holding funds
);
// All public, L1, and L2 methods available
const order = await client.createOrder({ /* ... */ });
const result = await client.postOrder(order);
const trades = await client.getTrades();
```
```python Python theme={null}
# Create client with signer and creds
const client = new ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key="private_key",
creds=creds,
signature_type=2, // Indicates Gnosis Safe proxy
funder="funder_address" // Safe wallet address holding funds
)
# All public, L1, and L2 methods available
order = client.create_order({ /* ... */ })
result = client.post_order(order)
trades = client.get_trades()
```
</CodeGroup>
</Tab>
<Tab title="Get Builders Orders">
<CodeGroup>
```typescript TypeScript theme={null}
// Create client with builder's authentication headers
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: BuilderConfig = {
localBuilderCreds: builderCreds
};
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
creds, // User's API credentials
2,
funder,
undefined,
false,
builderConfig // Builder's API credentials
);
// You can call all methods including builder methods
const builderTrades = await client.getBuilderTrades();
```
```python Python theme={null}
# Create client with builder's authentication headers
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import ApiCreds
from py_builder_signing_sdk.config import BuilderConfig, BuilderApiKeyCreds
builder_creds = BuilderApiKeyCreds(
key="POLY_BUILDER_API_KEY",
secret="POLY_BUILDER_SECRET,
passphrase="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=creds, # User's API credentials
signature_type=2,
funder=funder_address,
builder_config=builder_config # Builder's API credentials
)
# You can call all methods including builder methods
builder_trades = client.get_builder_trades()
```
</CodeGroup>
Learn more about the Builders Program and Relay Client here
</Tab>
</Tabs>
***
## Resources
<CardGroup cols={3}>
<Card title="TypeScript Client" icon="github" href="https://github.com/Polymarket/clob-client">
Open source TypeScript client on GitHub
</Card>
<Card title="Python Client" icon="github" href="https://github.com/Polymarket/py-clob-client">
Open source Python client for GitHub
</Card>
<Card title="Rust Client" icon="github" href="https://github.com/Polymarket/rs-clob-client">
Open source Rust client on GitHub
</Card>
<Card title="TypeScript Examples" icon="code" href="https://github.com/Polymarket/clob-client/tree/main/examples">
TypeScript client method examples
</Card>
<Card title="Python Examples" icon="python" href="https://github.com/Polymarket/py-clob-client/tree/main/examples">
Python client method examples
</Card>
<Card title="Rust Examples" icon="rust" href="https://github.com/Polymarket/rs-clob-client/tree/main/examples">
Rust client method examples
</Card>
<Card title="CLOB Rest API Reference" icon="hammer" href="/api-reference/orderbook/get-order-book-summary">
Complete REST endpoint documentation
</Card>
<Card title="Web Socket API" icon="hammer" href="/developers/CLOB/websocket/wss-overview">
Real-time market data streaming
<Card title="Authentication" icon="lock" href="/api-reference/authentication">
Understand L1/L2 auth and API credentials.
</Card>
</CardGroup>
+331 -385
View File
@@ -35,7 +35,7 @@ Public methods require the client to initialize with the host URL and Polygon ch
)
# Ready to call public methods
markets = await client.get_markets()
markets = client.get_markets()
```
</Tab>
</Tabs>
@@ -68,50 +68,121 @@ Get details for a single market by condition ID.
async getMarket(conditionId: string): Promise<Market>
```
```typescript Response theme={null}
interface MarketToken {
outcome: string;
price: number;
token_id: string;
winner: boolean;
}
<ResponseField name="accepting_order_timestamp" type="string">
Timestamp from which the market started accepting orders, or null if not set.
</ResponseField>
interface Market {
accepting_order_timestamp: string | null;
accepting_orders: boolean;
active: boolean;
archived: boolean;
closed: boolean;
condition_id: string;
description: string;
enable_order_book: boolean;
end_date_iso: string;
fpmm: string;
game_start_time: string;
icon: string;
image: string;
is_50_50_outcome: boolean;
maker_base_fee: number;
market_slug: string;
minimum_order_size: number;
minimum_tick_size: number;
neg_risk: boolean;
neg_risk_market_id: string;
neg_risk_request_id: string;
notifications_enabled: boolean;
question: string;
question_id: string;
rewards: {
max_spread: number;
min_size: number;
rates: any | null;
};
seconds_delay: number;
tags: string[];
taker_base_fee: number;
tokens: MarketToken[];
}
```
<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>
***
@@ -123,56 +194,17 @@ Get details for multiple markets paginated.
async getMarkets(): Promise<PaginationPayload>
```
```typescript Response theme={null}
interface PaginationPayload {
limit: number;
count: number;
data: Market[];
}
<ResponseField name="limit" type="number">
Maximum number of results per page.
</ResponseField>
interface Market {
accepting_order_timestamp: string | null;
accepting_orders: boolean;
active: boolean;
archived: boolean;
closed: boolean;
condition_id: string;
description: string;
enable_order_book: boolean;
end_date_iso: string;
fpmm: string;
game_start_time: string;
icon: string;
image: string;
is_50_50_outcome: boolean;
maker_base_fee: number;
market_slug: string;
minimum_order_size: number;
minimum_tick_size: number;
neg_risk: boolean;
neg_risk_market_id: string;
neg_risk_request_id: string;
notifications_enabled: boolean;
question: string;
question_id: string;
rewards: {
max_spread: number;
min_size: number;
rates: any | null;
};
seconds_delay: number;
tags: string[];
taker_base_fee: number;
tokens: MarketToken[];
}
<ResponseField name="count" type="number">
Total number of markets returned.
</ResponseField>
interface MarketToken {
outcome: string;
price: number;
token_id: string;
winner: boolean;
}
```
<ResponseField name="data" type="Market[]">
Array of Market objects. See `getMarket()` for the full Market structure.
</ResponseField>
***
@@ -184,129 +216,38 @@ Get simplified market data paginated for faster loading.
async getSimplifiedMarkets(): Promise<PaginationPayload>
```
```typescript Response theme={null}
interface PaginationPayload {
limit: number;
count: number;
data: SimplifiedMarket[];
}
<ResponseField name="limit" type="number">
Maximum number of results per page.
</ResponseField>
interface SimplifiedMarket {
accepting_orders: boolean;
active: boolean;
archived: boolean;
closed: boolean;
condition_id: string;
rewards: {
rates: any | null;
min_size: number;
max_spread: number;
};
tokens: SimplifiedToken[];
}
<ResponseField name="count" type="number">
Total number of markets returned.
</ResponseField>
interface SimplifiedToken {
outcome: string;
price: number;
token_id: string;
}
```
<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>
```
```typescript Response theme={null}
interface PaginationPayload {
limit: number;
count: number;
data: Market[];
}
interface Market {
accepting_order_timestamp: string | null;
accepting_orders: boolean;
active: boolean;
archived: boolean;
closed: boolean;
condition_id: string;
description: string;
enable_order_book: boolean;
end_date_iso: string;
fpmm: string;
game_start_time: string;
icon: string;
image: string;
is_50_50_outcome: boolean;
maker_base_fee: number;
market_slug: string;
minimum_order_size: number;
minimum_tick_size: number;
neg_risk: boolean;
neg_risk_market_id: string;
neg_risk_request_id: string;
notifications_enabled: boolean;
question: string;
question_id: string;
rewards: {
max_spread: number;
min_size: number;
rates: any | null;
};
seconds_delay: number;
tags: string[];
taker_base_fee: number;
tokens: MarketToken[];
}
interface MarketToken {
outcome: string;
price: number;
token_id: string;
winner: boolean;
}
```
***
### getSamplingSimplifiedMarkets()
Get simplified market data for markets eligible for sampling/liquidity rewards.
```typescript Signature theme={null}
async getSamplingSimplifiedMarkets(): Promise<PaginationPayload>
```
```typescript Response theme={null}
interface PaginationPayload {
limit: number;
count: number;
data: SimplifiedMarket[];
}
interface SimplifiedMarket {
accepting_orders: boolean;
active: boolean;
archived: boolean;
closed: boolean;
condition_id: string;
rewards: {
rates: any | null;
min_size: number;
max_spread: number;
};
tokens: SimplifiedToken[];
}
interface SimplifiedToken {
outcome: string;
price: number;
token_id: string;
}
```
***
## Order Books and Prices
@@ -315,6 +256,8 @@ interface SimplifiedToken {
### calculateMarketPrice()
Calculate the estimated price for a market order of a given size.
```typescript Signature theme={null}
async calculateMarketPrice(
tokenID: string,
@@ -324,23 +267,25 @@ async calculateMarketPrice(
): Promise<number>
```
```typescript Params theme={null}
enum OrderType {
GTC = "GTC", // Good Till Cancelled
FOK = "FOK", // Fill or Kill
GTD = "GTD", // Good Till Date
FAK = "FAK", // Fill and Kill
}
<ResponseField name="tokenID" type="string">
The token ID to calculate the market price for.
</ResponseField>
enum Side {
BUY = "BUY",
SELL = "SELL",
}
```
<ResponseField name="side" type="Side">
The side of the order. One of: `BUY`, `SELL`
</ResponseField>
```typescript Response theme={null}
number // calculated market price
```
<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>
***
@@ -352,24 +297,41 @@ Get the order book for a specific token ID.
async getOrderBook(tokenID: string): Promise<OrderBookSummary>
```
```typescript Response theme={null}
interface OrderBookSummary {
market: string;
asset_id: string;
timestamp: string;
bids: OrderSummary[];
asks: OrderSummary[];
min_order_size: string;
tick_size: string;
neg_risk: boolean;
hash: string;
}
<ResponseField name="market" type="string">
The market condition ID.
</ResponseField>
interface OrderSummary {
price: string;
size: string;
}
```
<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>
***
@@ -381,16 +343,17 @@ Get order books for multiple token IDs.
async getOrderBooks(params: BookParams[]): Promise<OrderBookSummary[]>
```
```typescript Params theme={null}
interface BookParams {
token_id: string;
side: Side; // Side.BUY or Side.SELL
}
```
<ResponseField name="token_id" type="string">
The token ID to fetch the order book for.
</ResponseField>
```typescript Response theme={null}
OrderBookSummary[]
```
<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>
***
@@ -405,11 +368,9 @@ async getPrice(
): Promise<any>
```
```typescript Response theme={null}
{
price: string;
}
```
<ResponseField name="price" type="string">
The current best price for the requested side.
</ResponseField>
***
@@ -421,23 +382,9 @@ Get the current best prices for multiple token IDs.
async getPrices(params: BookParams[]): Promise<PricesResponse>
```
```typescript Params theme={null}
interface BookParams {
token_id: string;
side: Side; // Side.BUY or Side.SELL
}
```
```typescript Response theme={null}
interface TokenPrices {
BUY?: string;
SELL?: string;
}
type PricesResponse = {
[tokenId: string]: TokenPrices;
}
```
<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>
***
@@ -449,34 +396,23 @@ Get the midpoint price (average of best bid and best ask) for a token ID.
async getMidpoint(tokenID: string): Promise<any>
```
```typescript Response theme={null}
{
mid: string;
}
```
<ResponseField name="mid" type="string">
The midpoint price, calculated as the average of best bid and best ask.
</ResponseField>
***
### getMidpoints()
Get the midpoint prices (average of best bid and best ask) for multiple token IDs.
Get the midpoint prices for multiple token IDs.
```typescript Signature theme={null}
async getMidpoints(params: BookParams[]): Promise<any>
```
```typescript Params theme={null}
interface BookParams {
token_id: string;
side: Side; // Side is ignored
}
```
```typescript Response theme={null}
{
[tokenId: string]: string;
}
```
<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>
***
@@ -488,34 +424,23 @@ Get the spread (difference between best ask and best bid) for a token ID.
async getSpread(tokenID: string): Promise<SpreadResponse>
```
```typescript Response theme={null}
interface SpreadResponse {
spread: string;
}
```
<ResponseField name="spread" type="string">
The spread value, calculated as the difference between best ask and best bid.
</ResponseField>
***
### getSpreads()
Get the spreads (difference between best ask and best bid) for multiple token IDs.
Get the spreads for multiple token IDs.
```typescript Signature theme={null}
async getSpreads(params: BookParams[]): Promise<SpreadsResponse>
```
```typescript Params theme={null}
interface BookParams {
token_id: string;
side: Side;
}
```
```typescript Response theme={null}
type SpreadsResponse = {
[tokenId: string]: string;
}
```
<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>
***
@@ -527,30 +452,33 @@ Get historical price data for a token.
async getPricesHistory(params: PriceHistoryFilterParams): Promise<MarketPrice[]>
```
```typescript Params theme={null}
interface PriceHistoryFilterParams {
market: string; // tokenID
startTs?: number;
endTs?: number;
fidelity?: number;
interval: PriceHistoryInterval;
}
<ResponseField name="market" type="string">
The token ID to fetch price history for.
</ResponseField>
enum PriceHistoryInterval {
MAX = "max",
ONE_WEEK = "1w",
ONE_DAY = "1d",
SIX_HOURS = "6h",
ONE_HOUR = "1h",
}
```
<ResponseField name="startTs" type="number">
Optional start timestamp (Unix seconds) for the price history range.
</ResponseField>
```typescript Response theme={null}
interface MarketPrice {
t: number; // timestamp
p: number; // price
}
```
<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>
***
@@ -566,73 +494,91 @@ Get the price of the most recent trade for a token.
async getLastTradePrice(tokenID: string): Promise<LastTradePrice>
```
```typescript Response theme={null}
interface LastTradePrice {
price: string;
side: string;
}
```
<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 price of the most recent trade for a token.
Get the most recent trade prices for multiple tokens.
```typescript Signature theme={null}
async getLastTradesPrices(params: BookParams[]): Promise<LastTradePriceWithToken[]>
```
```typescript Params theme={null}
interface BookParams {
token_id: string;
side: Side;
}
```
<ResponseField name="price" type="string">
The price of the most recent trade for the token.
</ResponseField>
```typescript Response theme={null}
interface LastTradePriceWithToken {
price: string;
side: string;
token_id: string;
}
```
<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
### getMarketTradesEvents()
Get recent trade events for a market.
```typescript Signature theme={null}
async getMarketTradesEvents(conditionID: string): Promise<MarketTradeEvent[]>
```
```typescript Response theme={null}
interface MarketTradeEvent {
event_type: string;
market: {
condition_id: string;
asset_id: string;
question: string;
icon: string;
slug: string;
};
user: {
address: string;
username: string;
profile_picture: string;
optimized_profile_picture: string;
pseudonym: string;
};
side: Side;
size: string;
fee_rate_bps: string;
price: string;
outcome: string;
outcome_index: number;
transaction_hash: string;
timestamp: string;
}
```
<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
@@ -646,9 +592,9 @@ Get the fee rate in basis points for a token.
async getFeeRateBps(tokenID: string): Promise<number>
```
```typescript Response theme={null}
number
```
<ResponseField name="returns" type="number">
The fee rate in basis points for the specified token.
</ResponseField>
***
@@ -660,9 +606,9 @@ Get the tick size (minimum price increment) for a market.
async getTickSize(tokenID: string): Promise<TickSize>
```
```typescript Response theme={null}
type TickSize = "0.1" | "0.01" | "0.001" | "0.0001";
```
<ResponseField name="returns" type="string">
The tick size for the market. One of: `0.1`, `0.01`, `0.001`, `0.0001`
</ResponseField>
***
@@ -674,9 +620,9 @@ Check if a market uses negative risk (binary complementary tokens).
async getNegRisk(tokenID: string): Promise<boolean>
```
```typescript Response theme={null}
boolean
```
<ResponseField name="returns" type="boolean">
Whether the market uses negative risk.
</ResponseField>
***
@@ -690,28 +636,28 @@ Get the current server timestamp.
async getServerTime(): Promise<number>
```
```typescript Response theme={null}
number // Unix timestamp in seconds
```
<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="/developers/CLOB/clients/methods-l1">
Private key authentication to create or derive API keys (L2 headers).
<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="/developers/CLOB/clients/methods-l2">
Manage and close orders. Creating orders requires signer.
<Card title="L2 Methods" icon="lock" href="/trading/clients/l2">
Place orders, cancel orders, and query your trades.
</Card>
<Card title="CLOB Rest API Reference" icon="hammer" href="/api-reference/orderbook/get-order-book-summary">
Complete REST endpoint documentation
<Card title="REST API Reference" icon="code" href="/api-reference/introduction">
Complete REST endpoint documentation.
</Card>
<Card title="Web Socket API" icon="hammer" href="/developers/CLOB/websocket/wss-overview">
Real-time market data streaming
<Card title="WebSocket" icon="bolt" href="/market-data/websocket/overview">
Real-time market data streaming.
</Card>
</CardGroup>
+92 -55
View File
@@ -4,27 +4,18 @@
# Geographic Restrictions
> Check geographic restrictions before placing orders on Polymarket's CLOB
> Check geographic restrictions before placing orders on the Polymarket API
## Overview
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.
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.
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>
***
## Server Infrastructure
* **Primary Servers**: eu-west-2
* **Closest Non-Georestricted Region**: eu-west-1
***
## Geoblock Endpoint
Check the geographic eligibility of the requesting IP address:
@@ -33,14 +24,16 @@ Check the geographic eligibility of the requesting IP address:
GET https://polymarket.com/api/geoblock
```
<Note>This endpoint is on `polymarket.com`, not the API servers.</Note>
### Response
```typescript theme={null}
```json theme={null}
{
"blocked": boolean;
"ip": string;
"country": string;
"region": string;
"blocked": true,
"ip": "203.0.113.42",
"country": "US",
"region": "NY"
}
```
@@ -55,43 +48,43 @@ GET https://polymarket.com/api/geoblock
## Blocked Countries
The following **33 countries** are completely restricted from placing orders on Polymarket:
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 |
| ------------ | ------------------------------------ |
| AU | Australia |
| BE | Belgium |
| BY | Belarus |
| BI | Burundi |
| CF | Central African Republic |
| CD | Congo (Kinshasa) |
| CU | Cuba |
| DE | Germany |
| ET | Ethiopia |
| FR | France |
| GB | United Kingdom |
| IR | Iran |
| IQ | Iraq |
| IT | Italy |
| KP | North Korea |
| LB | Lebanon |
| LY | Libya |
| MM | Myanmar |
| NI | Nicaragua |
| PL | Poland |
| RU | Russia |
| SG | Singapore |
| SO | Somalia |
| SS | South Sudan |
| SD | Sudan |
| SY | Syria |
| TH | Thailand |
| TW | Taiwan |
| UM | United States Minor Outlying Islands |
| US | United States |
| VE | Venezuela |
| YE | Yemen |
| ZW | Zimbabwe |
| 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 |
| 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 |
***
@@ -108,6 +101,22 @@ In addition to fully blocked countries, the following specific regions within ot
***
## 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>
@@ -154,3 +163,31 @@ In addition to fully blocked countries, the following specific regions within ot
```
</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>
+174 -30
View File
@@ -2,55 +2,199 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# CLOB Introduction
# Overview
Welcome to the Polymarket Order Book API! This documentation provides overviews, explanations, examples, and annotations to simplify interaction with the order book. The following sections detail the Polymarket Order Book and the API usage.
> Trading on the Polymarket CLOB
## System
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.
Polymarket's Order Book, or CLOB (Central Limit Order Book), is hybrid-decentralized. It includes an operator for off-chain matching/ordering, with settlement executed on-chain, non-custodially, via signed order messages.
We recommend using the open-source SDK clients, which handle order signing, authentication, and submission:
The exchange uses a custom Exchange contract facilitating atomic swaps between binary Outcome Tokens (CTF ERC1155 assets and ERC20 PToken assets) and collateral assets (ERC20), following signed limit orders. Designed for binary markets, the contract enables complementary tokens to match across a unified order book.
<CardGroup cols={2}>
<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>
Orders are EIP712-signed structured data. Matched orders have one maker and one or more takers, with price improvements benefiting the taker. The operator handles off-chain order management and submits matched trades to the blockchain for on-chain execution.
<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>
</CardGroup>
## API
<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>
The Polymarket Order Book API enables market makers and traders to programmatically manage market orders. Orders of any amount can be created, listed, fetched, or read from the market order books. Data includes all available markets, market prices, and order history via REST and WebSocket endpoints.
***
## Security
## Authentication
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 CLOB uses two levels of authentication:
The operator's privileges are limited to order matching, non-censorship, and ensuring correct ordering. Operators can't set prices or execute unauthorized trades. Users can cancel orders on-chain independently if trust issues arise.
| 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 |
## Fees
You use your private key once to derive **L2 credentials** (API key, secret, passphrase), which authenticate all subsequent trading requests.
### Schedule
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
> Subject to change
const signer = new Wallet(process.env.PRIVATE_KEY);
| Volume Level | Maker Fee Base Rate (bps) | Taker Fee Base Rate (bps) |
| ------------ | ------------------------- | ------------------------- |
| >0 USDC | 0 | 0 |
// Derive L2 API credentials
const tempClient = new ClobClient("https://clob.polymarket.com", 137, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
```
### Overview
```python Python theme={null}
from py_clob_client.client import ClobClient
import os
Fees apply symmetrically in output assets (proceeds). This symmetry ensures fairness and market integrity. Fees are calculated differently depending on whether you are buying or selling:
private_key = os.getenv("PRIVATE_KEY")
* **Selling outcome tokens (base) for collateral (quote):**
# 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()
```
</CodeGroup>
$$
feeQuote = baseRate \times \min(price, 1 - price) \times size
$$
***
* **Buying outcome tokens (base) with collateral (quote):**
## Signature Types
$$
feeBase = baseRate \times \min(price, 1 - price) \times \frac{size}{price}
$$
When initializing the trading client, you must specify your wallet's **signature type** and **funder address**:
## Additional Resources
| 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 |
* [Exchange contract source code](https://github.com/Polymarket/ctf-exchange/tree/main/src)
* [Exchange contract documentation](https://github.com/Polymarket/ctf-exchange/blob/main/docs/Overview.md)
<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
)
```
</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's 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>
+287 -131
View File
@@ -2,172 +2,328 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Cancel Orders(s)
# Cancel Order
> Multiple endpoints to cancel a single order, multiple orders, all orders or all orders from a single market.
> Cancel single, multiple, or all open orders
# Cancel an single Order
All cancel endpoints require [L2 authentication](/trading/overview#authentication). The response always includes `canceled` (list of cancelled order IDs) and `not_canceled` (map of order IDs to failure reasons).
<Tip> This endpoint requires a L2 Header. </Tip>
***
Cancel an order.
**HTTP REQUEST**
`DELETE /<clob-endpoint>/order`
### Request Payload Parameters
| Name | Required | Type | Description |
| ------- | -------- | ------ | --------------------- |
| orderID | yes | string | ID of order to cancel |
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
## Cancel a Single Order
<CodeGroup>
```python Python theme={null}
resp = client.cancel(order_id="0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88")
print(resp)
```typescript TypeScript theme={null}
const resp = await client.cancelOrder("0xb816482a...");
console.log(resp);
// { canceled: ["0xb816482a..."], not_canceled: {} }
```
```javascript Typescript theme={null}
async function main() {
// Send it to the server
const resp = await clobClient.cancelOrder({
orderID:
"0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88",
});
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
resp = client.cancel(order_id="0xb816482a...")
print(resp)
# {"canceled": ["0xb816482a..."], "not_canceled": {}}
```
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/order" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '{"orderID": "0xb816482a..."}'
```
</CodeGroup>
# Cancel Multiple Orders
***
<Tip> This endpoint requires a L2 Header. </Tip>
**HTTP REQUEST**
`DELETE /<clob-endpoint>/orders`
### Request Payload Parameters
| Name | Required | Type | Description |
| ---- | -------- | --------- | --------------------------- |
| null | yes | string\[] | IDs of the orders to cancel |
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
## Cancel Multiple Orders
<CodeGroup>
```python Python theme={null}
resp = client.cancel_orders(["0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88", "0xaaaa..."])
print(resp)
```typescript TypeScript theme={null}
const resp = await client.cancelOrders(["0xb816482a...", "0xc927593b..."]);
```
```javascript Typescript theme={null}
async function main() {
// Send it to the server
const resp = await clobClient.cancelOrders([
"0x38a73eed1e6d177545e9ab027abddfb7e08dbe975fa777123b1752d203d6ac88",
"0xaaaa...",
]);
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
resp = client.cancel_orders([
"0xb816482a...",
"0xc927593b...",
])
```
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/orders" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '["0xb816482a...", "0xc927593b..."]'
```
</CodeGroup>
# Cancel ALL Orders
***
<Tip> This endpoint requires a L2 Header. </Tip>
## Cancel All Orders
Cancel all open orders posted by a user.
**HTTP REQUEST**
`DELETE /<clob-endpoint>/cancel-all`
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
Cancel every open order across all markets:
<CodeGroup>
```typescript TypeScript theme={null}
const resp = await client.cancelAll();
```
```python Python theme={null}
resp = client.cancel_all()
print(resp)
print("Done!")
```
```javascript Typescript theme={null}
async function main() {
const resp = await clobClient.cancelAll();
console.log(resp);
console.log(`Done!`);
}
main();
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/cancel-all" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..."
```
</CodeGroup>
# Cancel orders from market
***
<Tip> This endpoint requires a L2 Header. </Tip>
## Cancel by Market
Cancel orders from market.
**HTTP REQUEST**
`DELETE /<clob-endpoint>/cancel-market-orders`
### Request Payload Parameters
| Name | Required | Type | Description |
| --------- | -------- | ------ | -------------------------- |
| market | no | string | condition id of the market |
| asset\_id | no | string | id of the asset/token |
### Response Format
| Name | Type | Description |
| ------------- | --------- | -------------------------------------------------------------------------- |
| canceled | string\[] | list of canceled orders |
| not\_canceled | {} | a order id -> reason map that explains why that order couldn't be canceled |
Cancel all orders for a specific market, optionally filtered to a single token. Both `market` and `asset_id` are optional — omit both to cancel all orders.
<CodeGroup>
```python Python theme={null}
resp = client.cancel_market_orders(market="0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af", asset_id="52114319501245915516055106046884209969926127482827954674443846427813813222426")
print(resp)
```typescript TypeScript theme={null}
const resp = await client.cancelMarketOrders({
market: "0xbd31dc8a...", // optional: condition ID
asset_id: "52114319501245...", // optional: specific token
});
```
```javascript Typescript theme={null}
async function main() {
// Send it to the server
const resp = await clobClient.cancelMarketOrders({
market:
"0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
asset_id:
"52114319501245915516055106046884209969926127482827954674443846427813813222426",
});
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
resp = client.cancel_market_orders(
market="0xbd31dc8a...",
asset_id="52114319501245...", # optional
)
```
```bash REST theme={null}
curl -X DELETE "https://clob.polymarket.com/cancel-market-orders" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '{"market": "0xbd31dc8a...", "asset_id": "52114319501245..."}'
```
</CodeGroup>
***
## Onchain Cancellation
If the API is unavailable, you can cancel orders directly on the [Exchange contract](https://github.com/Polymarket/ctf-exchange/tree/main/src) by calling `cancelOrder(Order order)` onchain. Pass the full order struct that was signed when placing the order.
Use the `CTFExchange` or `NegRiskCTFExchange` contract depending on the market type. See [Contract Addresses](/resources/contract-addresses) for addresses.
This is a fallback mechanism — API cancellation is instant while onchain cancellation requires a transaction.
***
## Querying Orders
### Get a Single Order
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order.status, order.size_matched);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order["status"], order["size_matched"])
```
</CodeGroup>
### Get Open Orders
Retrieve all open orders, optionally filtered by market or token:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by token
const tokenOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(market="0xbd31dc8a...")
)
```
</CodeGroup>
### OpenOrder Object
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Condition ID |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Size at placement |
| `size_matched` | string | Amount filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `associate_trades` | string\[] | Trade IDs this order has been included in |
| `expiration` | string | Unix expiration timestamp (`0` if none) |
| `created_at` | string | Unix creation timestamp |
***
## Trade History
When an order is matched, it creates a trade. Trades progress through these statuses:
| Status | Terminal | Description |
| ----------- | -------- | --------------------------------------- |
| `MATCHED` | No | Matched and sent for onchain submission |
| `MINED` | No | Mined on the chain, no finality yet |
| `CONFIRMED` | Yes | Achieved finality — trade successful |
| `RETRYING` | No | Transaction failed — being retried |
| `FAILED` | Yes | Failed permanently |
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
trades = client.get_trades()
market_trades = client.get_trades(
TradeParams(market="0xbd31dc8a...")
)
```
</CodeGroup>
Additional filter parameters: `id`, `maker_address`, `asset_id`, `before`, `after`.
For large result sets, use the paginated variant:
<CodeGroup>
```typescript TypeScript theme={null}
const page = await client.getTradesPaginated({ market: "0xbd31dc8a..." });
console.log(page.trades, page.count); // trades array + total count
```
```python Python theme={null}
page = client.get_trades_paginated(TradeParams(market="0xbd31dc8a..."))
```
</CodeGroup>
### Trade Object
| Field | Type | Description |
| ------------------ | ------------- | ------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order hash |
| `market` | string | Condition ID |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `price` | string | Execution price |
| `fee_rate_bps` | string | Fee rate in basis points |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when matched |
| `last_update` | string | Unix timestamp of last status change |
| `outcome` | string | Human-readable outcome (e.g., "Yes") |
| `maker_address` | string | Maker's funder address |
| `owner` | string | API key of the trade owner |
| `transaction_hash` | string | Onchain transaction hash |
| `bucket_index` | number | Index for trade reconciliation |
| `trader_side` | string | `TAKER` or `MAKER` |
| `maker_orders` | MakerOrder\[] | Maker orders that filled this trade |
<Note>
A single trade can be split across multiple onchain transactions due to gas
limits. Use `bucket_index` and `match_time` to reconcile related transactions
back to a single logical trade.
</Note>
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
// Multiple orders
const batch = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.clob_types import OrderScoringParams, OrdersScoringParams
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
batch = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
```
</CodeGroup>
***
## Next Steps
<CardGroup cols={2}>
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
<Card title="Fees" icon="receipt" href="/trading/fees">
Understand fee structures and maker rebates
</Card>
</CardGroup>
+429 -62
View File
@@ -2,95 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Check Order Reward Scoring
# Overview
> Check if an order is eligble or scoring for Rewards purposes
> Order types, tick sizes, and querying orders
<Tip> This endpoint requires a L2 Header. </Tip>
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
Returns a boolean value where it is indicated if an order is scoring or not.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
**HTTP REQUEST**
<Info>
If you prefer to use the REST API directly, you'll need to manage order
signing yourself. See [Authentication](/api-reference/authentication) for details on
constructing the required headers.
</Info>
`GET /<clob-endpoint>/order-scoring?order_id={...}`
***
### Request Parameters
## Order Types
| Name | Required | Type | Description |
| ------- | -------- | ------ | ------------------------------------ |
| orderId | yes | string | id of order to get information about |
| Type | Behavior | Use Case |
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
### Response Format
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
| Name | Type | Description |
| ---- | ------------- | ------------------ |
| null | OrdersScoring | order scoring data |
<Note>
**GTD expiration**: There is a security threshold of one minute. If you need
the order to expire in 90 seconds, the correct expiration value is `now + 1
minute + 30 seconds`.
</Note>
An `OrdersScoring` object is of the form:
### Post-Only Orders
| Name | Type | Description |
| ------- | ------- | ---------------------------------------- |
| scoring | boolean | indicates if the order is scoring or not |
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
# Check if some orders are scoring
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
* Post-only can only be used with **GTC** and **GTD** order types.
> This endpoint requires a L2 Header.
***
Returns to a dictionary with boolean value where it is indicated if an order is scoring or not.
## Tick Sizes
**HTTP REQUEST**
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
`POST /<clob-endpoint>/orders-scoring`
| Tick Size | Price Precision | Example Prices |
| --------- | --------------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
### Request Parameters
Retrieve the tick size for a market using the SDK:
| Name | Required | Type | Description |
| -------- | -------- | --------- | ------------------------------------------ |
| orderIds | yes | string\[] | ids of the orders to get information about |
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize(tokenID);
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
### Response Format
| Name | Type | Description |
| ---- | ------------- | ------------------- |
| null | OrdersScoring | orders scoring data |
An `OrdersScoring` object is a dictionary that indicates the order by if it score.
<RequestExample>
```python Python theme={null}
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **USDC.e** allowance greater than or equal to the spending amount.
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
This allows the Exchange contract to execute settlement according to your signed order instructions.
***
## Validity Checks
Orders are continually monitored to make sure they remain valid. This includes tracking:
* Underlying balances
* Allowances
* Onchain order cancellations
<Warning>
Any maker caught intentionally abusing these checks will be blacklisted.
</Warning>
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 USDC.e in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
The max size you can place for an order is:
$$
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
$$
***
## Querying Orders
All query endpoints require [L2 authentication](/api-reference/authentication).
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.clob_types import OrderScoringParams, OrdersScoringParams
# Single order
scoring = client.is_order_scoring(
OrderScoringParams(
orderId="0x..."
)
OrderScoringParams(orderId="0x...")
)
print(scoring)
scoring = client.are_orders_scoring(
OrdersScoringParams(
orderIds=["0x..."]
)
# Multiple orders
batch_scoring = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
print(scoring)
```
</CodeGroup>
```javascript Typescript theme={null}
async function main() {
const scoring = await clobClient.isOrderScoring({
orderId: "0x...",
});
console.log(scoring);
}
***
main();
## Onchain Order Info
async function main() {
const scoring = await clobClient.areOrdersScoring({
orderIds: ["0x..."],
});
console.log(scoring);
}
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
main();
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e for outcome tokens) |
| `makerAmountFilled` | Amount of the asset given out |
| `takerAmountFilled` | Amount of the asset received |
| `fee` | Fees paid by the order maker |
```
</RequestExample>
***
## Error Messages
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
| Error | Description |
| ---------------------------------- | ------------------------------------------------------ |
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
| `INVALID_ORDER_ERROR` | System error while inserting order |
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
| `EXECUTION_ERROR` | System error while executing trade |
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
| `DELAYING_ORDER_ERROR` | System error while delaying order |
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
| `MARKET_NOT_READY` | Market is not yet accepting orders |
### Insert Statuses
When an order is successfully placed, the response includes a `status` field:
| Status | Description |
| ----------- | -------------------------------------------------------------------- |
| `matched` | Order placed and matched with a resting order |
| `live` | Order placed and resting on the book |
| `delayed` | Order is marketable but subject to a matching delay |
| `unmatched` | Order is marketable but failed to delay — placement still successful |
***
## Security
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades. Users can cancel orders onchain independently if trust issues arise.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Create Order" icon="plus" href="/trading/orders/create">
Build, sign, and submit orders
</Card>
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all orders
</Card>
</CardGroup>
+488 -189
View File
@@ -2,233 +2,532 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Place Multiple Orders (Batching)
# Create Order
> Instructions for placing multiple orders(Batch)
> Build, sign, and submit orders
<Tip> This endpoint requires a L2 Header </Tip>
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
Polymarkets CLOB supports batch orders, allowing you to place up to `15` orders in a single request. Before using this feature, make sure you're comfortable placing a single order first. You can find the documentation for that [here.](/developers/CLOB/orders/create-order)
<Info>
The SDK handles EIP-712 signing and submission for you. If you prefer the REST
API directly, see [Authentication](/api-reference/authentication) for constructing the
required headers and the [API Reference](/api-reference/introduction) for full endpoint
documentation including the raw order object fields and request/response schemas.
</Info>
**HTTP REQUEST**
***
`POST /<clob-endpoint>/orders`
## Order Types
### Request Payload Parameters
| Type | Behavior | Use Case |
| ------- | -------------------------------------------------------------------- | ------------------------------- |
| **GTC** | Good-Til-Cancelled — rests on the book until filled or cancelled | Default for limit orders |
| **GTD** | Good-Til-Date — active until a specified expiration time | Auto-expire before known events |
| **FOK** | Fill-Or-Kill — must fill immediately and entirely, or cancel | All-or-nothing market orders |
| **FAK** | Fill-And-Kill — fills what's available immediately, cancels the rest | Partial-fill market orders |
| Name | Required | Type | Description |
| --------- | -------- | ------------- | ---------------------------------------------------------------- |
| PostOrder | yes | PostOrders\[] | list of signed order objects (Signed Order + Order Type + Owner) |
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
A `PostOrder` object is the form:
***
| Name | Required | Type | Description |
| --------- | -------- | ------- | -------------------------------------------------------------------------------------------- |
| order | yes | order | See below table for details on crafting this object |
| orderType | yes | string | order type ("FOK", "GTC", "GTD", "FAK") |
| owner | yes | string | api key of order owner |
| postOnly | no | boolean | if `true`, the order will only rest on the book and not match immediately (default: `false`) |
## Limit Orders
An `order` object is the form:
The simplest way to place a limit order — create, sign, and submit in one call:
| Name | Required | Type | Description |
| ------------- | -------- | ------- | -------------------------------------------------- |
| salt | yes | integer | random salt used to create unique order |
| maker | yes | string | maker address (funder) |
| signer | yes | string | signing address |
| taker | yes | string | taker address (operator) |
| tokenId | yes | string | ERC1155 token ID of conditional token being traded |
| makerAmount | yes | string | maximum amount maker is willing to spend |
| takerAmount | yes | string | minimum amount taker will pay the maker in return |
| expiration | yes | string | unix expiration timestamp |
| nonce | yes | string | maker's exchange nonce of the order is associated |
| feeRateBps | yes | string | fee rate basis points as required by the operator |
| side | yes | string | buy or sell enum index |
| signatureType | yes | integer | signature type enum index |
| signature | yes | string | hex encoded signature |
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
### Order types
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false,
},
OrderType.GTC,
);
* **FOK**: A Fill-Or-Kill order is an market order to buy (in dollars) or sell (in shares) shares that must be executed immediately in its entirety; otherwise, the entire order will be cancelled.
* **FAK**: A Fill-And-Kill order is a market order to buy (in dollars) or sell (in shares) that will be executed immediately for as many shares as are available; any portion not filled at once is cancelled.
* **GTC**: A Good-Til-Cancelled order is a limit order that is active until it is fulfilled or cancelled.
* **GTD**: A Good-Til-Date order is a type of order that is active until its specified date (UTC seconds timestamp), unless it has already been fulfilled or cancelled. There is a security threshold of one minute. If the order needs to expire in 90 seconds the correct expiration value is: now + 1 minute + 30 seconds
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
### Response Format
| Name | Type | Description |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | boolean indicating if server-side err (`success = false`) -> server-side error |
| errorMsg | string | error message in case of unsuccessful placement (in case `success = false`, e.g. `client-side error`, the reason is in `errorMsg`) |
| orderId | string | id of order |
| orderHashes | string\[] | hash of settlement transaction order was marketable and triggered a match |
### Insert Error Messages
If the `errorMsg` field of the response object from placement is not an empty string, the order was not able to be immediately placed. This might be because of a delay or because of a failure. If the `success` is not `true`, then there was an issue placing the order. The following `errorMessages` are possible:
#### Error
| Error | Success | Message | Description |
| ------------------------------------ | ------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| INVALID\_ORDER\_MIN\_TICK\_SIZE | yes | order is invalid. Price breaks minimum tick size rules | order price isn't accurate to correct tick sizing |
| INVALID\_ORDER\_MIN\_SIZE | yes | order is invalid. Size lower than the minimum | order size must meet min size threshold requirement |
| INVALID\_ORDER\_DUPLICATED | yes | order is invalid. Duplicated. Same order has already been placed, can't be placed again | |
| INVALID\_ORDER\_NOT\_ENOUGH\_BALANCE | yes | not enough balance / allowance | funder address doesn't have sufficient balance or allowance for order |
| INVALID\_ORDER\_EXPIRATION | yes | invalid expiration | expiration field expresses a time before now |
| INVALID\_ORDER\_ERROR | yes | could not insert order | system error while inserting order |
| INVALID\_POST\_ONLY\_ORDER\_TYPE | yes | invalid post-only order: only GTC and GTD order types are allowed | post only flag attached to a market order |
| INVALID\_POST\_ONLY\_ORDER | yes | invalid post-only order: order crosses book | post only order would match |
| EXECUTION\_ERROR | yes | could not run the execution | system error while attempting to execute trade |
| ORDER\_DELAYED | no | order match delayed due to market conditions | order placement delayed |
| DELAYING\_ORDER\_ERROR | yes | error delaying the order | system error while delaying order |
| FOK\_ORDER\_NOT\_FILLED\_ERROR | yes | order couldn't be fully filled, FOK orders are fully filled/killed | FOK order not fully filled so can't be placed |
| MARKET\_NOT\_READY | no | the market is not yet ready to process new orders | system not accepting orders for market yet |
### Insert Statuses
When placing an order, a status field is included. The status field provides additional information regarding the order's state as a result of the placement. Possible values include:
#### Status
| Status | Description |
| --------- | ------------------------------------------------------------ |
| matched | order placed and matched with an existing resting order |
| live | order placed and resting on the book |
| delayed | order marketable, but subject to matching delay |
| unmatched | order marketable, but failure delaying, placement successful |
<RequestExample>
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType, PostOrdersArgs
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTC
)
host: str = "https://clob.polymarket.com"
key: str = "" ##This is your Private Key. Export from https://reveal.magic.link/polymarket or from your Web3 Application
chain_id: int = 137 #No need to adjust this
POLYMARKET_PROXY_ADDRESS: str = '' #This is the address listed below your profile picture when using the Polymarket site.
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
</CodeGroup>
#Select from the following 3 initialization options to matches your login method, and remove any unused lines so only one client is initialized.
### Two-Step: Sign Then Submit
For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic:
### Initialization of a client using a Polymarket Proxy associated with an Email/Magic account. If you login with your email use this example.
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=1, funder=POLYMARKET_PROXY_ADDRESS)
<CodeGroup>
```typescript TypeScript theme={null}
// Step 1: Create and sign locally
const signedOrder = await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{ tickSize: "0.01", negRisk: false },
);
### Initialization of a client using a Polymarket Proxy associated with a Browser Wallet(Metamask, Coinbase Wallet, etc)
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=2, funder=POLYMARKET_PROXY_ADDRESS)
// Step 2: Submit to the CLOB
const response = await client.postOrder(signedOrder, OrderType.GTC);
```
### Initialization of a client that trades directly from an EOA.
client = ClobClient(host, key=key, chain_id=chain_id)
```python Python theme={null}
# Step 1: Create and sign locally
signed_order = client.create_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
}
)
## Create and sign a limit order buying 100 YES tokens for 0.50c each
#Refer to the Markets API documentation to locate a tokenID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets
# Step 2: Submit to the CLOB
response = client.post_order(signed_order, OrderType.GTC)
```
</CodeGroup>
client.set_api_creds(client.create_or_derive_api_creds())
***
resp = client.post_orders([
## GTD Orders (Expiring)
GTD orders auto-expire at a specified time. Useful for quoting around known events.
<CodeGroup>
```typescript TypeScript theme={null}
// Expire in 1 hour (+ 60s security threshold buffer)
const expiration = Math.floor(Date.now() / 1000) + 60 + 3600;
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
expiration,
},
{ tickSize: "0.01", negRisk: false },
OrderType.GTD,
);
```
```python Python theme={null}
import time
# Expire in 1 hour (+ 60s security threshold buffer)
expiration = int(time.time()) + 60 + 3600
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
expiration=expiration,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTD
)
```
</CodeGroup>
<Note>
There is a security threshold of one minute on GTD expiration. To set an
effective lifetime of N seconds, use `now + 60 + N`. For example, for a
30-second effective lifetime, set the expiration to `now + 60 + 30`.
</Note>
***
## Market Orders
Market orders execute immediately against resting liquidity using FOK or FAK types:
<CodeGroup>
```typescript TypeScript theme={null}
import { Side, OrderType } from "@polymarket/clob-client";
// FOK BUY: spend exactly $100 or cancel entirely
const buyOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
amount: 100, // dollar amount
price: 0.5, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(buyOrder, OrderType.FOK);
// FOK SELL: sell exactly 200 shares or cancel entirely
const sellOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.SELL,
amount: 200, // number of shares
price: 0.45, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(sellOrder, OrderType.FOK);
```
```python Python theme={null}
from py_clob_client.order_builder.constants import BUY, SELL
from py_clob_client.clob_types import OrderType
# FOK BUY: spend exactly $100 or cancel entirely
buy_order = client.create_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100, # dollar amount
price=0.50, # worst-price limit (slippage protection)
options={"tick_size": "0.01", "neg_risk": False},
)
client.post_order(buy_order, OrderType.FOK)
# FOK SELL: sell exactly 200 shares or cancel entirely
sell_order = client.create_market_order(
token_id="TOKEN_ID",
side=SELL,
amount=200, # number of shares
price=0.45, # worst-price limit (slippage protection)
options={"tick_size": "0.01", "neg_risk": False},
)
client.post_order(sell_order, OrderType.FOK)
```
</CodeGroup>
* **FOK** — fill entirely or cancel the whole order
* **FAK** — fill what's available, cancel the rest
The `price` field on market orders acts as a **worst-price limit** (slippage protection), not a target execution price.
### One-Step Market Order
For convenience, `createAndPostMarketOrder` handles creation, signing, and submission in one call:
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
amount: 100,
price: 0.5,
},
{ tickSize: "0.01", negRisk: false },
OrderType.FOK,
);
```
```python Python theme={null}
response = client.create_and_post_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100,
price=0.50,
options={"tick_size": "0.01", "neg_risk": False},
order_type=OrderType.FOK,
)
```
</CodeGroup>
***
## Post-Only Orders
Post-only orders guarantee you're always the maker. If the order would match immediately (cross the spread), it's rejected instead of executed.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.postOrder(signedOrder, OrderType.GTC, true);
```
```python Python theme={null}
response = client.post_order(signed_order, OrderType.GTC, post_only=True)
```
</CodeGroup>
* Only works with **GTC** and **GTD** order types
* Rejected if combined with FOK or FAK
***
## Batch Orders
Place up to **15 orders** in a single request:
<CodeGroup>
```typescript TypeScript theme={null}
import { OrderType, Side, PostOrdersArgs } from "@polymarket/clob-client";
const orders: PostOrdersArgs[] = [
{
order: await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.48,
side: Side.BUY,
size: 500,
},
{ tickSize: "0.01", negRisk: false },
),
orderType: OrderType.GTC,
},
{
order: await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.52,
side: Side.SELL,
size: 500,
},
{ tickSize: "0.01", negRisk: false },
),
orderType: OrderType.GTC,
},
];
const response = await client.postOrders(orders);
```
```python Python theme={null}
from py_clob_client.clob_types import OrderArgs, OrderType, PostOrdersArgs
from py_clob_client.order_builder.constants import BUY, SELL
response = client.post_orders([
PostOrdersArgs(
# Create and sign a limit order buying 100 YES tokens for 0.50 each
order=client.create_order(OrderArgs(
price=0.01,
size=5,
price=0.48,
size=500,
side=BUY,
token_id="88613172803544318200496156596909968959424174365708473463931555296257475886634",
)),
orderType=OrderType.GTC, # Good 'Til Cancelled
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
PostOrdersArgs(
# Create and sign a limit order selling 200 NO tokens for 0.25 each
order=client.create_order(OrderArgs(
price=0.01,
size=5,
side=BUY,
token_id="93025177978745967226369398316375153283719303181694312089956059680730874301533",
)),
orderType=OrderType.GTC, # Good 'Til Cancelled
)
price=0.52,
size=500,
side=SELL,
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
])
print(resp)
print("Done!")
```
</CodeGroup>
***
## Order Options
Every order requires two market-specific options: `tickSize` and `negRisk`. For details on signature types (`0` = EOA, `1` = POLY\_PROXY, `2` = GNOSIS\_SAFE), see [Authentication](/api-reference/authentication#signature-types-and-funder).
### Tick Sizes
Your order price must conform to the market's tick size, or the order is rejected.
| Tick Size | Precision | Example Prices |
| --------- | ---------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize("TOKEN_ID");
```
```javascript typescript theme={null}
import { ethers } from "ethers";
import { config as dotenvConfig } from "dotenv";
import { resolve } from "path";
import { ApiKeyCreds, Chain, ClobClient, OrderType, PostOrdersArgs, Side } from "../src";
```python Python theme={null}
tick_size = client.get_tick_size("TOKEN_ID")
```
</CodeGroup>
dotenvConfig({ path: resolve(__dirname, "../.env") });
### Negative Risk
async function main() {
const wallet = new ethers.Wallet(`${process.env.PK}`);
const chainId = parseInt(`${process.env.CHAIN_ID || Chain.AMOY}`) as Chain;
console.log(`Address: ${await wallet.getAddress()}, chainId: ${chainId}`);
Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets.
const host = process.env.CLOB_API_URL || "https://clob.polymarket.com";
const creds: ApiKeyCreds = {
key: `${process.env.CLOB_API_KEY}`,
secret: `${process.env.CLOB_SECRET}`,
passphrase: `${process.env.CLOB_PASS_PHRASE}`,
};
const clobClient = new ClobClient(host, chainId, wallet, creds);
await clobClient.cancelAll();
const YES = "71321045679252212594626385532706912750332728571942532289631379312455583992563";
const orders: PostOrdersArgs[] = [
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.4,
side: Side.BUY,
size: 100,
}),
orderType: OrderType.GTC,
},
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.45,
side: Side.BUY,
size: 100,
}),
orderType: OrderType.GTC,
},
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.55,
side: Side.SELL,
size: 100,
}),
orderType: OrderType.GTC,
},
{
order: await clobClient.createOrder({
tokenID: YES,
price: 0.6,
side: Side.SELL,
size: 100,
}),
orderType: OrderType.GTC,
},
];
// Send it to the server
const resp = await clobClient.postOrders(orders);
console.log(resp);
}
main();
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk("TOKEN_ID");
```
```REQUEST Example Payload theme={null}
[
{'order': {'salt': 660377097, 'maker': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'signer': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'taker': '0x0000000000000000000000000000000000000000', 'tokenId': '88613172803544318200496156596909968959424174365708473463931555296257475886634', 'makerAmount': '50000', 'takerAmount': '5000000', 'expiration': '0', 'nonce': '0', 'feeRateBps': '0', 'side': 'BUY', 'signatureType': 0, 'signature': '0xccb8d1298d698ebc0859e6a26044c848ac4a4b0e20a391a4574e42b9c9bf237e5fa09fc00743e3e2d2f8e909a21d60f276ce083cc35c6661410b892f5bcbe2291c'}, 'owner': 'PRIVATEKEY', 'orderType': 'GTC'},
{'order': {'salt': 1207111323, 'maker': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'signer': '0x17A9568474b5fc84B1D1C44f081A0a3aDE750B2b', 'taker': '0x0000000000000000000000000000000000000000', 'tokenId': '93025177978745967226369398316375153283719303181694312089956059680730874301533', 'makerAmount': '50000', 'takerAmount': '5000000', 'expiration': '0', 'nonce': '0', 'feeRateBps': '0', 'side': 'BUY', 'signatureType': 0, 'signature': '0x0feca28666283824c27d7bead0bc441dde6df20dd71ef5ff7c84d3d1d5bf8aa4296fa382769dc11a92abe05b6f731d6c32556e9b4fb29e6eb50131af23a9ac941c'}, 'owner': 'PRIVATEKEY', 'orderType': 'GTC'}
]
```python Python theme={null}
is_neg_risk = client.get_neg_risk("TOKEN_ID")
```
</RequestExample>
</CodeGroup>
<Tip>
Both values are also available on the market object: `minimum_tick_size` and
`neg_risk`.
</Tip>
***
## Prerequisites
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **BUY orders**: USDC.e allowance >= spending amount
* **SELL orders**: conditional token allowance >= selling amount
Order size is limited by your available balance minus amounts reserved by existing open orders:
$$
\text{maxOrderSize} = \text{balance} - \sum(\text{openOrderSize} - \text{filledAmount})
$$
<Warning>
Orders are continuously monitored for validity — balances, allowances, and
onchain cancellations are tracked in real time. Any maker caught intentionally
abusing these checks will be blacklisted.
</Warning>
### Advanced Parameters
These optional fields can be passed in the `UserOrder` object for fine-grained control:
| Parameter | Type | Description |
| ------------ | ------ | ----------------------------------------------- |
| `feeRateBps` | number | Fee rate in basis points (default: market rate) |
| `nonce` | number | Custom nonce for order uniqueness |
| `taker` | string | Restrict the order to a specific taker address |
### Sports Markets
Sports markets have additional behaviors:
* Outstanding limit orders are **automatically cancelled** once the game begins, clearing the entire order book at the official start time
* Marketable orders have a **3-second placement delay** before matching
* Game start times can shift — monitor your orders closely, as they may not be cleared if the start time changes unexpectedly
***
## Response
A successful order placement returns:
```json theme={null}
{
"success": true,
"errorMsg": "",
"orderID": "0xabc123...",
"takingAmount": "",
"makingAmount": "",
"status": "live",
"transactionsHashes": [],
"tradeIDs": []
}
```
### Statuses
| Status | Description |
| ----------- | ----------------------------------------------------------- |
| `live` | Order resting on the book |
| `matched` | Order matched immediately with a resting order |
| `delayed` | Marketable order subject to a matching delay |
| `unmatched` | Marketable but failed to delay — placement still successful |
### Error Messages
| Error | Description |
| ---------------------------------- | ----------------------------------------------- |
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
| `INVALID_ORDER_MIN_SIZE` | Order size below the minimum threshold |
| `INVALID_ORDER_DUPLICATED` | Identical order already placed |
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Insufficient balance or allowance |
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only used with FOK/FAK |
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
| `INVALID_ORDER_ERROR` | System error inserting the order |
| `EXECUTION_ERROR` | System error executing the trade |
| `ORDER_DELAYED` | Order match delayed due to market conditions |
| `DELAYING_ORDER_ERROR` | System error while delaying the order |
| `MARKET_NOT_READY` | Market not yet accepting orders |
***
## Heartbeat
The heartbeat endpoint maintains session liveness. If a valid heartbeat is not received within **10 seconds** (with a 5-second buffer), **all open orders are cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
</CodeGroup>
* Include the most recent `heartbeat_id` in each request. Use an empty string for the first request.
* If you send an expired ID, the server responds with `400` and the correct ID. Update and retry.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Cancel Orders" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all open orders
</Card>
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
</CardGroup>
+495 -226
View File
@@ -2,263 +2,532 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Place Single Order
# Create Order
> Detailed instructions for creating, placing, and managing orders using Polymarket's CLOB API.
> Build, sign, and submit orders
# Create and Place an Order
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
<Tip> This endpoint requires a L2 Header </Tip>
<Info>
The SDK handles EIP-712 signing and submission for you. If you prefer the REST
API directly, see [Authentication](/api-reference/authentication) for constructing the
required headers and the [API Reference](/api-reference/introduction) for full endpoint
documentation including the raw order object fields and request/response schemas.
</Info>
Create and place an order using the Polymarket CLOB API clients. All orders are represented as "limit" orders, but "market" orders are also supported. To place a market order, simply ensure your price is marketable against current resting limit orders, which are executed on input at the best price.
***
**HTTP REQUEST**
## Order Types
`POST /<clob-endpoint>/order`
| Type | Behavior | Use Case |
| ------- | -------------------------------------------------------------------- | ------------------------------- |
| **GTC** | Good-Til-Cancelled — rests on the book until filled or cancelled | Default for limit orders |
| **GTD** | Good-Til-Date — active until a specified expiration time | Auto-expire before known events |
| **FOK** | Fill-Or-Kill — must fill immediately and entirely, or cancel | All-or-nothing market orders |
| **FAK** | Fill-And-Kill — fills what's available immediately, cancels the rest | Partial-fill market orders |
### Request Payload Parameters
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
| Name | Required | Type | Description |
| --------- | -------- | ------- | -------------------------------------------------------------------------------------------- |
| order | yes | Order | signed object |
| owner | yes | string | api key of order owner |
| orderType | yes | string | order type ("FOK", "GTC", "GTD") |
| postOnly | no | boolean | if `true`, the order will only rest on the book and not match immediately (default: `false`) |
***
### Post-only orders
## Limit Orders
* postOnly submits a limit order that will not match resting liquidity upon entry.
* If a postOnly order would cross the spread (i.e., it is marketable), it will be rejected rather than executed.
* postOnly cannot be combined with market order types (e.g., FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
The simplest way to place a limit order — create, sign, and submit in one call:
An `order` object is the form:
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
| Name | Required | Type | Description |
| ------------- | -------- | ------- | -------------------------------------------------- |
| salt | yes | integer | random salt used to create unique order |
| maker | yes | string | maker address (funder) |
| signer | yes | string | signing address |
| taker | yes | string | taker address (operator) |
| tokenId | yes | string | ERC1155 token ID of conditional token being traded |
| makerAmount | yes | string | maximum amount maker is willing to spend |
| takerAmount | yes | string | minimum amount taker will pay the maker in return |
| expiration | yes | string | unix expiration timestamp |
| nonce | yes | string | maker's exchange nonce of the order is associated |
| feeRateBps | yes | string | fee rate basis points as required by the operator |
| side | yes | string | buy or sell enum index |
| signatureType | yes | integer | signature type enum index |
| signature | yes | string | hex encoded signature |
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false,
},
OrderType.GTC,
);
### Order types
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
* **FOK**: A Fill-Or-Kill order is an market order to buy (in dollars) or sell (in shares) shares that must be executed immediately in its entirety; otherwise, the entire order will be cancelled.
* **FAK**: A Fill-And-Kill order is a market order to buy (in dollars) or sell (in shares) that will be executed immediately for as many shares as are available; any portion not filled at once is cancelled.
* **GTC**: A Good-Til-Cancelled order is a limit order that is active until it is fulfilled or cancelled.
* **GTD**: A Good-Til-Date order is a type of order that is active until its specified date (UTC seconds timestamp), unless it has already been fulfilled or cancelled. There is a security threshold of one minute. If the order needs to expire in 90 seconds the correct expiration value is: now + 1 minute + 30 seconds
### Response Format
| Name | Type | Description |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| success | boolean | boolean indicating if server-side err (`success = false`) -> server-side error |
| errorMsg | string | error message in case of unsuccessful placement (in case `success = false`, e.g. `client-side error`, the reason is in `errorMsg`) |
| orderId | string | id of order |
| orderHashes | string\[] | hash of settlement transaction order was marketable and triggered a match |
### Insert Error Messages
If the `errorMsg` field of the response object from placement is not an empty string, the order was not able to be immediately placed. This might be because of a delay or because of a failure. If the `success` is not `true`, then there was an issue placing the order. The following `errorMessages` are possible:
#### Error
| Error | Success | Message | Description |
| ------------------------------------ | ------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| INVALID\_ORDER\_MIN\_TICK\_SIZE | yes | order is invalid. Price breaks minimum tick size rules | order price isn't accurate to correct tick sizing |
| INVALID\_ORDER\_MIN\_SIZE | yes | order is invalid. Size lower than the minimum | order size must meet min size threshold requirement |
| INVALID\_ORDER\_DUPLICATED | yes | order is invalid. Duplicated. Same order has already been placed, can't be placed again | |
| INVALID\_ORDER\_NOT\_ENOUGH\_BALANCE | yes | not enough balance / allowance | funder address doesn't have sufficient balance or allowance for order |
| INVALID\_ORDER\_EXPIRATION | yes | invalid expiration | expiration field expresses a time before now |
| INVALID\_ORDER\_ERROR | yes | could not insert order | system error while inserting order |
| INVALID\_POST\_ONLY\_ORDER\_TYPE | yes | invalid post-only order: only GTC and GTD order types are allowed | post only flag attached to a market order |
| INVALID\_POST\_ONLY\_ORDER | yes | invalid post-only order: order crosses book | post only order would match |
| EXECUTION\_ERROR | yes | could not run the execution | system error while attempting to execute trade |
| ORDER\_DELAYED | no | order match delayed due to market conditions | order placement delayed |
| DELAYING\_ORDER\_ERROR | yes | error delaying the order | system error while delaying order |
| FOK\_ORDER\_NOT\_FILLED\_ERROR | yes | order couldn't be fully filled, FOK orders are fully filled/killed | FOK order not fully filled so can't be placed |
| MARKET\_NOT\_READY | no | the market is not yet ready to process new orders | system not accepting orders for market yet |
### Insert Statuses
When placing an order, a status field is included. The status field provides additional information regarding the order's state as a result of the placement. Possible values include:
#### Status
| Status | Description |
| --------- | ------------------------------------------------------------ |
| matched | order placed and matched with an existing resting order |
| live | order placed and resting on the book |
| delayed | order marketable, but subject to matching delay |
| unmatched | order marketable, but failure delaying, placement successful |
<RequestExample>
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY
host: str = "https://clob.polymarket.com"
key: str = "" #This is your Private Key. Export from reveal.polymarket.com or from your Web3 Application
chain_id: int = 137 #No need to adjust this
POLYMARKET_PROXY_ADDRESS: str = '' #This is the address you deposit/send USDC to to FUND your Polymarket account.
#Select from the following 3 initialization options to matches your login method, and remove any unused lines so only one client is initialized.
### Initialization of a client using a Polymarket Proxy associated with an Email/Magic account. If you login with your email use this example.
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=1, funder=POLYMARKET_PROXY_ADDRESS)
### Initialization of a client using a Polymarket Proxy associated with a Browser Wallet(Metamask, Coinbase Wallet, etc)
client = ClobClient(host, key=key, chain_id=chain_id, signature_type=2, funder=POLYMARKET_PROXY_ADDRESS)
### Initialization of a client that trades directly from an EOA.
client = ClobClient(host, key=key, chain_id=chain_id)
## Create and sign a limit order buying 100 YES tokens for 0.50c each
#Refer to the Markets API documentation to locate a tokenID: https://docs.polymarket.com/developers/gamma-markets-api/get-markets
client.set_api_creds(client.create_or_derive_api_creds())
order_args = OrderArgs(
price=0.01,
size=5.0,
side=BUY,
token_id="", #Token ID you want to purchase goes here.
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTC
)
signed_order = client.create_order(order_args)
## GTC(Good-Till-Cancelled) Order
resp = client.post_order(signed_order, OrderType.GTC)
print(resp)
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
</CodeGroup>
### Two-Step: Sign Then Submit
For more control, you can separate signing from submission. This is useful for batch orders or custom submission logic:
<CodeGroup>
```typescript TypeScript theme={null}
// Step 1: Create and sign locally
const signedOrder = await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{ tickSize: "0.01", negRisk: false },
);
// Step 2: Submit to the CLOB
const response = await client.postOrder(signedOrder, OrderType.GTC);
```
```javascript typescript theme={null}
// GTC Order example
//
import { Side, OrderType } from "@polymarket/clob-client";
```python Python theme={null}
# Step 1: Create and sign locally
signed_order = client.create_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False,
}
)
async function main() {
// Create a buy order for 100 YES for 0.50c
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
const order = await clobClient.createOrder({
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
# Step 2: Submit to the CLOB
response = client.post_order(signed_order, OrderType.GTC)
```
</CodeGroup>
***
## GTD Orders (Expiring)
GTD orders auto-expire at a specified time. Useful for quoting around known events.
<CodeGroup>
```typescript TypeScript theme={null}
// Expire in 1 hour (+ 60s security threshold buffer)
const expiration = Math.floor(Date.now() / 1000) + 60 + 3600;
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
size: 100,
feeRateBps: 0,
nonce: 1,
});
console.log("Created Order", order);
expiration,
},
{ tickSize: "0.01", negRisk: false },
OrderType.GTD,
);
```
// Send it to the server
```python Python theme={null}
import time
// GTC Order
const resp = await clobClient.postOrder(order, OrderType.GTC);
console.log(resp);
}
# Expire in 1 hour (+ 60s security threshold buffer)
expiration = int(time.time()) + 60 + 3600
main();
// GTD Order example
//
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
expiration=expiration,
),
options={
"tick_size": "0.01",
"neg_risk": False,
},
order_type=OrderType.GTD
)
```
</CodeGroup>
<Note>
There is a security threshold of one minute on GTD expiration. To set an
effective lifetime of N seconds, use `now + 60 + N`. For example, for a
30-second effective lifetime, set the expiration to `now + 60 + 30`.
</Note>
***
## Market Orders
Market orders execute immediately against resting liquidity using FOK or FAK types:
<CodeGroup>
```typescript TypeScript theme={null}
import { Side, OrderType } from "@polymarket/clob-client";
async function main() {
// Create a buy order for 100 YES for 0.50c that expires in 1 minute
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
// There is a 1 minute of security threshold for the expiration field.
// If we need the order to expire in 30 seconds the correct expiration value is:
// now + 1 miute + 30 seconds
const oneMinute = 60 * 1000;
const seconds = 30 * 1000;
const expiration = parseInt(
((new Date().getTime() + oneMinute + seconds) / 1000).toString()
);
const order = await clobClient.createOrder({
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
price: 0.5,
// FOK BUY: spend exactly $100 or cancel entirely
const buyOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
size: 100,
feeRateBps: 0,
nonce: 1,
// There is a 1 minute of security threshold for the expiration field.
// If we need the order to expire in 30 seconds the correct expiration value is:
// now + 1 miute + 30 seconds
expiration: expiration,
});
console.log("Created Order", order);
amount: 100, // dollar amount
price: 0.5, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(buyOrder, OrderType.FOK);
// Send it to the server
// GTD Order
const resp = await clobClient.postOrder(order, OrderType.GTD);
console.log(resp);
}
main();
// FOK BUY Order example
//
import { Side, OrderType } from "@polymarket/clob-client";
async function main() {
// Create a market buy order for $100
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
const marketOrder = await clobClient.createMarketOrder({
side: Side.BUY,
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
amount: 100, // $$$
feeRateBps: 0,
nonce: 0,
price: 0.5,
});
console.log("Created Order", order);
// Send it to the server
// FOK Order
const resp = await clobClient.postOrder(order, OrderType.FOK);
console.log(resp);
}
main();
// FOK SELL Order example
//
import { Side, OrderType } from "@polymarket/clob-client";
async function main() {
// Create a market sell order for 100 shares
// YES: 71321045679252212594626385532706912750332728571942532289631379312455583992563
const marketOrder = await clobClient.createMarketOrder({
// FOK SELL: sell exactly 200 shares or cancel entirely
const sellOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.SELL,
tokenID:
"71321045679252212594626385532706912750332728571942532289631379312455583992563",
amount: 100, // shares
feeRateBps: 0,
nonce: 0,
price: 0.5,
});
console.log("Created Order", order);
// Send it to the server
// FOK Order
const resp = await clobClient.postOrder(order, OrderType.FOK);
console.log(resp);
}
main();
amount: 200, // number of shares
price: 0.45, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(sellOrder, OrderType.FOK);
```
</RequestExample>
```python Python theme={null}
from py_clob_client.order_builder.constants import BUY, SELL
from py_clob_client.clob_types import OrderType
# FOK BUY: spend exactly $100 or cancel entirely
buy_order = client.create_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100, # dollar amount
price=0.50, # worst-price limit (slippage protection)
options={"tick_size": "0.01", "neg_risk": False},
)
client.post_order(buy_order, OrderType.FOK)
# FOK SELL: sell exactly 200 shares or cancel entirely
sell_order = client.create_market_order(
token_id="TOKEN_ID",
side=SELL,
amount=200, # number of shares
price=0.45, # worst-price limit (slippage protection)
options={"tick_size": "0.01", "neg_risk": False},
)
client.post_order(sell_order, OrderType.FOK)
```
</CodeGroup>
* **FOK** — fill entirely or cancel the whole order
* **FAK** — fill what's available, cancel the rest
The `price` field on market orders acts as a **worst-price limit** (slippage protection), not a target execution price.
### One-Step Market Order
For convenience, `createAndPostMarketOrder` handles creation, signing, and submission in one call:
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
amount: 100,
price: 0.5,
},
{ tickSize: "0.01", negRisk: false },
OrderType.FOK,
);
```
```python Python theme={null}
response = client.create_and_post_market_order(
token_id="TOKEN_ID",
side=BUY,
amount=100,
price=0.50,
options={"tick_size": "0.01", "neg_risk": False},
order_type=OrderType.FOK,
)
```
</CodeGroup>
***
## Post-Only Orders
Post-only orders guarantee you're always the maker. If the order would match immediately (cross the spread), it's rejected instead of executed.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.postOrder(signedOrder, OrderType.GTC, true);
```
```python Python theme={null}
response = client.post_order(signed_order, OrderType.GTC, post_only=True)
```
</CodeGroup>
* Only works with **GTC** and **GTD** order types
* Rejected if combined with FOK or FAK
***
## Batch Orders
Place up to **15 orders** in a single request:
<CodeGroup>
```typescript TypeScript theme={null}
import { OrderType, Side, PostOrdersArgs } from "@polymarket/clob-client";
const orders: PostOrdersArgs[] = [
{
order: await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.48,
side: Side.BUY,
size: 500,
},
{ tickSize: "0.01", negRisk: false },
),
orderType: OrderType.GTC,
},
{
order: await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.52,
side: Side.SELL,
size: 500,
},
{ tickSize: "0.01", negRisk: false },
),
orderType: OrderType.GTC,
},
];
const response = await client.postOrders(orders);
```
```python Python theme={null}
from py_clob_client.clob_types import OrderArgs, OrderType, PostOrdersArgs
from py_clob_client.order_builder.constants import BUY, SELL
response = client.post_orders([
PostOrdersArgs(
order=client.create_order(OrderArgs(
price=0.48,
size=500,
side=BUY,
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
PostOrdersArgs(
order=client.create_order(OrderArgs(
price=0.52,
size=500,
side=SELL,
token_id="TOKEN_ID",
), options={"tick_size": "0.01", "neg_risk": False}),
orderType=OrderType.GTC,
),
])
```
</CodeGroup>
***
## Order Options
Every order requires two market-specific options: `tickSize` and `negRisk`. For details on signature types (`0` = EOA, `1` = POLY\_PROXY, `2` = GNOSIS\_SAFE), see [Authentication](/api-reference/authentication#signature-types-and-funder).
### Tick Sizes
Your order price must conform to the market's tick size, or the order is rejected.
| Tick Size | Precision | Example Prices |
| --------- | ---------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize("TOKEN_ID");
```
```python Python theme={null}
tick_size = client.get_tick_size("TOKEN_ID")
```
</CodeGroup>
### Negative Risk
Multi-outcome events (3+ outcomes) use the Neg Risk CTF Exchange. Pass `negRisk: true` for these markets.
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk("TOKEN_ID");
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk("TOKEN_ID")
```
</CodeGroup>
<Tip>
Both values are also available on the market object: `minimum_tick_size` and
`neg_risk`.
</Tip>
***
## Prerequisites
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **BUY orders**: USDC.e allowance >= spending amount
* **SELL orders**: conditional token allowance >= selling amount
Order size is limited by your available balance minus amounts reserved by existing open orders:
$$
\text{maxOrderSize} = \text{balance} - \sum(\text{openOrderSize} - \text{filledAmount})
$$
<Warning>
Orders are continuously monitored for validity — balances, allowances, and
onchain cancellations are tracked in real time. Any maker caught intentionally
abusing these checks will be blacklisted.
</Warning>
### Advanced Parameters
These optional fields can be passed in the `UserOrder` object for fine-grained control:
| Parameter | Type | Description |
| ------------ | ------ | ----------------------------------------------- |
| `feeRateBps` | number | Fee rate in basis points (default: market rate) |
| `nonce` | number | Custom nonce for order uniqueness |
| `taker` | string | Restrict the order to a specific taker address |
### Sports Markets
Sports markets have additional behaviors:
* Outstanding limit orders are **automatically cancelled** once the game begins, clearing the entire order book at the official start time
* Marketable orders have a **3-second placement delay** before matching
* Game start times can shift — monitor your orders closely, as they may not be cleared if the start time changes unexpectedly
***
## Response
A successful order placement returns:
```json theme={null}
{
"success": true,
"errorMsg": "",
"orderID": "0xabc123...",
"takingAmount": "",
"makingAmount": "",
"status": "live",
"transactionsHashes": [],
"tradeIDs": []
}
```
### Statuses
| Status | Description |
| ----------- | ----------------------------------------------------------- |
| `live` | Order resting on the book |
| `matched` | Order matched immediately with a resting order |
| `delayed` | Marketable order subject to a matching delay |
| `unmatched` | Marketable but failed to delay — placement still successful |
### Error Messages
| Error | Description |
| ---------------------------------- | ----------------------------------------------- |
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
| `INVALID_ORDER_MIN_SIZE` | Order size below the minimum threshold |
| `INVALID_ORDER_DUPLICATED` | Identical order already placed |
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Insufficient balance or allowance |
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only used with FOK/FAK |
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
| `INVALID_ORDER_ERROR` | System error inserting the order |
| `EXECUTION_ERROR` | System error executing the trade |
| `ORDER_DELAYED` | Order match delayed due to market conditions |
| `DELAYING_ORDER_ERROR` | System error while delaying the order |
| `MARKET_NOT_READY` | Market not yet accepting orders |
***
## Heartbeat
The heartbeat endpoint maintains session liveness. If a valid heartbeat is not received within **10 seconds** (with a 5-second buffer), **all open orders are cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
</CodeGroup>
* Include the most recent `heartbeat_id` in each request. Use an empty string for the first request.
* If you send an expired ID, the server responds with `400` and the correct ID. Update and retry.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Cancel Orders" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all open orders
</Card>
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
</CardGroup>
+441 -31
View File
@@ -2,52 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Get Active Orders
# Overview
<Tip> This endpoint requires a L2 Header. </Tip>
> Order types, tick sizes, and querying orders
Get active order(s) for a specific market.
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
**HTTP REQUEST**
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
`GET /<clob-endpoint>/data/orders`
<Info>
If you prefer to use the REST API directly, you'll need to manage order
signing yourself. See [Authentication](/api-reference/authentication) for details on
constructing the required headers.
</Info>
### Request Parameters
***
| Name | Required | Type | Description |
| --------- | -------- | ------ | ------------------------------------ |
| id | no | string | id of order to get information about |
| market | no | string | condition id of market |
| asset\_id | no | string | id of the asset/token |
## Order Types
### Response Format
| Type | Behavior | Use Case |
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
| Name | Type | Description |
| ---- | ------------ | ---------------------------------------------------- |
| null | OpenOrder\[] | list of open orders filtered by the query parameters |
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
<Note>
**GTD expiration**: There is a security threshold of one minute. If you need
the order to expire in 90 seconds, the correct expiration value is `now + 1
minute + 30 seconds`.
</Note>
### Post-Only Orders
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
* Post-only can only be used with **GTC** and **GTD** order types.
***
## Tick Sizes
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
| Tick Size | Price Precision | Example Prices |
| --------- | --------------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
Retrieve the tick size for a market using the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize(tokenID);
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
```python Python theme={null}
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **USDC.e** allowance greater than or equal to the spending amount.
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
This allows the Exchange contract to execute settlement according to your signed order instructions.
***
## Validity Checks
Orders are continually monitored to make sure they remain valid. This includes tracking:
* Underlying balances
* Allowances
* Onchain order cancellations
<Warning>
Any maker caught intentionally abusing these checks will be blacklisted.
</Warning>
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 USDC.e in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
The max size you can place for an order is:
$$
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
$$
***
## Querying Orders
All query endpoints require [L2 authentication](/api-reference/authentication).
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
<RequestExample>
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
resp = client.get_orders(
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
market="0xbd31dc8a...",
)
)
print(resp)
print("Done!")
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```javascript Typescript theme={null}
async function main() {
const resp = await clobClient.getOpenOrders({
market:
"0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
});
console.log(resp);
console.log(`Done!`);
}
main();
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</RequestExample>
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.clob_types import OrderScoringParams, OrdersScoringParams
# Single order
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
# Multiple orders
batch_scoring = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e for outcome tokens) |
| `makerAmountFilled` | Amount of the asset given out |
| `takerAmountFilled` | Amount of the asset received |
| `fee` | Fees paid by the order maker |
***
## Error Messages
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
| Error | Description |
| ---------------------------------- | ------------------------------------------------------ |
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
| `INVALID_ORDER_ERROR` | System error while inserting order |
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
| `EXECUTION_ERROR` | System error while executing trade |
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
| `DELAYING_ORDER_ERROR` | System error while delaying order |
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
| `MARKET_NOT_READY` | Market is not yet accepting orders |
### Insert Statuses
When an order is successfully placed, the response includes a `status` field:
| Status | Description |
| ----------- | -------------------------------------------------------------------- |
| `matched` | Order placed and matched with a resting order |
| `live` | Order placed and resting on the book |
| `delayed` | Order is marketable but subject to a matching delay |
| `unmatched` | Order is marketable but failed to delay — placement still successful |
***
## Security
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades. Users can cancel orders onchain independently if trust issues arise.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Create Order" icon="plus" href="/trading/orders/create">
Build, sign, and submit orders
</Card>
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all orders
</Card>
</CardGroup>
+440 -43
View File
@@ -2,65 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Get Order
# Overview
> Get information about an existing order
> Order types, tick sizes, and querying orders
<Tip>This endpoint requires a L2 Header. </Tip>
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
Get single order by id.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
**HTTP REQUEST**
<Info>
If you prefer to use the REST API directly, you'll need to manage order
signing yourself. See [Authentication](/api-reference/authentication) for details on
constructing the required headers.
</Info>
`GET /<clob-endpoint>/data/order/<order_hash>`
***
### Request Parameters
## Order Types
| Name | Required | Type | Description |
| ---- | -------- | ------ | ------------------------------------ |
| id | no | string | id of order to get information about |
| Type | Behavior | Use Case |
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
### Response Format
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
| Name | Type | Description |
| ----- | --------- | ------------------ |
| order | OpenOrder | order if it exists |
<Note>
**GTD expiration**: There is a security threshold of one minute. If you need
the order to expire in 90 seconds, the correct expiration value is `now + 1
minute + 30 seconds`.
</Note>
An `OpenOrder` object is of the form:
### Post-Only Orders
| Name | Type | Description |
| ----------------- | --------- | -------------------------------------------------------------- |
| associate\_trades | string\[] | any Trade id the order has been partially included in |
| id | string | order id |
| status | string | order current status |
| market | string | market id (condition id) |
| original\_size | string | original order size at placement |
| outcome | string | human readable outcome the order is for |
| maker\_address | string | maker address (funder) |
| owner | string | api key |
| price | string | price |
| side | string | buy or sell |
| size\_matched | string | size of order that has been matched/filled |
| asset\_id | string | token id |
| expiration | string | unix timestamp when the order expired, 0 if it does not expire |
| type | string | order type (GTC, FOK, GTD) |
| created\_at | string | unix timestamp when the order was created |
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
* Post-only can only be used with **GTC** and **GTD** order types.
***
## Tick Sizes
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
| Tick Size | Price Precision | Example Prices |
| --------- | --------------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
Retrieve the tick size for a market using the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize(tokenID);
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
<RequestExample>
```python Python theme={null}
order = clob_client.get_order("0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc")
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **USDC.e** allowance greater than or equal to the spending amount.
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
This allows the Exchange contract to execute settlement according to your signed order instructions.
***
## Validity Checks
Orders are continually monitored to make sure they remain valid. This includes tracking:
* Underlying balances
* Allowances
* Onchain order cancellations
<Warning>
Any maker caught intentionally abusing these checks will be blacklisted.
</Warning>
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 USDC.e in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
The max size you can place for an order is:
$$
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
$$
***
## Querying Orders
All query endpoints require [L2 authentication](/api-reference/authentication).
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
</CodeGroup>
```javascript Typescript theme={null}
async function main() {
const order = await clobClient.getOrder(
"0xb816482a5187a3d3db49cbaf6fe3ddf24f53e6c712b5a4bf5e01d0ec7b11dabc"
);
console.log(order);
}
### Get Open Orders
main();
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
</RequestExample>
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.clob_types import OrderScoringParams, OrdersScoringParams
# Single order
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
# Multiple orders
batch_scoring = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e for outcome tokens) |
| `makerAmountFilled` | Amount of the asset given out |
| `takerAmountFilled` | Amount of the asset received |
| `fee` | Fees paid by the order maker |
***
## Error Messages
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
| Error | Description |
| ---------------------------------- | ------------------------------------------------------ |
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
| `INVALID_ORDER_ERROR` | System error while inserting order |
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
| `EXECUTION_ERROR` | System error while executing trade |
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
| `DELAYING_ORDER_ERROR` | System error while delaying order |
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
| `MARKET_NOT_READY` | Market is not yet accepting orders |
### Insert Statuses
When an order is successfully placed, the response includes a `status` field:
| Status | Description |
| ----------- | -------------------------------------------------------------------- |
| `matched` | Order placed and matched with a resting order |
| `live` | Order placed and resting on the book |
| `delayed` | Order is marketable but subject to a matching delay |
| `unmatched` | Order is marketable but failed to delay — placement still successful |
***
## Security
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades. Users can cancel orders onchain independently if trust issues arise.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Create Order" icon="plus" href="/trading/orders/create">
Build, sign, and submit orders
</Card>
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all orders
</Card>
</CardGroup>
+456 -11
View File
@@ -2,17 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Onchain Order Info
# Overview
## How do I interpret the OrderFilled onchain event?
> Order types, tick sizes, and querying orders
Given an OrderFilled event:
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
* `orderHash`: a unique hash for the Order being filled
* `maker`: the user generating the order and the source of funds for the order
* `taker`: the user filling the order OR the Exchange contract if the order fills multiple limit orders
* `makerAssetId`: id of the asset that is given out. If 0, indicates that the Order is a BUY, giving USDC in exchange for Outcome tokens. Else, indicates that the Order is a SELL, giving Outcome tokens in exchange for USDC.
* `takerAssetId`: id of the asset that is received. If 0, indicates that the Order is a SELL, receiving USDC in exchange for Outcome tokens. Else, indicates that the Order is a BUY, receiving Outcome tokens in exchange for USDC.
* `makerAmountFilled`: the amount of the asset that is given out.
* `takerAmountFilled`: the amount of the asset that is received.
* `fee`: the fees paid by the order maker
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
<Info>
If you prefer to use the REST API directly, you'll need to manage order
signing yourself. See [Authentication](/api-reference/authentication) for details on
constructing the required headers.
</Info>
***
## Order Types
| Type | Behavior | Use Case |
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
<Note>
**GTD expiration**: There is a security threshold of one minute. If you need
the order to expire in 90 seconds, the correct expiration value is `now + 1
minute + 30 seconds`.
</Note>
### Post-Only Orders
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
* Post-only can only be used with **GTC** and **GTD** order types.
***
## Tick Sizes
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
| Tick Size | Price Precision | Example Prices |
| --------- | --------------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
Retrieve the tick size for a market using the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize(tokenID);
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
```python Python theme={null}
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
</CodeGroup>
***
## Allowances
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
* **Buying**: the funder must have set a **USDC.e** allowance greater than or equal to the spending amount.
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
This allows the Exchange contract to execute settlement according to your signed order instructions.
***
## Validity Checks
Orders are continually monitored to make sure they remain valid. This includes tracking:
* Underlying balances
* Allowances
* Onchain order cancellations
<Warning>
Any maker caught intentionally abusing these checks will be blacklisted.
</Warning>
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 USDC.e in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
The max size you can place for an order is:
$$
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
$$
***
## Querying Orders
All query endpoints require [L2 authentication](/api-reference/authentication).
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.clob_types import OrderScoringParams, OrdersScoringParams
# Single order
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
# Multiple orders
batch_scoring = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e for outcome tokens) |
| `makerAmountFilled` | Amount of the asset given out |
| `takerAmountFilled` | Amount of the asset received |
| `fee` | Fees paid by the order maker |
***
## Error Messages
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
| Error | Description |
| ---------------------------------- | ------------------------------------------------------ |
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
| `INVALID_ORDER_ERROR` | System error while inserting order |
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
| `EXECUTION_ERROR` | System error while executing trade |
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
| `DELAYING_ORDER_ERROR` | System error while delaying order |
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
| `MARKET_NOT_READY` | Market is not yet accepting orders |
### Insert Statuses
When an order is successfully placed, the response includes a `status` field:
| Status | Description |
| ----------- | -------------------------------------------------------------------- |
| `matched` | Order placed and matched with a resting order |
| `live` | Order placed and resting on the book |
| `delayed` | Order is marketable but subject to a matching delay |
| `unmatched` | Order is marketable but failed to delay — placement still successful |
***
## Security
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades. Users can cancel orders onchain independently if trust issues arise.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Create Order" icon="plus" href="/trading/orders/create">
Build, sign, and submit orders
</Card>
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all orders
</Card>
</CardGroup>
+443 -13
View File
@@ -2,32 +2,462 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Orders Overview
# Overview
> Detailed instructions for creating, placing, and managing orders using Polymarket's CLOB API.
> Order types, tick sizes, and querying orders
All orders are expressed as limit orders (can be marketable). The underlying order primitive must be in the form expected and executable by the on-chain binary limit order protocol contract. Preparing such an order is quite involved (structuring, hashing, signing), thus Polymarket suggests using the open source typescript, python and golang libraries.
All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
<Info>
If you prefer to use the REST API directly, you'll need to manage order
signing yourself. See [Authentication](/api-reference/authentication) for details on
constructing the required headers.
</Info>
***
## Order Types
| Type | Behavior | Use Case |
| ---------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- |
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
<Note>
**GTD expiration**: There is a security threshold of one minute. If you need
the order to expire in 90 seconds, the correct expiration value is `now + 1
minute + 30 seconds`.
</Note>
### Post-Only Orders
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
* Post-only can only be used with **GTC** and **GTD** order types.
***
## Tick Sizes
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
| Tick Size | Price Precision | Example Prices |
| --------- | --------------- | ---------------------- |
| `0.1` | 1 decimal | 0.1, 0.2, 0.5 |
| `0.01` | 2 decimals | 0.01, 0.50, 0.99 |
| `0.001` | 3 decimals | 0.001, 0.500, 0.999 |
| `0.0001` | 4 decimals | 0.0001, 0.5000, 0.9999 |
Retrieve the tick size for a market using the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
const tickSize = await client.getTickSize(tokenID);
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
```python Python theme={null}
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
</CodeGroup>
<Tip>
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
<CodeGroup>
```typescript TypeScript theme={null}
const isNegRisk = await client.getNegRisk(tokenID);
```
```python Python theme={null}
is_neg_risk = client.get_neg_risk(token_id)
```
</CodeGroup>
***
## Allowances
To place an order, allowances must be set by the funder address for the specified `maker` asset for the Exchange contract. When buying, this means the funder must have set a USDC allowance greater than or equal to the spending amount. When selling, the funder must have set an allowance for the conditional token that is greater than or equal to the selling amount. This allows the Exchange contract to execute settlement according to the signed order instructions created by a user and matched by the operator.
Before placing an order, your funder address must have approved the Exchange contract to spend the relevant tokens:
## Signature Types
* **Buying**: the funder must have set a **USDC.e** allowance greater than or equal to the spending amount.
* **Selling**: the funder must have set a **conditional token** allowance greater than or equal to the selling amount.
Polymarkets CLOB supports 3 signature types. Orders must identify what signature type they use. The available typescript and python clients abstract the complexity of signing and preparing orders with the following signature types by allowing a funder address and signer type to be specified on initialization. The supported signature types are:
This allows the Exchange contract to execute settlement according to your signed order instructions.
| Type | ID | Description |
| ------------------ | -- | ------------------------------------------------------------------------------------------ |
| EOA | 0 | EIP712 signature signed by an EOA |
| POLY\_PROXY | 1 | EIP712 signatures signed by a signer associated with funding Polymarket proxy wallet |
| POLY\_GNOSIS\_SAFE | 2 | EIP712 signatures signed by a signer associated with funding Polymarket gnosis safe wallet |
***
## Validity Checks
Orders are continually monitored to make sure they remain valid. Specifically, this includes continually tracking underlying balances, allowances and on-chain order cancellations. Any maker that is caught intentionally abusing these checks (which are essentially real time) will be blacklisted.
Orders are continually monitored to make sure they remain valid. This includes tracking:
Additionally, there are rails on order placement in a market. Specifically, you can only place orders that sum to less than or equal to your available balance for each market. For example if you have 500 USDC in your funding wallet, you can place one order to buy 1000 YES in marketA @ \$.50, then any additional buy orders to that market will be rejected since your entire balance is reserved for the first (and only) buy order. More explicitly the max size you can place for an order is:
* Underlying balances
* Allowances
* Onchain order cancellations
<Warning>
Any maker caught intentionally abusing these checks will be blacklisted.
</Warning>
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 USDC.e in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
The max size you can place for an order is:
$$
\text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount})
$$
***
## Querying Orders
All query endpoints require [L2 authentication](/api-reference/authentication).
### Get a Single Order
Retrieve details for a specific order by its ID:
<CodeGroup>
```typescript TypeScript theme={null}
const order = await client.getOrder("0xb816482a...");
console.log(order);
```
```python Python theme={null}
order = client.get_order("0xb816482a...")
print(order)
```
</CodeGroup>
### Get Open Orders
Retrieve your open orders, optionally filtered by market or asset:
<CodeGroup>
```typescript TypeScript theme={null}
// All open orders
const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
### OpenOrder Object
Each order returned contains these fields:
| Field | Type | Description |
| ------------------ | --------- | ------------------------------------------------------------ |
| `id` | string | Order ID |
| `status` | string | Current order status |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `original_size` | string | Original order size at placement |
| `size_matched` | string | Amount that has been filled |
| `price` | string | Limit price |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `order_type` | string | Order type (GTC, GTD, FOK, FAK) |
| `maker_address` | string | Funder address |
| `owner` | string | API key of the order owner |
| `expiration` | string | Unix timestamp when the order expires (`0` if no expiration) |
| `associate_trades` | string\[] | Trade IDs this order has been partially included in |
| `created_at` | string | Unix timestamp when the order was created |
***
## Trade History
When an order is matched, it creates a trade. Trades go through the following statuses:
| Status | Terminal? | Description |
| ----------- | --------- | -------------------------------------------------------------------- |
| `MATCHED` | No | Matched and sent to the executor service for onchain submission |
| `MINED` | No | Observed as mined on the chain, no finality threshold yet |
| `CONFIRMED` | Yes | Achieved strong probabilistic finality — trade successful |
| `RETRYING` | No | Transaction failed (revert or reorg) — being retried by the operator |
| `FAILED` | Yes | Trade failed permanently and is not being retried |
### Trade Object
Each trade contains these fields:
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------ |
| `id` | string | Trade ID |
| `taker_order_id` | string | Taker order ID (hash) |
| `market` | string | Market ID (condition ID) |
| `asset_id` | string | Token ID |
| `side` | string | `BUY` or `SELL` |
| `size` | string | Trade size |
| `fee_rate_bps` | string | Fee rate in basis points |
| `price` | string | Trade price |
| `status` | string | Trade status (see table above) |
| `match_time` | string | Unix timestamp when the trade was matched |
| `last_update` | string | Unix timestamp of last status update |
| `outcome` | string | Human-readable outcome (e.g., "Yes", "No") |
| `owner` | string | API key ID of the trade owner |
| `maker_address` | string | Funder address |
| `trader_side` | string | Whether you were `TAKER` or `MAKER` in this trade |
| `transaction_hash` | string | Onchain transaction hash (available after mining) |
| `maker_orders` | array | Array of maker orders matched against this trade (see below) |
### MakerOrder Fields
Each entry in the `maker_orders` array contains:
| Field | Type | Description |
| ---------------- | ------ | ---------------------------- |
| `order_id` | string | Maker order ID (hash) |
| `owner` | string | Maker's API key ID |
| `maker_address` | string | Maker's funder address |
| `matched_amount` | string | Amount matched in this trade |
| `price` | string | Maker order price |
| `fee_rate_bps` | string | Maker fee rate in bps |
| `asset_id` | string | Token ID |
| `outcome` | string | Outcome name |
| `side` | string | `BUY` or `SELL` |
Retrieve your trades with the SDK:
<CodeGroup>
```typescript TypeScript theme={null}
// All trades
const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
```
</CodeGroup>
***
## Heartbeat
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
<CodeGroup>
```typescript TypeScript theme={null}
// Send heartbeats in a loop
let heartbeatId = "";
setInterval(async () => {
const resp = await client.postHeartbeat(heartbeatId);
heartbeatId = resp.heartbeat_id;
}, 5000);
```
```python Python theme={null}
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
```
</CodeGroup>
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
<CodeGroup>
```typescript TypeScript theme={null}
// Single order
const scoring = await client.isOrderScoring({ orderId: "0x..." });
console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```
```python Python theme={null}
from py_clob_client.clob_types import OrderScoringParams, OrdersScoringParams
# Single order
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
# Multiple orders
batch_scoring = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
```
</CodeGroup>
***
## Onchain Order Info
When a trade is settled onchain, the Exchange contract emits an `OrderFilled` event with the following fields:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e for outcome tokens) |
| `makerAmountFilled` | Amount of the asset given out |
| `takerAmountFilled` | Amount of the asset received |
| `fee` | Fees paid by the order maker |
***
## Error Messages
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
| Error | Description |
| ---------------------------------- | ------------------------------------------------------ |
| `INVALID_ORDER_MIN_TICK_SIZE` | Price doesn't conform to the market's tick size |
| `INVALID_ORDER_MIN_SIZE` | Order size is below the minimum threshold |
| `INVALID_ORDER_DUPLICATED` | Identical order has already been placed |
| `INVALID_ORDER_NOT_ENOUGH_BALANCE` | Funder doesn't have sufficient balance or allowance |
| `INVALID_ORDER_EXPIRATION` | Expiration timestamp is in the past |
| `INVALID_ORDER_ERROR` | System error while inserting order |
| `INVALID_POST_ONLY_ORDER_TYPE` | Post-only flag used with a market order type (FOK/FAK) |
| `INVALID_POST_ONLY_ORDER` | Post-only order would cross the book |
| `EXECUTION_ERROR` | System error while executing trade |
| `ORDER_DELAYED` | Order placement delayed due to market conditions |
| `DELAYING_ORDER_ERROR` | System error while delaying order |
| `FOK_ORDER_NOT_FILLED_ERROR` | FOK order couldn't be fully filled |
| `MARKET_NOT_READY` | Market is not yet accepting orders |
### Insert Statuses
When an order is successfully placed, the response includes a `status` field:
| Status | Description |
| ----------- | -------------------------------------------------------------------- |
| `matched` | Order placed and matched with a resting order |
| `live` | Order placed and resting on the book |
| `delayed` | Order is marketable but subject to a matching delay |
| `unmatched` | Order is marketable but failed to delay — placement still successful |
***
## Security
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades. Users can cancel orders onchain independently if trust issues arise.
***
## Next Steps
<CardGroup cols={2}>
<Card title="Create Order" icon="plus" href="/trading/orders/create">
Build, sign, and submit orders
</Card>
<Card title="Cancel Order" icon="xmark" href="/trading/orders/cancel">
Cancel single, multiple, or all orders
</Card>
</CardGroup>
+165 -243
View File
@@ -4,274 +4,211 @@
# Quickstart
> Initialize the CLOB and place your first order.
> Place your first order on Polymarket
## Installation
This guide walks you through placing an order on Polymarket end-to-end.
<CodeGroup>
```bash TypeScript theme={null}
npm install @polymarket/clob-client ethers
```
<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 Python theme={null}
pip install py-clob-client
```
</CodeGroup>
</Step>
```bash Rust theme={null}
cargo add polymarket-client-sdk
```
</CodeGroup>
<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
## Quick Start
const HOST = "https://clob.polymarket.com";
const CHAIN_ID = 137; // Polygon mainnet
const signer = new Wallet(process.env.PRIVATE_KEY);
### 1. Setup Client
// Derive API credentials
const tempClient = new ClobClient(HOST, CHAIN_ID, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers"; // v5.8.0
// Initialize trading client
const client = new ClobClient(
HOST,
CHAIN_ID,
signer,
apiCreds,
0, // EOA
signer.address,
);
```
const HOST = "https://clob.polymarket.com";
const CHAIN_ID = 137; // Polygon mainnet
const signer = new Wallet(process.env.PRIVATE_KEY);
```python Python theme={null}
from py_clob_client.client import ClobClient
import os
// Create or derive user API credentials
const tempClient = new ClobClient(HOST, CHAIN_ID, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
// See 'Signature Types' note below
const signatureType = 0;
// Initialize trading client
const client = new ClobClient(
HOST,
CHAIN_ID,
signer,
apiCreds,
signatureType
);
```
```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")
# Create or derive user API credentials
temp_client = ClobClient(host, key=private_key, chain_id=chain_id)
api_creds = await temp_client.create_or_derive_api_key()
# See 'Signature Types' note below
signature_type = 0
# Initialize trading client
client = ClobClient(
host,
key=private_key,
chain_id=chain_id,
creds=api_creds,
signature_type=signature_type
)
```
</CodeGroup>
<Note>
This quick start sets your EOA as the trading account. You'll need to fund this
wallet to trade and pay for gas on transactions. Gas-less transactions are only
available by deploying a proxy wallet and using Polymarket's Polygon relayer
infrastructure.
</Note>
<Accordion title="Signature Types">
| Wallet Type | ID | When to Use |
| ------------ | --- | ------------------------------------------------------ |
| EOA | `0` | Standard Ethereum wallet (MetaMask) |
| Custom Proxy | `1` | Specific to Magic Link users from Polymarket only |
| Gnosis Safe | `2` | Injected providers (Metamask, Rabby, embedded wallets) |
</Accordion>
***
### 2. Place an Order
<CodeGroup>
```typescript TypeScript theme={null}
import { Side } from "@polymarket/clob-client";
// Place a limit order in one step
const response = await client.createAndPostOrder({
tokenID: "YOUR_TOKEN_ID", // Get from Gamma API
price: 0.65, // Price per share
size: 10, // Number of shares
side: Side.BUY, // or SELL
});
console.log(`Order placed! ID: ${response.orderID}`);
```
```python Python theme={null}
from py_clob_client.clob_types import OrderArgs
from py_clob_client.order_builder.constants import BUY
# Place a limit order in one step
response = await client.create_and_post_order(
OrderArgs(
token_id="YOUR_TOKEN_ID", # Get from Gamma API
price=0.65, # Price per share
size=10, # Number of shares
side=BUY, # or SELL
)
)
print(f"Order placed! ID: {response['orderID']}")
```
</CodeGroup>
***
### 3. 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`);
```
```python Python theme={null}
# View all open orders
open_orders = await client.get_open_orders()
print(f"You have {len(open_orders)} open orders")
# View your trade history
trades = await client.get_trades()
print(f"You've made {len(trades)} trades")
```
</CodeGroup>
***
## Complete Example
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient, Side } from "@polymarket/clob-client";
import { Wallet } from "ethers";
async function trade() {
const HOST = "https://clob.polymarket.com";
const CHAIN_ID = 137; // Polygon mainnet
const signer = new Wallet(process.env.PRIVATE_KEY);
const tempClient = new ClobClient(HOST, CHAIN_ID, signer);
const apiCreds = await tempClient.createOrDeriveApiKey();
const signatureType = 0;
const client = new ClobClient(
HOST,
CHAIN_ID,
signer,
apiCreds,
signatureType
);
const response = await client.createAndPostOrder({
tokenID: "YOUR_TOKEN_ID",
price: 0.65,
size: 10,
side: Side.BUY,
});
console.log(`Order placed! ID: ${response.orderID}`);
}
trade();
```
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs
from py_clob_client.order_builder.constants import BUY
import asyncio
import os
async def trade():
host = "https://clob.polymarket.com"
chain_id = 137 # Polygon mainnet
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)
creds = await temp_client.create_or_derive_api_key()
signature_type=0
api_creds = temp_client.create_or_derive_api_creds()
# Initialize trading client
client = ClobClient(
host,
chain_id=chain_id,
key=private_key,
creds=creds,
signature_type=signature_type
chain_id=chain_id,
creds=api_creds,
signature_type=0, # EOA
funder="YOUR_WALLET_ADDRESS"
)
```
</CodeGroup>
response = await client.create_and_post_order(
<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.65,
price=0.50,
size=10,
side=BUY
)
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": False, # Set to True for multi-outcome markets
},
order_type=OrderType.GTC
)
print(f"Order placed! ID: {response['orderID']}")
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
</CodeGroup>
if __name__ == "__main__":
asyncio.run(trade())
```
</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"])
```
</CodeGroup>
</Step>
</Steps>
***
## Troubleshooting
<AccordionGroup>
<Accordion title="Error: L2_AUTH_NOT_AVAILABLE">
You forgot to call `createOrDeriveApiKey()`. Make sure you initialize the client with API credentials:
<Accordion title="L2_AUTH_NOT_AVAILABLE / Invalid Signature">
Wrong private key, signature type, or funder address for the derived API credentials.
```typescript theme={null}
const creds = await clobClient.createOrDeriveApiKey();
const client = new ClobClient(host, chainId, wallet, creds);
```
* 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">
Ensure you have:
Your funder address doesn't have enough tokens:
* **USDC** in your funder address for BUY orders
* **Outcome tokens** in your funder address for SELL orders
Check your balance at [polymarket.com/portfolio](https://polymarket.com/portfolio).
* **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 use the CTF contract's `setApprovalForAll()` method.
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's my funder address?">
Your funder address is the Polymarket proxy wallet where you deposit funds. Find it:
Your funder address is the wallet where your funds are held:
1. Go to [polymarket.com/settings](https://polymarket.com/settings)
2. Look for "Wallet Address" or "Profile Address"
3. This is your `FUNDER_ADDRESS`
* **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 / Geoblock">
You're trying to place a trade from a restricted region. See [Geographic Restrictions](/api-reference/geoblock) for details.
</Accordion>
</AccordionGroup>
@@ -279,27 +216,12 @@
## Next Steps
<CardGroup cols={1}>
<Card title="Full Example Implementations" icon="puzzle" href="/developers/builders/examples">
Complete Next.js examples demonstrating integration of embedded wallets
(Privy, Magic, Turnkey, wagmi) and the CLOB and Builder Relay clients
</Card>
</CardGroup>
<CardGroup cols={2}>
<Card title="Understand CLOB Authentication" icon="shield" href="/developers/CLOB/authentication">
Deep dive into L1 and L2 authentication
<Card title="Create Orders" icon="plus" href="/trading/orders/create">
Order types, tick sizes, and error handling
</Card>
<Card title="Browse Client Methods" icon="book" href="/developers/CLOB/clients/methods-overview">
Explore the complete client reference
</Card>
<Card title="Find Markets to Trade" icon="chart-line" href="/developers/gamma-markets-api/get-markets">
Use Gamma API to discover markets
</Card>
<Card title="Monitor with WebSocket" icon="signal-stream" href="/developers/CLOB/websocket/wss-overview">
Get real-time order updates
<Card title="Order Attribution" icon="tag" href="/trading/orders/attribution">
Attribute orders to your builder account for volume credit
</Card>
</CardGroup>
File diff suppressed because one or more lines are too long
+56 -75
View File
@@ -2,153 +2,134 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Historical Timeseries Data
# Get prices history
> Fetches historical price data for a specified market token.
> Retrieve historical price data for a market.
The CLOB provides detailed price history for each traded token.
**HTTP REQUEST**
`GET /<clob-endpoint>/prices-history`
<Tip>We also have a Interactive Notebook to visualize the data from this endpoint available [here](https://colab.research.google.com/drive/1s4TCOR4K7fRP7EwAH1YmOactMakx24Cs?usp=sharing#scrollTo=mYCJBcfB9Zu4).</Tip>
## OpenAPI
````yaml GET /prices-history
openapi: 3.0.3
````yaml api-spec/clob-openapi.yaml get /prices-history
openapi: 3.1.0
info:
title: CLOB (Central Limit Order Book) API
description: >-
API for interacting with the Central Limit Order Book system, providing
orderbook data, prices, midpoints, and spreads
version: 1.0.0
contact:
name: CLOB API Team
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 server
- url: https://clob.polymarket.com
description: Production CLOB API
- url: https://clob-staging.polymarket.com
description: Staging CLOB API
security: []
tags:
- name: Orderbook
description: Order book related operations
- name: Pricing
description: Price and midpoint operations
- name: Spreads
description: Spread calculation operations
- 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
paths:
/prices-history:
get:
tags:
- Pricing
summary: Get price history for a traded token
description: Fetches historical price data for a specified market token
- 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
description: The CLOB token ID for which to fetch price history
example: '1234567890'
- name: startTs
in: query
required: false
description: Filter by items after this unix timestamp.
schema:
type: number
description: The start time, a Unix timestamp in UTC
example: 1697875200
format: double
- name: endTs
in: query
required: false
description: Filter by items before this unix timestamp.
schema:
type: number
description: The end time, a Unix timestamp in UTC
example: 1697961600
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
- max
description: >-
A string representing a duration ending at the current time.
Mutually exclusive with startTs and endTs
example: 1d
- name: fidelity
in: query
required: false
description: Accuracy of the data expressed in minutes. Default is 1 minute.
schema:
type: number
description: The resolution of the data, in minutes
example: 60
type: integer
responses:
'200':
description: A list of timestamp/price pairs
description: Successful response with price history
content:
application/json:
schema:
$ref: '#/components/schemas/PriceHistoryResponse'
$ref: '#/components/schemas/PricesHistoryResponse'
'400':
description: Bad request
description: Bad Request - Missing or invalid query parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Market not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
$ref: '#/components/schemas/ErrorResponse'
security: []
components:
schemas:
PriceHistoryResponse:
PricesHistoryResponse:
type: object
required:
- history
properties:
history:
type: array
items:
type: object
required:
- t
- p
properties:
t:
type: number
description: UTC timestamp
example: 1697875200
p:
type: number
description: Price
example: 1800.75
Error:
$ref: '#/components/schemas/MarketPrice'
ErrorResponse:
type: object
required:
- error
properties:
error:
type: string
description: Error message describing what went wrong
example: Invalid token id
description: Error message
MarketPrice:
type: object
properties:
t:
type: integer
format: uint32
p:
type: number
format: float
````
````
+192 -11
View File
@@ -2,18 +2,199 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Trades Overview
# Overview
## Overview
> Trading on the Polymarket CLOB
All historical trades can be fetched via the Polymarket CLOB REST API. A trade is initiated by a "taker" who creates a marketable limit order. This limit order can be matched against one or more resting limit orders on the associated book. A trade can be in various states as described below. Note: in some cases (due to gas limitations) the execution of a "trade" must be broken into multiple transactions which case separate trade entities will be returned. To associate trade entities, there is a bucket\_index field and a match\_time field. Trades that have been broken into multiple trade objects can be reconciled by combining trade objects with the same market\_order\_id, match\_time and incrementing bucket\_index's into a top level "trade" client side.
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.
## Statuses
We recommend using the open-source SDK clients, which handle order signing, authentication, and submission:
| Status | Terminal? | Description |
| --------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| MATCHED | no | trade has been matched and sent to the executor service by the operator, the executor service submits the trade as a transaction to the Exchange contract |
| MINED | no | trade is 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 |
<CardGroup cols={2}>
<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>
</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()
```
</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
)
```
</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's 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>
+177 -73
View File
@@ -2,95 +2,199 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Get Trades
# Overview
<Tip> This endpoint requires a L2 Header. </Tip>
> Trading on the Polymarket CLOB
Get trades for the authenticated user based on the provided filters.
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.
**HTTP REQUEST**
We recommend using the open-source SDK clients, which handle order signing, authentication, and submission:
`GET /<clob-endpoint>/data/trades`
<CardGroup cols={2}>
<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>
### Request Parameters
<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>
</CardGroup>
| Name | Required | Type | Description |
| ------ | -------- | ------ | --------------------------------------------------------------------------------------------------- |
| id | no | string | id of trade to fetch |
| taker | no | string | address to get trades for where it is included as a taker |
| maker | no | string | address to get trades for where it is included as a maker |
| market | no | string | market for which to get the trades (condition ID) |
| before | no | string | unix timestamp representing the cutoff up to which trades that happened before then can be included |
| after | no | string | unix timestamp representing the cutoff for which trades that happened after can be included |
<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>
### Response Format
***
| Name | Type | Description |
| ---- | -------- | ------------------------------------------- |
| null | Trade\[] | list of trades filtered by query parameters |
## Authentication
A `Trade` object is of the form:
The CLOB uses two levels of authentication:
| Name | Type | Description |
| ----------------- | ------------- | ---------------------------------------------------------------------------- |
| id | string | trade id |
| taker\_order\_id | string | hash of taker order (market order) that catalyzed the trade |
| market | string | market id (condition id) |
| asset\_id | string | asset id (token id) of taker order (market order) |
| side | string | buy or sell |
| size | string | size |
| fee\_rate\_bps | string | the fees paid for the taker order expressed in basic points |
| price | string | limit price of taker order |
| status | string | trade status (see above) |
| match\_time | string | time at which the trade was matched |
| last\_update | string | timestamp of last status update |
| outcome | string | human readable outcome of the trade |
| maker\_address | string | funder address of the taker of the trade |
| owner | string | api key of taker of the trade |
| transaction\_hash | string | hash of the transaction where the trade was executed |
| bucket\_index | integer | index of bucket for trade in case trade is executed in multiple transactions |
| maker\_orders | MakerOrder\[] | list of the maker trades the taker trade was filled against |
| type | string | side of the trade: TAKER or MAKER |
| 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 |
A `MakerOrder` object is of the form:
You use your private key once to derive **L2 credentials** (API key, secret, passphrase), which authenticate all subsequent trading requests.
| Name | Type | Description |
| --------------- | ------ | ----------------------------------------------------------- |
| order\_id | string | id of maker order |
| maker\_address | string | maker address of the order |
| owner | string | api key of the owner of the order |
| matched\_amount | string | size of maker order consumed with this trade |
| fee\_rate\_bps | string | the fees paid for the taker order expressed in basic points |
| price | string | price of maker order |
| asset\_id | string | token/asset id |
| outcome | string | human readable outcome of the maker order |
| side | string | the side of the maker order. Can be `buy` or `sell` |
<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();
```
<RequestExample>
```python Python theme={null}
from py_clob_client.clob_types import TradeParams
from py_clob_client.client import ClobClient
import os
resp = client.get_trades(
TradeParams(
maker_address=client.get_address(),
market="0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
),
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()
```
</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
)
print(resp)
print("Done!")
```
</CodeGroup>
```typescript Typescript theme={null}
async function main() {
const trades = await clobClient.getTrades({
market:
"0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
maker_address: await wallet.getAddress(),
});
console.log(`trades: `);
console.log(trades);
}
***
main();
```
</RequestExample>
## 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's 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>
+120 -242
View File
@@ -4,39 +4,37 @@
# Market Channel
Public channel for updates related to market updates (level 2 price data).
> Real-time orderbook, price, and trade data
**SUBSCRIBE**
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.
`<wss-channel> market`
## Endpoint
## book Message
```
wss://ws-subscriptions-clob.polymarket.com/ws/market
```
Emitted When:
## Subscription
* First subscribed to a market
* When there is a trade that affects the book
```json theme={null}
{
"assets_ids": ["<token_id_1>", "<token_id_2>"],
"type": "market",
"custom_feature_enabled": true
}
```
### Structure
Set `custom_feature_enabled: true` to receive `best_bid_ask`, `new_market`, and `market_resolved` events.
| Name | Type | Description |
| ----------- | --------------- | --------------------------------------------------------------------------- |
| event\_type | string | "book" |
| asset\_id | string | asset ID (token ID) |
| market | string | condition ID of market |
| timestamp | string | unix timestamp the current book generation in milliseconds (1/1,000 second) |
| hash | string | hash summary of the orderbook content |
| buys | OrderSummary\[] | list of type (size, price) aggregate book levels for buys |
| sells | OrderSummary\[] | list of type (size, price) aggregate book levels for sells |
## Message Types
Where a `OrderSummary` object is of the form:
Each message includes an `event_type` field identifying the type.
| Name | Type | Description |
| ----- | ------ | ---------------------------------- |
| price | string | price of the orderbook level |
| size | string | size available at that price level |
### book
```json Response theme={null}
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",
@@ -56,137 +54,79 @@ Where a `OrderSummary` object is of the form:
}
```
## price\_change Message
### price\_change
<div style={{backgroundColor: '#fff3cd', border: '1px solid #ffeaa7', borderRadius: '4px', padding: '12px', marginBottom: '16px'}}>
<strong>⚠️ Breaking Change Notice:</strong> The price\_change message schema will be updated on September 15, 2025 at 11 PM UTC. Please see the [migration guide](/developers/CLOB/websocket/market-channel-migration-guide) for details.
</div>
Emitted when a new order is placed or an order is cancelled.
Emitted When:
* A new order is placed
* An order is cancelled
### Structure
| Name | Type | Description |
| -------------- | -------------- | ------------------------------ |
| event\_type | string | "price\_change" |
| market | string | condition ID of market |
| price\_changes | PriceChange\[] | array of price change objects |
| timestamp | string | unix timestamp in milliseconds |
Where a `PriceChange` object is of the form:
| Name | Type | Description |
| --------- | ------ | ---------------------------------- |
| asset\_id | string | asset ID (token ID) |
| price | string | price level affected |
| size | string | new aggregate size for price level |
| side | string | "BUY" or "SELL" |
| hash | string | hash of the order |
| best\_bid | string | current best bid price |
| best\_ask | string | current best ask price |
```json Response theme={null}
```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"
"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"
}
```
## tick\_size\_change Message
A `size` of `"0"` means the price level has been removed from the book.
Emitted When:
### tick\_size\_change
* The minimum tick size of the market changes. This happens when the book's price reaches the limits: price > 0.96 or price \< 0.04
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.
### Structure
| Name | Type | Description |
| --------------- | ------ | -------------------------- |
| event\_type | string | "price\_change" |
| asset\_id | string | asset ID (token ID) |
| market | string | condition ID of market |
| old\_tick\_size | string | previous minimum tick size |
| new\_tick\_size | string | current minimum tick size |
| side | string | buy/sell |
| timestamp | string | time of event |
```json Response theme={null}
```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"
"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 Message
### last\_trade\_price
Emitted When:
Emitted when a maker and taker order is matched, creating a trade event.
* When a maker and taker order is matched creating a trade event.
```json Response theme={null}
```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"
"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 Message
### best\_bid\_ask
Emitted When:
<Note>Requires `custom_feature_enabled: true`.</Note>
* The best bid and ask prices for a market change.
Emitted when the best bid or ask prices for a market change.
(This message is behind the `custom_feature_enabled` flag)
### Structure
| Name | Type | Description |
| ----------- | ------ | ------------------------------- |
| event\_type | string | "best\_bid\_ask" |
| market | string | condition ID of market |
| asset\_id | string | asset ID (token ID) |
| best\_bid | string | current best bid price |
| best\_ask | string | current best ask price |
| spread | string | spread between best bid and ask |
| timestamp | string | unix timestamp in milliseconds |
### Example
```json Response theme={null}
```json theme={null}
{
"event_type": "best_bid_ask",
"market": "0x0005c0d312de0be897668695bae9f32b624b4a1ae8b140c49f08447fcc74f442",
@@ -198,126 +138,64 @@ Emitted When:
}
```
## new\_market Message
### new\_market
Emitted When:
<Note>Requires `custom_feature_enabled: true`.</Note>
* A new market is created.
Emitted when a new market is created.
(This message is behind the `custom_feature_enabled` flag)
### Structure
| Name | Type | Description |
| -------------- | --------- | ------------------------------ |
| id | string | market ID |
| question | string | market question |
| market | string | condition ID of market |
| slug | string | market slug |
| description | string | market description |
| assets\_ids | string\[] | list of asset IDs |
| outcomes | string\[] | list of outcomes |
| event\_message | object | event message object |
| timestamp | string | unix timestamp in milliseconds |
| event\_type | string | "new\_market" |
Where a `EventMessage` object is of the form:
| Name | Type | Description |
| ----------- | ------ | ------------------------- |
| id | string | event message ID |
| ticker | string | event message ticker |
| slug | string | event message slug |
| title | string | event message title |
| description | string | event message description |
### Example
```json Response theme={null}
```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 for NVIDIA (NVDA) on the final trading day of January 2026 is higher than the listed price. Otherwise, this market will resolve to \"No\".\n\nIf the final trading day of the month is shortened (for example, due to a market-holiday schedule), the official closing price published for that shortened session will still be used for resolution.\n\nIf no official closing price is published for that session (for example, due to a trading halt into the close, system issue, or other disruption), the market will use the last valid on-exchange trade price of the regular session as the effective closing price.\n\nThe resolution source for this market is Yahoo Finance — specifically, the NVIDIA (NVDA) \"Close\" prices available at https://finance.yahoo.com/quote/NVDA/history, published under \"Historical Prices.\"\n\nIn the event of a stock split, reverse stock split, or similar corporate action affecting the listed company during the listed time frame, this market will resolve based on split-adjusted prices as displayed on Yahoo Finance.",
"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 for NVIDIA (NVDA) on the final trading day of January 2026 is higher than the listed price. Otherwise, this market will resolve to \"No\".\n\nIf the final trading day of the month is shortened (for example, due to a market-holiday schedule), the official closing price published for that shortened session will still be used for resolution.\n\nIf no official closing price is published for that session (for example, due to a trading halt into the close, system issue, or other disruption), the market will use the last valid on-exchange trade price of the regular session as the effective closing price.\n\nThe resolution source for this market is Yahoo Finance — specifically, the NVIDIA (NVDA) \"Close\" prices available at https://finance.yahoo.com/quote/NVDA/history, published under \"Historical Prices.\"\n\nIn the event of a stock split, reverse stock split, or similar corporate action affecting the listed company during the listed time frame, this market will resolve based on split-adjusted prices as displayed on Yahoo Finance."
},
"timestamp": "1766790415550",
"event_type": "new_market"
"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"
}
```
## market\_resolved Message
### market\_resolved
Emitted When:
<Note>Requires `custom_feature_enabled: true`.</Note>
* A market is resolved.
Emitted when a market is resolved.
(This message is behind the `custom_feature_enabled` flag)
### Structure
| Name | Type | Description |
| ------------------ | --------- | ------------------------------ |
| id | string | market ID |
| question | string | market question |
| market | string | condition ID of market |
| slug | string | market slug |
| description | string | market description |
| assets\_ids | string\[] | list of asset IDs |
| outcomes | string\[] | list of outcomes |
| winning\_asset\_id | string | winning asset ID |
| winning\_outcome | string | winning outcome |
| event\_message | object | event message object |
| timestamp | string | unix timestamp in milliseconds |
| event\_type | string | "market\_resolved" |
Where a `EventMessage` object is of the form:
| Name | Type | Description |
| ----------- | ------ | ------------------------- |
| id | string | event message ID |
| ticker | string | event message ticker |
| slug | string | event message slug |
| title | string | event message title |
| description | string | event message description |
### Example
```json Response theme={null}
```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 for NVIDIA (NVDA) on the final trading day of January 2026 is higher than the listed price. Otherwise, this market will resolve to \"No\".\n\nIf the final trading day of the month is shortened (for example, due to a market-holiday schedule), the official closing price published for that shortened session will still be used for resolution.\n\nIf no official closing price is published for that session (for example, due to a trading halt into the close, system issue, or other disruption), the market will use the last valid on-exchange trade price of the regular session as the effective closing price.\n\nThe resolution source for this market is Yahoo Finance — specifically, the NVIDIA (NVDA) \"Close\" prices available at https://finance.yahoo.com/quote/NVDA/history, published under \"Historical Prices.\"\n\nIn the event of a stock split, reverse stock split, or similar corporate action affecting the listed company during the listed time frame, this market will resolve based on split-adjusted prices as displayed on Yahoo Finance.",
"assets_ids": [
"76043073756653678226373981964075571318267289248134717369284518995922789326425",
"31690934263385727664202099278545688007799199447969475608906331829650099442770"
],
"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 for NVIDIA (NVDA) on the final trading day of January 2026 is higher than the listed price. Otherwise, this market will resolve to \"No\".\n\nIf the final trading day of the month is shortened (for example, due to a market-holiday schedule), the official closing price published for that shortened session will still be used for resolution.\n\nIf no official closing price is published for that session (for example, due to a trading halt into the close, system issue, or other disruption), the market will use the last valid on-exchange trade price of the regular session as the effective closing price.\n\nThe resolution source for this market is Yahoo Finance — specifically, the NVIDIA (NVDA) \"Close\" prices available at https://finance.yahoo.com/quote/NVDA/history, published under \"Historical Prices.\"\n\nIn the event of a stock split, reverse stock split, or similar corporate action affecting the listed company during the listed time frame, this market will resolve based on split-adjusted prices as displayed on Yahoo Finance."
},
"timestamp": "1766790415550",
"event_type": "new_market"
"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"
}
```
+60 -65
View File
@@ -4,54 +4,50 @@
# User Channel
Authenticated channel for updates related to user activities (orders, trades), filtered for authenticated user by apikey.
> Authenticated order and trade updates
**SUBSCRIBE**
Authenticated channel for updates related to your orders and trades, filtered by API key.
`<wss-channel> user`
## Endpoint
## Trade Message
```
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:
* when a market order is matched ("MATCHED")
* when a limit order for the user is included in a trade ("MATCHED")
* subsequent status changes for trade ("MINED", "CONFIRMED", "RETRYING", "FAILED")
* 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`)
### Structure
| Name | Type | Description |
| ---------------- | ------------- | ------------------------------------------- |
| asset\_id | string | asset id (token ID) of order (market order) |
| event\_type | string | "trade" |
| id | string | trade id |
| last\_update | string | time of last update to trade |
| maker\_orders | MakerOrder\[] | array of maker order details |
| market | string | market identifier (condition ID) |
| matchtime | string | time trade was matched |
| outcome | string | outcome |
| owner | string | api key of event owner |
| price | string | price |
| side | string | BUY/SELL |
| size | string | size |
| status | string | trade status |
| taker\_order\_id | string | id of taker order |
| timestamp | string | time of event |
| trade\_owner | string | api key of trade owner |
| type | string | "TRADE" |
Where a `MakerOrder` object is of the form:
| Name | Type | Description |
| --------------- | ------ | -------------------------------------- |
| asset\_id | string | asset of the maker order |
| matched\_amount | string | amount of maker order matched in trade |
| order\_id | string | maker order ID |
| outcome | string | outcome |
| owner | string | owner of maker order |
| price | string | price of maker order |
```json Response theme={null}
```json theme={null}
{
"asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
"event_type": "trade",
@@ -82,34 +78,33 @@ Where a `MakerOrder` object is of the form:
}
```
## Order Message
#### 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:
* When an order is placed (PLACEMENT)
* When an order is updated (some of it is matched) (UPDATE)
* When an order is canceled (CANCELLATION)
* An order is placed (`PLACEMENT`)
* An order is updated some of it is matched (`UPDATE`)
* An order is cancelled (`CANCELLATION`)
### Structure
| Name | Type | Description |
| ----------------- | --------- | ------------------------------------------------------------------- |
| asset\_id | string | asset ID (token ID) of order |
| associate\_trades | string\[] | array of ids referencing trades that the order has been included in |
| event\_type | string | "order" |
| id | string | order id |
| market | string | condition ID of market |
| order\_owner | string | owner of order |
| original\_size | string | original order size |
| outcome | string | outcome |
| owner | string | owner of orders |
| price | string | price of order |
| side | string | BUY/SELL |
| size\_matched | string | size of order that has been matched |
| timestamp | string | time of event |
| type | string | PLACEMENT/UPDATE/CANCELLATION |
```json Response theme={null}
```json theme={null}
{
"asset_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
"associate_trades": null,
+175 -7
View File
@@ -2,12 +2,180 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# WSS Authentication
# Overview
<Tip> Only connections to `user` channel require authentication. </Tip>
> Real-time market data and trading updates via WebSocket
| Field | Optional | Description |
| ---------- | -------- | ------------------------------------- |
| apikey | yes | Polygon account's CLOB api key |
| secret | yes | Polygon account's CLOB api secret |
| passphrase | yes | Polygon account's CLOB api passphrase |
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 & 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 ~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>
+166 -21
View File
@@ -2,35 +2,180 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# WSS Overview
# Overview
> Overview and general information about the Polymarket Websocket
> Real-time market data and trading updates via WebSocket
## Overview
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).
The Polymarket CLOB API provides websocket (wss) channels through which clients can get pushed updates. These endpoints allow clients to maintain almost real-time views of their orders, their trades and markets in general. There are two available channels `user` and `market`.
## Channels
## Subscription
| 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 |
To subscribe send a message including the following authentication and intent information upon opening the connection.
### Market Channel
| Field | Type | Description |
| ------------------------ | --------- | --------------------------------------------------------------------------- |
| auth | Auth | see next page for auth information |
| markets | string\[] | array of markets (condition IDs) to receive events for (for `user` channel) |
| assets\_ids | string\[] | array of asset ids (token IDs) to receive events for (for `market` channel) |
| type | string | id of channel to subscribe to (USER or MARKET) |
| custom\_feature\_enabled | bool | enabling / disabling custom features |
| 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 |
Where the `auth` field is of type `Auth` which has the form described in the WSS Authentication section below.
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
Once connected, the client can subscribe and unsubscribe to `asset_ids` by sending the following message:
```json theme={null}
{
"assets_ids": ["new_asset_id_1", "new_asset_id_2"],
"operation": "subscribe",
"custom_feature_enabled": true
}
```
| Field | Type | Description |
| ------------------------ | --------- | ------------------------------------------------------------------------------ |
| assets\_ids | string\[] | array of asset ids (token IDs) to receive events for (for `market` channel) |
| markets | string\[] | array of market ids (condition IDs) to receive events for (for `user` channel) |
| operation | string | "subscribe" or "unsubscribe" |
| custom\_feature\_enabled | bool | enabling / disabling custom features |
### 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 & 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 ~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>
+82 -18
View File
@@ -2,27 +2,91 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Deployment and Additional Information
# Contract Addresses
## Deployment
> All Polymarket smart contract addresses on Polygon
The CTF contract is deployed (and verified) at the following addresses:
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.
| Network | Deployed Address |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Polygon Mainnet | [0x4D97DCd97eC945f40cF65F87097ACe5EA0476045](https://polygonscan.com/address/0x4D97DCd97eC945f40cF65F87097ACe5EA0476045) |
| Polygon Mainnet | [0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E](https://polygonscan.com/address/0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E) |
***
Polymarket provides code samples in both Python and TypeScript for interacting
with our smart chain contracts. You will need an RPC endpoint to access the
blockchain, and you'll be responsible for paying gas fees when executing these
RPC/function calls. Please ensure you're using the correct example for your wallet
type (Safe Wallet vs Proxy Wallet) when implementing.
## Core Trading Contracts
## Resources
| 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 |
* [On-Chain Code Samples](https://github.com/Polymarket/examples/tree/main/examples)
* [Polygon RPC List](https://chainlist.org/chain/137)
* [CTF Source Code](https://github.com/gnosis/conditional-tokens-contracts)
* [Audits](https://github.com/gnosis/conditional-tokens-contracts/tree/master/docs/audit)
* [Gist For positionId Calculation](https://gist.github.com/L-Kov/950bce141a9d1aa1ed3b1cfce6d30217)
***
## 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",
}
```
</CodeGroup>
+57 -7
View File
@@ -2,12 +2,62 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Merging Tokens
# Merge Tokens
In addition to splitting collateral for a full set, the inverse can also happen; a full set can be "merged" for collateral. This operation can again happen at any time after a condition has been prepared on the CTF contract. One unit of each position in a full set is burned in return for 1 collateral unit. This operation happens via the `mergePositions()` function on the CTF contract with the following parameters:
> Convert outcome token pairs back to USDC.e
* `collateralToken`: IERC20 - The address of the positions' backing collateral token.
* `parentCollectionId`: bytes32 - The ID of the outcome collections common to the position being merged and the merge target positions. Null in Polymarket case.
* `conditionId`: bytes32 - The ID of the condition to merge on.
* `partition`: uint\[] - An array of disjoint index sets representing a nontrivial partition of the outcome slots of the given condition. E.G. A|B and C but not A|B and B|C (is not disjoint). Each element's a number which, together with the condition, represents the outcome collection. E.G. 0b110 is A|B, 0b010 is B, etc. In the Polymarket case 1|2.
* `amount` - The number of full sets to merge. Also the amount of collateral to receive.
**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>
+130 -24
View File
@@ -2,33 +2,139 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Overview
# Conditional Token Framework
All outcomes on Polymarket are tokenized on the Polygon network. Specifically, Polymarket outcomes shares are binary outcomes (ie "YES" and "NO") using Gnosis' Conditional Token Framework (CTF). They are distinct ERC1155 tokens related to a parent condition and backed by the same collateral. More technically, the binary outcome tokens are referred to as "positionIds" in Gnosis's documentation. "PositionIds" are derived from a collateral token and distinct "collectionIds". "CollectionIds" are derived from a "parentCollectionId", (always bytes32(0) in our case) a "conditionId", and a unique "indexSet".
> Onchain token mechanics powering Polymarket positions
The "indexSet" is a 256 bit array denoting which outcome slots are in an outcome collection; it MUST be a nonempty proper subset of a condition's outcome slots. In the binary case, which we are interested in, there are two "indexSets", one for the first outcome and one for the second. The first outcome's "indexSet" is 0b01 = 1 and the second's is 0b10 = 2. The parent "conditionId" (shared by both "collectionIds" and therefore "positionIds") is derived from a "questionId" (a hash of the UMA ancillary data), an "oracle" (the UMA adapter V2), and an "outcomeSlotCount" (always 2 in the binary case). The steps for calculating the ERC1155 token ids (positionIds) is as follows:
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.
1. Get the conditionId
1. Function:
1. `getConditionId(oracle, questionId, outcomeSlotCount)`
2. Inputs:
1. `oracle`: address - UMA adapter V2
2. `questionId`: bytes32 - hash of the UMA ancillary data
3. `outcomeSlotCount`: uint - 2 for binary markets
## What is CTF?
2. Get the two collectionIds
1. Function:
1. `getCollectionId(parentCollectionId, conditionId, indexSet)`
2. Inputs:
1. `parentCollectionId`: bytes32 - bytes32(0)
2. `conditionId`: bytes32 - the conditionId derived from (1)
3. `indexSet`: uint - 1 (0b01) for the first and 2 (0b10) for the second.
The Conditional Token Framework creates **ERC1155 tokens** representing outcomes of prediction markets. Each binary market has two tokens:
3. Get the two positionIds
1. Function:
1. `getPositionId(collateralToken, collectionId)`
2. Inputs:
1. `collateralToken`: IERC20 - address of ERC20 token collateral (USDC)
2. `collectionId`: bytes32 - the two collectionIds derived from (3)
| Token | Redeems for | Condition |
| ------- | ------------- | -------------------- |
| **Yes** | \$1.00 USDC.e | Event occurs |
| **No** | \$1.00 USDC.e | Event does not occur |
Leveraging the relations above, specifically "conditionIds" -> "positionIds" the Gnosis CTF contract allows for "splitting" and "merging" full outcome sets. We explore these actions and provide code examples below.
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" data-og-width="1596" width="1596" data-og-height="952" height="952" data-path="images/core-concepts/token-flow.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/token-flow.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=abc92640ec62d9e02f2097f1c67231cb 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/token-flow.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=0f3f010e10a5cf39e78e594cdf8e579d 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/token-flow.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=e26855cc3aeac4b609657690df3d0086 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/token-flow.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=78547971ce2f750cb824d2cfdc705171 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/token-flow.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=bfdcab4d02ad6fe37e0549b33b940869 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/token-flow.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=78ec4b0dae7b6dc701e180fbb2e755e4 2500w" />
<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" data-og-width="1596" width="1596" data-og-height="952" height="952" data-path="images/dark/core-concepts/token-flow.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/token-flow.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=0ef33ff2c0ab77156745d8b381dafe00 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/token-flow.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=8ab82e34078a6811fc929d3bb15ee448 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/token-flow.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=750c6e303bc8df05bbb335dd79edd2d6 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/token-flow.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=4d5553bef579cd8b50f5be39e8e91e61 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/token-flow.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=d69588b8286d2a561101ffbd55364ebd 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/token-flow.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=633d6ce55594e89381b81b30f5f0ad45 2500w" />
</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>
+88 -6
View File
@@ -2,11 +2,93 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Reedeeming Tokens
# Redeem Tokens
Once a condition has had it's payouts reported (ie by the UMACTFAdapter calling `reportPayouts` on the CTF contract), users with shares in the winning outcome can redeem them for the underlying collateral. Specifically, users can call the `redeemPositions` function on the CTF contract which will burn all valuable conditional tokens in return for collateral according to the reported payout vector. This function has the following parameters:
> Exchange winning tokens for USDC.e after market resolution
* `collateralToken`: IERC20 - The address of the positions' backing collateral token.
* `parentCollectionId`: bytes32 - The ID of the outcome collections common to the position being redeemed. Null in Polymarket case.
* `indexSets`: uint\[] - The ID of the condition to redeem.
* `indexSets`: uint\[] - An array of disjoint index sets representing a nontrivial partition of the outcome slots of the given condition. E.G. A|B and C but not A|B and B|C (is not disjoint). Each element's a number which, together with the condition, represents the outcome collection. E.G. 0b110 is A|B, 0b010 is B, etc. In the Polymarket case 1|2.
**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>
+63 -7
View File
@@ -2,12 +2,68 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Splitting USDC
# Split Tokens
At any time, after a condition has been prepared on the CTF contract (via `prepareCondition`), it is possible to "split" collateral into a full (position) set. In other words, one unit USDC can be split into 1 YES unit and 1 NO unit. If splitting from the collateral, the CTF contract will attempt to transfer `amount` collateral from the message sender to itself. If successful, `amount` stake will be minted in the split target positions. If any of the transfers, mints, or burns fail, the transaction will revert. The transaction will also revert if the given partition is trivial, invalid, or refers to more slots than the condition is prepared with. This operation happens via the `splitPosition()` function on the CTF contract with the following parameters:
> Convert USDC.e into outcome token pairs
* `collateralToken`: IERC20 - The address of the positions' backing collateral token.
* `parentCollectionId`: bytes32 - The ID of the outcome collections common to the position being split and the split target positions. Null in Polymarket case.
* `conditionId`: bytes32 - The ID of the condition to split on.
* `partition`: uint\[] - An array of disjoint index sets representing a nontrivial partition of the outcome slots of the given condition. E.G. A|B and C but not A|B and B|C (is not disjoint). Each element's a number which, together with the condition, represents the outcome collection. E.G. 0b110 is A|B, 0b010 is B, etc. In the Polymarket case 1|2.
* `amount` - The amount of collateral or stake to split. Also the number of full sets to receive.
**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>
+269 -110
View File
@@ -2,123 +2,259 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# RTDS Comments
# Real-Time Data Socket
> Stream comments and crypto prices via WebSocket
The Polymarket Real-Time Data Socket (RTDS) is a WebSocket-based streaming service that provides real-time updates for **comments** and **crypto 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>
## Overview
## Endpoint
The comments subscription provides real-time updates for comment-related events on the Polymarket platform. This includes new comments being created, as well as other comment interactions like reactions and replies.
```
wss://ws-live-data.polymarket.com
```
## Subscription Details
Some user-specific streams may require `gamma_auth` with your wallet address.
* **Topic**: `comments`
* **Type**: `comment_created` (and potentially other comment event types like `reaction_created`)
* **Authentication**: May require Gamma authentication for user-specific data
* **Filters**: Optional (can filter by specific comment IDs, users, or events)
## Subscribing
## Subscription Message
Send a JSON message to subscribe to data streams:
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "comments",
"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`, `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 (`crypto_prices`)
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 (`crypto_prices_chainlink`)
<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
## 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 Format
### Message Types
When subscribed to comments, you'll receive messages with the following structure:
```json theme={null}
{
"topic": "comments",
"type": "comment_created",
"timestamp": 1753454975808,
"payload": {
"body": "do you know what the term encircle means? it means to surround from all sides, Russia has present on only 1 side, that's the opposite of an encirclement",
"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"
}
}
```
## 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
Triggered when a user creates a new comment on an event or in reply to another comment.
### comment\_removed
Triggered when a comment is removed or deleted.
### reaction\_created
Triggered when a user adds a reaction to an existing comment.
### reaction\_removed
Triggered when a reaction is removed from a 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 (e.g., "Event", "Market") |
| `profile` | object | Profile information of the user who created the comment |
| `reactionCount` | number | Current number of reactions on this comment |
| `replyAddress` | string | Polygon address for replies (may be different from userAddress) |
| `reportCount` | number | Current number of reports on this comment |
| `userAddress` | string | Polygon address of the user who created the comment |
### Profile Object Fields
| Field | Type | Description |
| ----------------------- | ------- | ------------------------------------------------- |
| `baseAddress` | string | User profile address |
| `displayUsernamePublic` | boolean | Whether the username should be displayed publicly |
| `name` | string | User's display name |
| `proxyWallet` | string | Proxy wallet address used for transactions |
| `pseudonym` | string | Generated pseudonym for the user |
## Parent Entity Types
The following parent entity types are supported:
* `Event` - Comments on prediction events
* `Market` - Comments on specific markets
* Additional entity types may be available
## Example Messages
### New Comment Created
Emitted when a user posts a new comment or replies to an existing one.
```json theme={null}
{
@@ -126,7 +262,7 @@ The following parent entity types are supported:
"type": "comment_created",
"timestamp": 1753454975808,
"payload": {
"body": "do you know what the term encircle means? it means to surround from all sides, Russia has present on only 1 side, that's the opposite of an encirclement",
"body": "That's a good point about the definition.",
"createdAt": "2025-07-25T14:49:35.801298Z",
"id": "1763355",
"parentCommentID": "1763325",
@@ -147,7 +283,7 @@ The following parent entity types are supported:
}
```
### Reply to Existing Comment
A reply to the above comment — note `parentCommentID` references the parent:
```json theme={null}
{
@@ -155,7 +291,7 @@ The following parent entity types are supported:
"type": "comment_created",
"timestamp": 1753454985123,
"payload": {
"body": "That's a good point about the definition of encirclement.",
"body": "I agree, the resolution criteria should be clearer.",
"createdAt": "2025-07-25T14:49:45.120000Z",
"id": "1763356",
"parentCommentID": "1763355",
@@ -176,27 +312,50 @@ The following parent entity types are supported:
}
```
## Comment Hierarchy
### 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`
* All comments are associated with a `parentEntityID` and `parentEntityType` (`Event` or `Market`)
## Use Cases
## Troubleshooting
* Real-time comment feed displays
* Discussion thread monitoring
* Community sentiment analysis
<Accordion title="Connection drops unexpectedly">
Send `PING` messages every 5 seconds to keep the connection alive. Connection errors will trigger automatic reconnection attempts.
</Accordion>
## Content
<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>
* Comments include `reactionCount` and `reportCount`
* Comment body contains the full text content
## Notes
* The `createdAt` timestamp uses ISO 8601 format with timezone information
* The outer `timestamp` field represents when the WebSocket message was sent
* User profiles include both primary addresses and proxy wallet addresses
<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>
+249 -132
View File
@@ -2,32 +2,77 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# RTDS Crypto Prices
# Real-Time Data Socket
> Stream comments and crypto prices via WebSocket
The Polymarket Real-Time Data Socket (RTDS) is a WebSocket-based streaming service that provides real-time updates for **comments** and **crypto 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>
## Overview
## Endpoint
The crypto prices subscription provides real-time updates for cryptocurrency price data from two different sources:
```
wss://ws-live-data.polymarket.com
```
* **Binance Source** (`crypto_prices`): Real-time price data from Binance exchange
* **Chainlink Source** (`crypto_prices_chainlink`): Price data from Chainlink oracle networks
Some user-specific streams may require `gamma_auth` with your wallet address.
Both streams deliver current market prices for various cryptocurrency trading pairs, but use different symbol formats and subscription structures.
## Subscribing
## Binance Source (`crypto_prices`)
Send a JSON message to subscribe to data streams:
### Subscription Details
```json theme={null}
{
"action": "subscribe",
"subscriptions": [
{
"topic": "topic_name",
"type": "message_type",
"filters": "optional_filter_string",
"gamma_auth": {
"address": "wallet_address"
}
}
]
}
```
* **Topic**: `crypto_prices`
* **Type**: `update`
* **Authentication**: Not required
* **Filters**: Optional (specific symbols can be filtered)
* **Symbol Format**: Lowercase concatenated pairs (e.g., `solusdt`, `btcusdt`)
To unsubscribe, send the same structure with `"action": "unsubscribe"`.
### Subscription Message
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`, `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 (`crypto_prices`)
Subscribe to all symbols:
```json theme={null}
{
@@ -41,13 +86,11 @@ Both streams deliver current market prices for various cryptocurrency trading pa
}
```
### With Symbol Filter
To subscribe to specific cryptocurrency symbols, include a filters parameter:
Subscribe to specific symbols with a comma-separated filter:
```json theme={null}
{
"action": "subscribe",
"action": "subscribe",
"subscriptions": [
{
"topic": "crypto_prices",
@@ -58,21 +101,45 @@ To subscribe to specific cryptocurrency symbols, include a filters parameter:
}
```
## Chainlink Source (`crypto_prices_chainlink`)
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 (`crypto_prices_chainlink`)
<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>
### Subscription Details
* **Topic**: `crypto_prices_chainlink`
* **Type**: `*` (all types)
* **Authentication**: Not required
* **Filters**: Optional (JSON object with symbol specification)
* **Symbol Format**: Slash-separated pairs (e.g., `eth/usd`, `btc/usd`)
### Subscription Message
Subscribe to all symbols:
```json theme={null}
{
@@ -87,9 +154,7 @@ To subscribe to specific cryptocurrency symbols, include a filters parameter:
}
```
### With Symbol Filter
To subscribe to specific cryptocurrency symbols, include a JSON filters parameter:
Subscribe to a specific symbol with a JSON filter:
```json theme={null}
{
@@ -104,33 +169,14 @@ To subscribe to specific cryptocurrency symbols, include a JSON filters paramete
}
```
## Message Format
Symbols use slash-separated format (e.g., `eth/usd`, `btc/usd`).
### Binance Source Message Format
When subscribed to Binance crypto prices (`crypto_prices`), you'll receive messages with the following structure:
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "solusdt",
"timestamp": 1753314064213,
"value": 189.55
}
}
```
### Chainlink Source Message Format
When subscribed to Chainlink crypto prices (`crypto_prices_chainlink`), you'll receive messages with the following structure:
**Ethereum price update:**
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "eth/usd",
@@ -140,71 +186,12 @@ When subscribed to Chainlink crypto prices (`crypto_prices_chainlink`), you'll r
}
```
## Payload Fields
| Field | Type | Description |
| ----------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `symbol` | string | Trading pair symbol<br />**Binance**: lowercase concatenated (e.g., "solusdt", "btcusdt")<br />**Chainlink**: slash-separated (e.g., "eth/usd", "btc/usd") |
| `timestamp` | number | Price timestamp in Unix milliseconds |
| `value` | number | Current price value in the quote currency |
## Example Messages
### Binance Source Examples
#### Solana Price Update (Binance)
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314064237,
"payload": {
"symbol": "solusdt",
"timestamp": 1753314064213,
"value": 189.55
}
}
```
#### Bitcoin Price Update (Binance)
```json theme={null}
{
"topic": "crypto_prices",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btcusdt",
"timestamp": 1753314088395,
"value": 67234.50
}
}
```
### Chainlink Source Examples
#### Ethereum Price Update (Chainlink)
**Bitcoin 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 (Chainlink)
```json theme={null}
{
"topic": "crypto_prices_chainlink",
"type": "update",
"timestamp": 1753314088421,
"payload": {
"symbol": "btc/usd",
@@ -214,31 +201,161 @@ When subscribed to Chainlink crypto prices (`crypto_prices_chainlink`), you'll r
}
```
## Supported Symbols
### Price Payload Fields
### Binance Source Symbols
| 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 |
The Binance source supports various cryptocurrency trading pairs using lowercase concatenated format:
### Supported Symbols
* `btcusdt` - Bitcoin to USDT
* `ethusdt` - Ethereum to USDT
* `solusdt` - Solana to USDT
* `xrpusdt` - XRP to USDT
**Binance Source** — lowercase concatenated format:
### Chainlink Source Symbols
* `btcusdt` — Bitcoin to USDT
* `ethusdt` — Ethereum to USDT
* `solusdt` — Solana to USDT
* `xrpusdt` — XRP to USDT
The Chainlink source supports cryptocurrency trading pairs using slash-separated format:
**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
* `btc/usd` Bitcoin to USD
* `eth/usd` Ethereum to USD
* `sol/usd` Solana to USD
* `xrp/usd` XRP to USD
## Notes
## Comments
### General
Real-time comment events on the Polymarket platform, including new comments, replies, reactions, and removals. May require Gamma authentication for user-specific data.
* Price updates are sent as market prices change
* The timestamp in the payload represents when the price was recorded
* The outer timestamp represents when the message was sent via WebSocket
* No authentication is required for crypto price 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>
+324 -54
View File
@@ -2,9 +2,9 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Real Time Data Socket
# Real-Time Data Socket
## Overview
> Stream comments and crypto prices via WebSocket
The Polymarket Real-Time Data Socket (RTDS) is a WebSocket-based streaming service that provides real-time updates for **comments** and **crypto prices**.
@@ -12,57 +12,17 @@ The Polymarket Real-Time Data Socket (RTDS) is a WebSocket-based streaming servi
Official RTDS TypeScript client (`real-time-data-client`).
</Card>
### Connection Details
## Endpoint
* **WebSocket URL**: `wss://ws-live-data.polymarket.com`
* **Protocol**: WebSocket
* **Data Format**: JSON
### Authentication
Some user-specific streams may require `gamma_auth`:
* `address`: User wallet address
### Connection Management
The WebSocket connection supports:
* **Dynamic Subscriptions**: Without disconnecting from the socket users can add, remove and modify topics and filters they are subscribed to.
* **Ping/Pong**: You should send PING messages (every 5 seconds ideally) to maintain connection
## Available Subscription Types
<Note>Only the subscription types documented below are supported.</Note>
The RTDS currently supports the following subscription types:
1. **[Crypto Prices](/developers/RTDS/RTDS-crypto-prices)** - Real-time cryptocurrency price updates
2. **[Comments](/developers/RTDS/RTDS-comments)** - Comment-related events including reactions
## Message Structure
All messages received from the WebSocket follow this structure:
```json theme={null}
{
"topic": "string",
"type": "string",
"timestamp": "number",
"payload": "object"
}
```
wss://ws-live-data.polymarket.com
```
* `topic`: The subscription topic (e.g., "crypto\_prices", "comments")
* `type`: The message type/event (e.g., "update", "reaction\_created")
* `timestamp`: Unix timestamp in milliseconds
* `payload`: Event-specific data object
Some user-specific streams may require `gamma_auth` with your wallet address.
## Subscription Management
## Subscribing
### Subscribe to Topics
To subscribe to data streams, send a JSON message with this structure:
Send a JSON message to subscribe to data streams:
```json theme={null}
{
@@ -80,12 +40,322 @@ To subscribe to data streams, send a JSON message with this structure:
}
```
### Unsubscribe from Topics
To unsubscribe, send the same structure with `"action": "unsubscribe"`.
To unsubscribe from data streams, send a similar message with `"action": "unsubscribe"`.
Subscriptions can be added, removed, and modified without disconnecting. Send `PING` messages every 5 seconds to maintain the connection.
## Error Handling
<Note>Only the subscription types documented below are supported.</Note>
* Connection errors will trigger automatic reconnection attempts
* Invalid subscription messages may result in connection closure
* Authentication failures will prevent successful subscription to protected topics
## 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`, `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 (`crypto_prices`)
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 (`crypto_prices_chainlink`)
<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
## 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>
@@ -2,69 +2,91 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Blockchain Data Resources
# Contract Addresses
> Access Polymarket on-chain activity for data & analytics
> All Polymarket smart contract addresses on Polygon
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.
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.
***
## Data
## Core Trading Contracts
### Goldsky
| 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 |
[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.
## Token Contracts
### Dune
| Contract | Address | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| USDC.e (Bridged USDC) | [`0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`](https://polygonscan.com/address/0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) | Collateral token used for all Polymarket trading (6 decimals) |
[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:
## Wallet Factory Contracts
| 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) |
| 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 |
### 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.
## 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 |
## Dashboards
***
Third-party blockchain analytics platforms that aggregate and visualize Polymarket data:
## Liquidity
<CardGroup cols={4}>
<Card title="Blockworks" img="https://pbs.twimg.com/profile_images/1651677302634483712/7s2FxV2K_400x400.jpg" href="https://blockworks.com/analytics/polymarket" />
| Contract | Address | Description |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| Uniswap v3 USDC.e/USDC Pool | [`0xd36ec33c8bed5a9f7b6630855f1533455b98a418`](https://polygonscan.com/address/0xd36ec33c8bed5a9f7b6630855f1533455b98a418) | Used for USDC.e ↔ USDC conversion during withdrawals |
<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" />
## Source Code
<Card title="DeFiLlama" img="https://pbs.twimg.com/profile_images/1915756547705036800/rAeLzZqs_400x400.jpg" href="https://defillama.com/protocol/polymarket" />
<CardGroup cols={2}>
<Card title="CTF Exchange" icon="github" href="https://github.com/Polymarket/ctf-exchange">
Order matching and settlement contracts
</Card>
<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" />
<Card title="Conditional Tokens" icon="github" href="https://github.com/gnosis/conditional-tokens-contracts">
Gnosis Conditional Token Framework (ERC1155)
</Card>
</CardGroup>
### Community Dashboards
***
Community-created Dune dashboards of Polymarket on-chain analytics:
## Usage in Code
| 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) |
<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",
}
```
</CodeGroup>
+164 -48
View File
@@ -2,76 +2,95 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Builder Program Introduction
# Builder Program
> Learn about Polymarket's Builder Program and how to integrate
> Build applications that route orders through Polymarket
## What is a Builder?
A "builder" is a person, group, or organization that routes orders from their users to Polymarket.
If you've created a platform that allows users to trade on Polymarket via your system, this program is for you.
***
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={3}>
<Card title="Relayer Access" icon="gas-pump">
All onchain operations are gasless through our relayer
<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 credited for orders and compete for weekly rewards on the Builder Leaderboard
</Card>
<Card title="Fee Share" icon="percent">
Earn a share of fees on routed orders
Get credit for orders and compete for grants on the Builder Leaderboard
</Card>
</CardGroup>
### Relayer Access
<Card title="Revenue Share" icon="percent">
Earn a share of fees on orders you route
</Card>
We expose our relayer to builders, providing gasless transactions for users with
Polymarket's Proxy Wallets deployed via [Relayer Client](/developers/builders/relayer-client).
### What You Get
When transactions are routed through proxy wallets, Polymarket pays all gas fees for:
* Deploying Gnosis Safe Wallets or Custom Proxy (Magic Link users) Wallets
* Token approvals (USDC, outcome tokens)
* CTF operations (split, merge, redeem)
* Order execution (via [CLOB API](/developers/CLOB/introduction))
| Benefit | Description |
| ------------------- | ------------------------------------------------------------------------------- |
| **Relayer Access** | Gas-free wallet deployment, approvals, order execution and CTF operations |
| **Volume Tracking** | All orders attributed to your builder profile |
| **Weekly Rewards** | USDC rewards program based on volume (Verified+) |
| **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.
EOA wallets do not have relayer access. Users trading directly from an EOA pay
their own gas fees.
</Warning>
### Trading Attribution
## How It Works
Attach custom headers to orders to identify your builder account:
<Steps>
<Step title="User Places Order">
User places an order through your application.
</Step>
* Orders attributed to your builder account
* Compete on the [Builder Leaderboard](https://builders.polymarket.com/) for weekly rewards
* Track performance via the Data API
* [Leaderboard API](/api-reference/builders/get-aggregated-builder-leaderboard): Get aggregated builder rankings for a time period
* [Volume API](/api-reference/builders/get-daily-builder-volume-time-series): Get daily time-series volume data for trend analysis
<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
1. **Get Builder Credentials**: Generate API keys from your [Builder Profile](/developers/builders/builder-profile)
2. **Configure Order Attribution**: Set up CLOB client to credit trades to your account ([guide](/developers/builders/order-attribution))
3. **Enable Gasless Transactions**: Use the Relayer for gas-free wallet deployment and trading ([guide](/developers/builders/relayer-client))
<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>
<Tip>
See [Example Apps](/developers/builders/examples) for complete Next.js reference implementations.
</Tip>
<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 & Libraries
<CardGroup cols={3}>
<CardGroup cols={2}>
<Card title="CLOB Client (TypeScript)" icon="github" href="https://github.com/Polymarket/clob-client">
Place orders with builder attribution
</Card>
@@ -80,16 +99,16 @@ Attach custom headers to orders to identify your builder account:
Place orders with builder attribution
</Card>
<Card title="CLOB Client (Rust)" icon="github" href="https://github.com/Polymarket/rs-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 for your users
Gasless onchain transactions
</Card>
<Card title="Relayer Client (Python)" icon="github" href="https://github.com/Polymarket/py-builder-relayer-client">
Gasless onchain transactions for your users
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">
@@ -100,3 +119,100 @@ Attach custom headers to orders to identify your builder account:
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>
+179 -37
View File
@@ -2,75 +2,217 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Builder Profile & Keys
# Builder Program
> Learn how to access your builder profile and obtain API credentials
> Build applications that route orders through Polymarket
## Accessing Your Builder Profile
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="Direct Link" icon="link">
Go to [polymarket.com/settings?tab=builder](https://polymarket.com/settings?tab=builder)
<Card title="Gasless Transactions" icon="gas-pump">
All onchain operations are gas-free through our relayer
</Card>
<Card title="From Profile Menu" icon="user">
Click your profile image and Select "Builders"
<Card title="Order Attribution" icon="tag">
Get credit for orders and compete for grants on the Builder Leaderboard
</Card>
</CardGroup>
***
<Card title="Revenue Share" icon="percent">
Earn a share of fees on orders you route
</Card>
## Builder Profile Settings
### What You Get
<img src="https://mintcdn.com/polymarket-292d1b1b/Quu9lXyXHL-5rjVX/images/builder-profile-image.png?fit=max&auto=format&n=Quu9lXyXHL-5rjVX&q=85&s=67176050b411016e3bfea47bc6fd8fbb" alt="Builder Settings Page" data-og-width="1854" width="1854" data-og-height="1056" height="1056" data-path="images/builder-profile-image.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/Quu9lXyXHL-5rjVX/images/builder-profile-image.png?w=280&fit=max&auto=format&n=Quu9lXyXHL-5rjVX&q=85&s=539b92c0a46959d583d603849459e8df 280w, https://mintcdn.com/polymarket-292d1b1b/Quu9lXyXHL-5rjVX/images/builder-profile-image.png?w=560&fit=max&auto=format&n=Quu9lXyXHL-5rjVX&q=85&s=e7141165754009d3942946b53817feb8 560w, https://mintcdn.com/polymarket-292d1b1b/Quu9lXyXHL-5rjVX/images/builder-profile-image.png?w=840&fit=max&auto=format&n=Quu9lXyXHL-5rjVX&q=85&s=1ec3abc842204033dc99acc2a1fdd9bf 840w, https://mintcdn.com/polymarket-292d1b1b/Quu9lXyXHL-5rjVX/images/builder-profile-image.png?w=1100&fit=max&auto=format&n=Quu9lXyXHL-5rjVX&q=85&s=33d5ca2e18a9267289c1075a0b6d2413 1100w, https://mintcdn.com/polymarket-292d1b1b/Quu9lXyXHL-5rjVX/images/builder-profile-image.png?w=1650&fit=max&auto=format&n=Quu9lXyXHL-5rjVX&q=85&s=5ee84537ae2c108a23f01a19581f2783 1650w, https://mintcdn.com/polymarket-292d1b1b/Quu9lXyXHL-5rjVX/images/builder-profile-image.png?w=2500&fit=max&auto=format&n=Quu9lXyXHL-5rjVX&q=85&s=ed471a4141f2e55fba0f16ad0b70aa38 2500w" />
| Benefit | Description |
| ------------------- | ------------------------------------------------------------------------------- |
| **Relayer Access** | Gas-free wallet deployment, approvals, order execution and CTF operations |
| **Volume Tracking** | All orders attributed to your builder profile |
| **Weekly Rewards** | USDC rewards program based on volume (Verified+) |
| **Leaderboard** | Public visibility on [builders.polymarket.com](https://builders.polymarket.com) |
| **Support** | Telegram channel and engineering support (Verified+) |
### Customize Your Builder Identity
<Warning>
EOA wallets do not have relayer access. Users trading directly from an EOA pay
their own gas fees.
</Warning>
* **Profile Picture**: Upload a custom image for the [Builder Leaderboard](https://builders.polymarket.com/)
* **Builder Name**: Set the name displayed publicly on the leaderboard
## How It Works
### View Your Builder Information
<Steps>
<Step title="User Places Order">
User places an order through your application.
</Step>
* **Builder Address**: Your unique builder address for identification
* **Creation Date**: When your builder account was created
* **Current Tier**: Your rate limit tier (Unverified or Verified)
<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>
## Builder API Keys
<Step title="Trade Execution">
Polymarket matches the order and covers gas fees for onchain operations.
</Step>
Builder API keys are required to access the relayer and for CLOB order attribution.
<Step title="Volume Attribution">
Volume is credited to your builder account.
</Step>
</Steps>
### Creating API Keys
## Getting Started
In the **Builder Keys** section of your profile's **Builder Settings**:
<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>
1. View existing API keys with their creation dates and status
2. Click **"+ Create New"** to generate a new API key
<Step title="Configure Attribution">
Set up your CLOB client to include builder authentication headers with every
order.
</Step>
Each API key includes:
<Step title="Enable Gasless Transactions">
Use the Relayer Client for gas-free wallet deployment and onchain
operations.
</Step>
| Credential | Description |
| ------------ | ------------------------------------ |
| `apiKey` | Your builder API key identifier |
| `secret` | Secret key for signing requests |
| `passphrase` | Additional authentication passphrase |
<Step title="Track Performance">
Monitor your volume on the [Builder
Leaderboard](https://builders.polymarket.com).
</Step>
</Steps>
### Managing API Keys
## SDKs & Libraries
* **Multiple Keys**: Create separate keys for different environments
* **Active Status**: Keys show "ACTIVE" when operational
<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="Order Attribution" icon="tag" href="/developers/builders/order-attribution">
Start attributing customer orders to your account
<Card title="Get API Keys" icon="key" href="/builders/api-keys">
Create and manage your Builder API credentials.
</Card>
<Card title="Builder Leaderboard" icon="trophy" href="https://builders.polymarket.com/">
View your public profile and stats
<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>
+86 -53
View File
@@ -2,14 +2,11 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Builder Tiers
# Tiers
> Permissionless integration with tiered rate limits, rewards, and revenue generating opportunities as you scale
> Rate limits, rewards, and how to upgrade
## Overview
Polymarket Builders lets anyone integrate without approval.
Tiers exist to manage rate limits while rewarding high performing integrations with weekly rewards and revenue sharing opportunities. Higher tiers also unlock engineering support, marketing promotion, and priority access.
The Builder Program uses a tiered system to manage rate limits while rewarding high-performing integrations. Higher tiers unlock increased limits, weekly rewards, revenue sharing, and priority support.
## Feature Definitions
@@ -20,78 +17,90 @@ Tiers exist to manage rate limits while rewarding high performing integrations w
| **Subsidized Transactions** | Gas fees subsidized for Relayer and CLOB operations via Safe/Proxy wallets |
| **Order Attribution** | Orders tracked and attributed to your Builder profile |
| **RevShare Protocol** | Infrastructure allowing Builders to charge fees |
| **Leaderboard Visibility** | Visibility on the [Builder leaderboard](https://builders.polymarket.com/) |
| **Leaderboard Visibility** | Visibility on the [Builder Leaderboard](https://builders.polymarket.com/) |
| **Weekly Rewards** | Weekly USDC rewards program for visible builders based on volume |
| **Grants** | Builder grants subject to approval, awarded based on innovation and impact |
| **Telegram Channel** | Private Builders channel for announcements and support |
| **Badge** | Verified Builder affiliate badge on your Builder profile |
| **Engineering Support** | Direct access to engineering team |
| **Marketing Support** | Promotion via official Polymarket social accounts |
| **Weekly Rewards Boost** | Multiplier on the weekly USDC rewards program for visible builders |
| **Weekly Reward Boosts** | Multiplier on the weekly USDC rewards program for visible builders |
| **Priority Access** | Early access to new features and products |
## Tier Comparison
| Feature | Unverified | Verified | Partner |
| --------------------------- | :--------: | :-------: | :-------: |
| **Daily Relayer Txn Limit** | 100/day | 3,000/day | Unlimited |
| **API Rate Limits** | Standard | Standard | Highest |
| **Subsidized Transactions** | ✅ | ✅ | ✅ |
| **Order Attribution** | ✅ | ✅ | ✅ |
| **RevShare Protocol** | ❌ | ✅ | ✅ |
| **Leaderboard Visibility** | ❌ | ✅ | ✅ |
| **Weekly Rewards** | ❌ | ✅ | ✅ |
| **Telegram Channel** | ❌ | ✅ | ✅ |
| **Badge** | ❌ | ✅ | ✅ |
| **Engineering Support** | ❌ | Standard | Elevated |
| **Marketing Support** | ❌ | Standard | Elevated |
| **Weekly Reward Boosts** | ❌ | ❌ | ✅ |
| **Priority Access** | ❌ | ❌ | ✅ |
***
### Unverified
## Tier Comparison
| Feature | Unverified | Verified | Partner |
| --------------------------- | :-----------------: | :-----------------: | :-----------------: |
| **Daily Relayer Txn Limit** | 100/day | 3,000/day | Unlimited |
| **API Rate Limits** | Standard | Standard | Highest |
| **Subsidized Transactions** | Yes | Yes | Yes |
| **Order Attribution** | Yes | Yes | Yes |
| **RevShare Protocol** | — | Yes | Yes |
| **Leaderboard Visibility** | — | Yes | Yes |
| **Weekly Rewards** | — | Yes | Yes |
| **Grants** | Subject to approval | Subject to approval | Subject to approval |
| **Telegram Channel** | — | Yes | Yes |
| **Badge** | — | Yes | Yes |
| **Engineering Support** | — | Standard | Elevated |
| **Marketing Support** | — | Standard | Elevated |
| **Weekly Reward Boosts** | — | — | Yes |
| **Priority Access** | — | — | Yes |
***
## Unverified
<Card title="100 transactions/day" icon="seedling">
The default tier for all new builders. Create Builder API keys instantly from your Polymarket profile.
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 and click **"+ Create New"** to generate builder API keys
3. Implement [builder signing](/developers/builders/order-attribution); required for Relayer access and CLOB order attribution
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
**Included:**
**What's included:**
* Gasless trading on all CLOB orders through Safe/Proxy wallets
* Gas subsidized on all Relayer transactions through Safe/Proxy wallets up to daily limit
* Order attribution credit to your Builder profile
* Gas subsidized on all Relayer transactions up to daily limit (through Safe/Proxy wallets)
* Order attribution to your builder profile
* Access to all client libraries and documentation
***
### Verified
## Verified
<Card title="3,000 transactions/day" icon="badge-check">
For builders who need higher throughput. Requires manual approval by Polymarket.
For builders who need higher throughput. Requires manual approval.
</Card>
**How to upgrade:**
Contact us with your Builder API Key, use case, expected volume, and relevant info (app, docs, X profile).
Contact us with:
* Your Builder API Key
* Use case description
* Expected volume
* Links to your app, docs, or X profile
**Unlocks over Unverified:**
* 15x daily Relayer transaction limit
* RevShare Protocol Access
* Telegram channel
* Leaderboard visibility
* Eligible for Weekly Rewards Program
* Promotion and verified affiliate badge from @PolymarketBuild
* 30x daily Relayer transaction limit
* RevShare Protocol access
* Leaderboard visibility at [builders.polymarket.com](https://builders.polymarket.com)
* Weekly USDC rewards based on volume
* Private Telegram channel for announcements and support
* Verified affiliate badge and promotion from [@PolymarketBuild](https://x.com/PolymarketBuild)
* Grants (subject to approval)
***
### Partner
## Partner
<Card title="Unlimited transactions/day" icon="handshake">
Enterprise tier for high-volume integrations and strategic partners.
@@ -99,7 +108,7 @@ Contact us with your Builder API Key, use case, expected volume, and relevant in
**How to apply:**
Reach out to discuss partnership opportunities.
Reach out to [builder@polymarket.com](mailto:builder@polymarket.com) to discuss partnership opportunities.
**Unlocks over Verified:**
@@ -112,13 +121,35 @@ Reach out to discuss partnership opportunities.
***
## 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?
* [builder@polymarket.com](mailto:builder@polymarket.com)
***
<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
@@ -128,11 +159,13 @@ Ready to upgrade or have questions?
</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.
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="Can I get a temporary limit increase?">
For special events or product launches, contact [builder@polymarket.com](mailto:builder@polymarket.com)
For special events or product launches, contact [builder@polymarket.com](mailto:builder@polymarket.com).
</Accordion>
</AccordionGroup>
@@ -141,11 +174,11 @@ Ready to upgrade or have questions?
## Next Steps
<CardGroup cols={2}>
<Card title="Get Your Builder Keys" icon="key" href="/developers/builders/builder-profile">
Create Builder API credentials to get started
<Card title="Get API Keys" icon="key" href="/builders/api-keys">
Create your Builder API credentials.
</Card>
<Card title="Use Your Builder Keys" icon="server" href="/developers/builders/relayer-client">
Configure Builder API credentials to attribute orders
<Card title="Attribute Orders" icon="tag" href="/trading/orders/attribution">
Configure your client to credit trades to your account.
</Card>
</CardGroup>
+142 -10
View File
@@ -2,11 +2,125 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Examples
# Builder Program
> Complete Next.js applications demonstrating Polymarket builder integration
> Build applications that route orders through Polymarket
## Overview
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>
<Card title="Revenue Share" icon="percent">
Earn a share of fees on orders you route
</Card>
### 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 |
| **Weekly Rewards** | USDC rewards program based on volume (Verified+) |
| **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 & 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.
@@ -24,9 +138,7 @@ These open-source demo applications show how to integrate Polymarket's CLOB Clie
</Card>
</CardGroup>
***
## Safe Wallet Examples
### Safe Wallet Examples
Deploy Gnosis Safe wallets for your users:
@@ -48,7 +160,7 @@ Deploy Gnosis Safe wallets for your users:
</Card>
</CardGroup>
## Proxy Wallet Examples
### Proxy Wallet Examples
For existing Magic Link users from Polymarket.com:
@@ -58,9 +170,7 @@ For existing Magic Link users from Polymarket.com:
</Card>
</CardGroup>
***
## What Each Demo Covers
### What Each Demo Covers
<Tabs>
<Tab title="Authentication">
@@ -84,3 +194,25 @@ For existing Magic Link users from Polymarket.com:
* 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>
+254 -273
View File
@@ -4,20 +4,19 @@
# Order Attribution
> Learn how to attribute orders to your builder account
> Attribute orders to your builder key for volume credit
## Overview
The [CLOB (Central Limit Order Book)](/developers/CLOB/introduction) is Polymarket's order matching system. Order attribution adds builder authentication headers when placing orders through the CLOB Client, enabling Polymarket to credit trades to your builder account. This allows you to:
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](/developers/builders/builder-profile):
Each builder receives API credentials from their [Builder Profile](https://polymarket.com/settings?tab=builder):
| Credential | Description |
| ------------ | ------------------------------------ |
@@ -26,305 +25,217 @@ Each builder receives API credentials from their [Builder Profile](/developers/b
| `passphrase` | Additional authentication passphrase |
<Warning>
**Security Notice**: Your Builder API keys must be kept secure. Never expose them in client-side code.
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>
***
## Signing Methods
## Remote Signing (Recommended)
<Tabs>
<Tab title="Remote Signing (Recommended)">
Remote signing keeps your credentials secure on a server you control.
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.
**How it works:**
### Server Implementation
1. User signs an order payload
2. Payload is sent to your builder signing server
3. Your server adds builder authentication headers
4. Complete order is sent to the CLOB
Your signing server receives request details and returns the authentication headers:
### Server Implementation
<CodeGroup>
```typescript TypeScript theme={null}
import {
buildHmacSignature,
BuilderApiKeyCreds,
} from "@polymarket/builder-signing-sdk";
Your signing server receives request details and returns the authentication headers. Use the `buildHmacSignature` function from the SDK:
const BUILDER_CREDENTIALS: BuilderApiKeyCreds = {
key: process.env.POLY_BUILDER_API_KEY!,
secret: process.env.POLY_BUILDER_SECRET!,
passphrase: process.env.POLY_BUILDER_PASSPHRASE!,
};
<CodeGroup>
```typescript TypeScript theme={null}
import {
buildHmacSignature,
BuilderApiKeyCreds
} from "@polymarket/builder-signing-sdk";
// 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 BUILDER_CREDENTIALS: BuilderApiKeyCreds = {
key: process.env.POLY_BUILDER_API_KEY!,
secret: process.env.POLY_BUILDER_SECRET!,
passphrase: process.env.POLY_BUILDER_PASSPHRASE!,
};
const signature = buildHmacSignature(
BUILDER_CREDENTIALS.secret,
parseInt(timestamp),
method,
path,
body,
);
// 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(
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,
parseInt(timestamp),
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,
};
return {
"POLY_BUILDER_SIGNATURE": signature,
"POLY_BUILDER_TIMESTAMP": timestamp,
"POLY_BUILDER_API_KEY": BUILDER_CREDENTIALS.key,
"POLY_BUILDER_PASSPHRASE": BUILDER_CREDENTIALS.passphrase,
}
```
```
</CodeGroup>
```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
### Client Configuration
BUILDER_CREDENTIALS = BuilderApiKeyCreds(
key=os.environ["POLY_BUILDER_API_KEY"],
secret=os.environ["POLY_BUILDER_SECRET"],
passphrase=os.environ["POLY_BUILDER_PASSPHRASE"],
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
)
)
# 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
)
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
)
return {
"POLY_BUILDER_SIGNATURE": signature,
"POLY_BUILDER_TIMESTAMP": timestamp,
"POLY_BUILDER_API_KEY": BUILDER_CREDENTIALS.key,
"POLY_BUILDER_PASSPHRASE": BUILDER_CREDENTIALS.passphrase,
}
```
</CodeGroup>
# Orders automatically include builder headers
response = client.create_and_post_order(...)
```
</CodeGroup>
<Warning>
Never commit credentials to version control. Use environment variables or a secrets manager.
</Warning>
***
### Client Configuration
## Local Signing
Point your client to your signing server:
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 } from "@polymarket/builder-signing-sdk";
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import {
BuilderConfig,
BuilderApiKeyCreds,
} from "@polymarket/builder-signing-sdk";
// Point to your signing server
const builderConfig = new BuilderConfig({
remoteBuilderConfig: {
url: "https://your-server.com/sign"
}
});
const builderCreds: BuilderApiKeyCreds = {
key: process.env.POLY_BUILDER_API_KEY!,
secret: process.env.POLY_BUILDER_SECRET!,
passphrase: process.env.POLY_BUILDER_PASSPHRASE!,
};
// Or with optional authorization token
const builderConfigWithAuth = new BuilderConfig({
remoteBuilderConfig: {
url: "https://your-server.com/sign",
token: "your-auth-token"
}
});
const builderConfig = new BuilderConfig({
localBuilderCreds: builderCreds,
});
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer, // ethers v5.x EOA signer
creds, // User's API Credentials
2, // signatureType for the Safe proxy wallet
funderAddress, // Safe proxy wallet address
undefined,
false,
builderConfig
);
const client = new ClobClient(
"https://clob.polymarket.com",
137,
signer,
apiCreds,
2,
funderAddress,
undefined,
false,
builderConfig,
);
// Orders automatically use the signing server
const order = await client.createOrder({
price: 0.40,
side: Side.BUY,
size: 5,
tokenID: "YOUR_TOKEN_ID"
});
// Orders automatically include builder headers
const response = await client.createAndPostOrder(/* ... */);
```
const response = await client.postOrder(order);
```
```python Python theme={null}
import os
from py_clob_client.client import ClobClient
from py_builder_signing_sdk import BuilderConfig, BuilderApiKeyCreds
```python Python theme={null}
from py_clob_client.client import ClobClient
from py_builder_signing_sdk import BuilderConfig, RemoteBuilderConfig
builder_creds = BuilderApiKeyCreds(
key=os.environ["POLY_BUILDER_API_KEY"],
secret=os.environ["POLY_BUILDER_SECRET"],
passphrase=os.environ["POLY_BUILDER_PASSPHRASE"],
)
# Point to your signing server
builder_config = BuilderConfig(
remote_builder_config=RemoteBuilderConfig(
url="https://your-server.com/sign"
)
)
builder_config = BuilderConfig(
local_builder_creds=builder_creds,
)
# Or with optional authorization token
builder_config_with_auth = BuilderConfig(
remote_builder_config=RemoteBuilderConfig(
url="https://your-server.com/sign",
token="your-auth-token"
)
)
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
)
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=private_key,
creds=creds, # User's API Credentials
signature_type=2, # signatureType for the Safe proxy wallet
funder=funder_address, # Safe proxy wallet address
builder_config=builder_config
)
# Orders automatically use the signing server
order = client.create_order({
"price": 0.40,
"side": "BUY",
"size": 5,
"token_id": "YOUR_TOKEN_ID"
})
response = client.post_order(order)
```
</CodeGroup>
### Troubleshooting
<AccordionGroup>
<Accordion title="Invalid Signature Errors">
**Error:** Client receives invalid signature errors
**Solution:**
1. Verify the request body is passed correctly as JSON
2. Check that `path`, `body`, and `method` match what the client sends
3. Ensure your server and client use the same Builder API credentials
</Accordion>
<Accordion title="Missing Credentials">
**Error:** `Builder credentials not configured` or undefined values
**Solution:** Ensure your environment variables are set:
* `POLY_BUILDER_API_KEY`
* `POLY_BUILDER_SECRET`
* `POLY_BUILDER_PASSPHRASE`
</Accordion>
</AccordionGroup>
</Tab>
<Tab title="Local Signing">
Sign orders locally when you control the entire order placement flow.
**How it works:**
1. Your system creates and signs orders on behalf of users
2. Your system uses Builder API credentials locally to add headers
3. Complete signed order is sent directly to the CLOB
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
import { BuilderConfig, BuilderApiKeyCreds } from "@polymarket/builder-signing-sdk";
// Configure with local builder credentials
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, // ethers v5.x EOA signer
creds, // User's API Credentials
2, // signatureType for the Safe proxy wallet
funderAddress, // Safe proxy wallet address
undefined,
false,
builderConfig
);
// Orders automatically include builder headers
const order = await client.createOrder({
price: 0.40,
side: Side.BUY,
size: 5,
tokenID: "YOUR_TOKEN_ID"
});
const response = await client.postOrder(order);
```
```python Python theme={null}
import os
from py_clob_client.client import ClobClient
from py_builder_signing_sdk import BuilderConfig, BuilderApiKeyCreds
# Configure with local builder credentials
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=creds, # User's API Credentials
signature_type=2, # signatureType for the Safe proxy wallet
funder=funder_address, # Safe proxy wallet address
builder_config=builder_config
)
# Orders automatically include builder headers
order = client.create_order({
"price": 0.40,
"side": "BUY",
"size": 5,
"token_id": "YOUR_TOKEN_ID"
})
response = client.post_order(order)
```
</CodeGroup>
<Warning>
Never commit credentials to version control. Use environment variables or a secrets manager.
</Warning>
</Tab>
</Tabs>
# Orders automatically include builder headers
response = client.create_and_post_order(...)
```
</CodeGroup>
***
@@ -340,19 +251,89 @@ The SDK automatically generates and attaches these headers to each request:
| `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 must return these headers (see Server Implementation above), and the SDK attaches them to the request.
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..."
)
```
</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()
```
</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="Relayer Client" icon="bolt" href="/developers/builders/relayer-client">
Learn how to configure and use the Relay Client too!
<Card title="Builder Program" icon="hammer" href="/builders/overview">
Learn about the Builder Program tiers and rewards
</Card>
<Card title="CLOB Client Methods" icon="book" href="/developers/CLOB/clients/methods-overview">
Explore the complete CLOB client reference
<Card title="Create Orders" icon="plus" href="/trading/orders/create">
Build, sign, and submit orders
</Card>
</CardGroup>
File diff suppressed because it is too large Load Diff
@@ -2,76 +2,80 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# How to Fetch Markets
# Fetching Markets
<Tip>Both the getEvents and getMarkets are paginated. See [pagination section](#pagination) for details.</Tip>
This guide covers the three recommended approaches for fetching market data from the Gamma API, each optimized for different use cases.
> Three strategies for discovering and querying markets
## Overview
<Tip>
Both the events and markets endpoints are paginated. See
[pagination](#pagination) for details.
</Tip>
There are three main strategies for retrieving market data:
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
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
***
## 1. Fetch by Slug
## Fetch by Slug
**Use Case:** When you need to retrieve a specific market or event that you already know about.
**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/` or `/market/`:
From any Polymarket URL, the slug is the path segment after `/event/`:
```
https://polymarket.com/event/fed-decision-in-october?tid=1758818660485
Slug: fed-decision-in-october
https://polymarket.com/event/fed-decision-in-october
Slug: fed-decision-in-october
```
### API Endpoints
**For Events:** [GET /events/slug/{slug}](/api-reference/events/list-events)
**For Markets:** [GET /markets/slug/{slug}](/api-reference/markets/list-markets)
### 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"
```
***
## 2. Fetch by Tags
## Fetch by Tags
**Use Case:** When you want to filter markets by category, sport, or topic.
**Use case:** When you want to filter markets by category, sport, or topic.
Tags provide a powerful way to categorize and filter markets. You can discover available tags and then use them to filter your market requests.
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](/api-reference/tags/list-tags)
**General tags:** `GET /tags` (Gamma API)
**Sports Tags & Metadata:** [GET /sports](/api-reference/sports/get-sports-metadata-information)
**Sports tags and metadata:** `GET /sports` (Gamma API)
The `/sports` endpoint returns comprehensive metadata for sports including tag IDs, images, resolution sources, and series information.
The `/sports` endpoint returns metadata for sports including tag IDs, images, resolution sources, and series information.
### Using Tags in Market Requests
### Filter by Tag
Once you have tag IDs, you can use them with the `tag_id` parameter in both markets and events endpoints.
**Markets with Tags:** [GET /markets](/api-reference/markets/list-markets)
**Events with Tags:** [GET /events](/api-reference/events/list-events)
Once you have tag IDs, use the `tag_id` parameter in both events and markets endpoints:
```bash theme={null}
curl "https://gamma-api.polymarket.com/events?tag_id=100381&limit=1&closed=false"
# 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
@@ -81,80 +85,76 @@ 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"
```
***
## 3. Fetch All Active Markets
## Fetch All Active Markets
**Use Case:** When you need to retrieve all available active markets, typically for broader analysis or market discovery.
**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 and work backwards, as events contain their associated markets.
The most efficient approach is to use the events endpoint with `active=true&closed=false`, as events contain their associated markets.
**Events Endpoint:** [GET /events](/api-reference/events/list-events)
**Markets Endpoint:** [GET /markets](/api-reference/markets/list-markets)
```bash theme={null}
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=100"
```
### Key Parameters
* `order=id` - Order by event ID
* `ascending=false` - Get newest events first
* `closed=false` - Only active markets
* `limit` - Control response size
* `offset` - For pagination
### Examples
| 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 |
| `limit` | Results per page |
| `offset` | Number of results to skip for pagination |
```bash theme={null}
curl "https://gamma-api.polymarket.com/events?order=id&ascending=false&closed=false&limit=100"
# Get the highest volume active events
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&order=volume_24hr&ascending=false&limit=100"
```
This approach gives you all active markets ordered from newest to oldest, allowing you to systematically process all available trading opportunities.
***
### Pagination
## Pagination
For large datasets, use pagination with `limit` and `offset` parameters:
* `limit=50` - Return 50 results per page
* `offset=0` - Start from the beginning (increment by limit for subsequent pages)
**Pagination Examples:**
All list endpoints return paginated responses with `limit` and `offset` parameters:
```bash theme={null}
# Page 1: First 50 results (offset=0)
curl "https://gamma-api.polymarket.com/events?order=id&ascending=false&closed=false&limit=50&offset=0"
```
# Page 1: First 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=0"
```bash theme={null}
# Page 2: Next 50 results (offset=50)
curl "https://gamma-api.polymarket.com/events?order=id&ascending=false&closed=false&limit=50&offset=50"
```
# Page 2: Next 50 results
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=50&offset=50"
```bash theme={null}
# Page 3: Next 50 results (offset=100)
curl "https://gamma-api.polymarket.com/events?order=id&ascending=false&closed=false&limit=50&offset=100"
```
```bash theme={null}
# Paginating through markets with tag filtering
curl "https://gamma-api.polymarket.com/markets?tag_id=100381&closed=false&limit=25&offset=0"
```
```bash theme={null}
# Next page of markets with tag filtering
curl "https://gamma-api.polymarket.com/markets?tag_id=100381&closed=false&limit=25&offset=25"
# 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:** Always use the slug method for best performance
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 `closed=false`:** Unless you specifically need historical data
5. **Implement Rate Limiting:** Respect API limits for production applications
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&closed=false`** unless you specifically need historical data
5. **Use the events endpoint** and work backwards — events contain their associated markets, reducing the number of API calls needed
## Related Endpoints
***
* [Get Markets](/developers/gamma-markets-api/get-markets) - Full markets endpoint documentation
* [Get Events](/developers/gamma-markets-api/get-events) - Full events endpoint documentation
* [Search Markets](/developers/gamma-markets-api/get-public-search) - Search functionality
## Next Steps
<CardGroup cols={2}>
<Card title="API Reference" icon="code" href="/api-reference/introduction">
Full endpoint documentation with parameters and response schemas.
</Card>
<Card title="Subgraph" icon="share-nodes" href="/market-data/subgraph">
Query onchain data directly from the Polymarket subgraph.
</Card>
</CardGroup>
@@ -2,26 +2,107 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Gamma Structure
# Markets & Events
Gamma provides some organizational models. These include events, and markets. The most fundamental element is always markets and the other models simply provide additional organization.
> Understanding the fundamental building blocks of Polymarket
# Detail
Every prediction on Polymarket is structured around two core concepts: **markets** and **events**. Understanding how they relate is essential for building on the platform.
1. **Market**
1. Contains data related to a market that is traded on. Maps onto a pair of clob token ids, a market address, a question id and a condition id
<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" data-og-width="1540" width="1540" data-og-height="952" height="952" data-path="images/core-concepts/event-market.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event-market.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=0bd6fa8d9505b0f2fa4626c7d596b0e8 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event-market.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=f6acefe7559f5e48d1903fb772754aeb 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event-market.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=603c382f66e84f9020d45cd43ac59ea4 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event-market.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=eaed4a9b88ff99c795bb27654a1914cd 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event-market.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=020326eff37833ae1111575e85ecf898 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event-market.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=57ce32b2abd1a2f7193a0c9bad064fbc 2500w" />
2. **Event**
1. Contains a set of markets
2. Variants:
1. Event with 1 market (i.e., resulting in an SMP)
2. Event with 2 or more markets (i.e., resulting in an GMP)
<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" data-og-width="1540" width="1540" data-og-height="952" height="952" data-path="images/dark/core-concepts/event-market.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event-market.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=c4da01c8fec2e6cfe7f2d4934200ebf7 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event-market.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=e52eafe9dca3370f2cf9f48aa7a587fa 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event-market.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=420de664532386a57e674c37e2475f45 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event-market.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=e7aeeb9c591df58d3de1d3d3ee9b6aa5 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event-market.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=b68ab7f2f68b3ee6c1670edab68dddd6 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event-market.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=89ae2017bf3ee1eec57ebd4ac4b5cddc 2500w" />
</Frame>
# Example
## Markets
* **\[Event]** Where will Barron Trump attend College?
* **\[Market]** Will Barron attend Georgetown?
* **\[Market]** Will Barron attend NYU?
* **\[Market]** Will Barron attend UPenn?
* **\[Market]** Will Barron attend Harvard?
* **\[Market]** Will Barron attend another college?
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" data-og-width="1540" width="1540" data-og-height="952" height="952" data-path="images/core-concepts/event.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=72a07b6b9d83367b9aa829a60c07f2b3 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=a222505efdc485a3b2410055394109cd 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=1afd89af327cef04f03a0c085a4a0ef5 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=a419c0d09ca0cbb7f870372157c56727 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=19797452df63f42cf2d84e709483a4a2 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/event.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=4643344994e4717bfdc94bad606eda7f 2500w" />
<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" data-og-width="1540" width="1540" data-og-height="952" height="952" data-path="images/dark/core-concepts/event.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=541e0c044f32f667c9c59e31f1572167 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=16e79044e1f4cb99e3c28335308ea821 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=71d440db449638eec0f3b8a5d80bef13 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=25f781834c41ecd4d835e0c209bceb2e 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=1a2120728cf262e68d993a1db44371b1 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/event.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=9ecb8ab37d7fc4460fa07c892ab1978a 2500w" />
</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>
+104 -4
View File
@@ -2,10 +2,110 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# null
# Overview
All market data necessary for market resolution is available on-chain (ie ancillaryData in UMA 00 request), but Polymarket also provides a hosted service, Gamma, that indexes this data and provides additional market metadata (ie categorization, indexed volume, etc). This service is made available through a REST API. For public users, this resource read only and can be used to fetch useful information about markets for things like non-profit research projects, alternative trading interfaces, automated trading systems etc.
> Fetch market data with no authentication required
# Endpoint
All market data is available through public REST endpoints. No API key, no authentication, no wallet required.
[https://gamma-api.polymarket.com](https://gamma-api.polymarket.com)
```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 (`gamma-api.polymarket.com`) — Events, Markets & 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 (`clob.polymarket.com`) — Prices & 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 (`data-api.polymarket.com`) — Positions, Trades & 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>
+116 -122
View File
@@ -2,165 +2,159 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Data Feeds
# Fetching Markets
> Real-time and historical data sources for market makers
> Three strategies for discovering and querying markets
## Overview
<Tip>
Both the events and markets endpoints are paginated. See
[pagination](#pagination) for details.
</Tip>
Market makers need fast, reliable data to price markets and manage inventory. Polymarket provides several data feeds at different latency and detail levels.
There are three main strategies for retrieving market data, each optimized for different use cases:
| Feed | Latency | Use Case | Access |
| --------- | ---------- | ------------------------- | ------ |
| WebSocket | \~100ms | Standard MM operations | Public |
| Gamma API | \~1s | Market metadata, indexing | Public |
| Onchain | Block time | Settlement, resolution | Public |
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
## WebSocket Feeds
***
The WebSocket API provides real-time market data with low latency. This is sufficient for most market making strategies.
## Fetch by Slug
### Connecting
**Use case:** When you need to retrieve a specific market or event that you already know about.
```typescript theme={null}
const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");
Individual markets and events are best fetched using their unique slug identifier. The slug can be found directly in the Polymarket frontend URL.
ws.onopen = () => {
// Subscribe to orderbook updates
ws.send(JSON.stringify({
type: "market",
assets_ids: [tokenId]
}));
};
### How to Extract the Slug
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
// Handle orderbook update
};
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
```
### Available Channels
### Examples
| Channel | Message Types | Documentation |
| -------- | ------------------------------------------ | ----------------------------------------------------------- |
| `market` | `book`, `price_change`, `last_trade_price` | [Market Channel](/developers/CLOB/websocket/market-channel) |
| `user` | Order fills, cancellations | [User Channel](/developers/CLOB/websocket/user-channel) |
```bash theme={null}
# Fetch an event by slug (query parameter)
curl "https://gamma-api.polymarket.com/events?slug=fed-decision-in-october"
### User Channel (Authenticated)
Monitor your order activity in real-time:
```typescript theme={null}
// Requires authentication
const userWs = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/user");
userWs.onopen = () => {
userWs.send(JSON.stringify({
type: "user",
auth: {
apiKey: "your-api-key",
secret: "your-secret",
passphrase: "your-passphrase"
},
markets: [conditionId] // Optional: filter to specific markets
}));
};
userWs.onmessage = (event) => {
const data = JSON.parse(event.data);
// Handle order fills, cancellations, etc.
};
# Or use the path endpoint
curl "https://gamma-api.polymarket.com/events/slug/fed-decision-in-october"
```
See [WebSocket Authentication](/developers/CLOB/websocket/wss-auth) for auth details.
```bash theme={null}
# Fetch a market by slug (query parameter)
curl "https://gamma-api.polymarket.com/markets?slug=fed-decision-in-october"
### Best Practices
1. **Reconnection logic** - Implement automatic reconnection with exponential backoff
2. **Heartbeats** - Respond to ping messages to maintain connection
3. **Local orderbook** - Maintain a local copy and apply incremental updates
4. **Sequence numbers** - Track sequence to detect missed messages
See [WebSocket Overview](/developers/CLOB/websocket/wss-overview) for complete documentation.
## Gamma API
The Gamma API provides market metadata and indexing. Use it for:
* Market titles, slugs, categories
* Event/condition mapping
* Volume and liquidity data
* Outcome token metadata
### Get Markets
```typescript theme={null}
const response = await fetch(
"https://gamma-api.polymarket.com/markets?active=true"
);
const markets = await response.json();
# Or use the path endpoint
curl "https://gamma-api.polymarket.com/markets/slug/fed-decision-in-october"
```
### Get Events
***
```typescript theme={null}
const response = await fetch(
"https://gamma-api.polymarket.com/events?slug=us-presidential-election"
);
const event = await response.json();
## 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"
```
### Key Fields for MMs
### Additional Tag Filtering
| Field | Description |
| --------------- | ------------------------ |
| `conditionId` | Unique market identifier |
| `clobTokenIds` | Outcome token IDs |
| `outcomes` | Outcome names |
| `outcomePrices` | Current outcome prices |
| `volume` | Trading volume |
| `liquidity` | Current liquidity |
You can also:
See [Gamma API Overview](/developers/gamma-markets-api/overview) for complete documentation.
* Use `related_tags=true` to include related tag markets
* Exclude specific tags with `exclude_tag_id`
## Onchain Data
```bash theme={null}
# Include related tags
curl "https://gamma-api.polymarket.com/events?tag_id=100381&related_tags=true&active=true&closed=false"
```
For settlement, resolution, and position tracking, market makers may query onchain data directly.
***
### Data Sources
## Fetch All Active Markets
| Data | Source | Use Case |
| -------------------- | ------------------- | ---------------------------- |
| Token balances | ERC1155 `balanceOf` | Position tracking |
| Resolution | UMA Oracle events | Pre-resolution risk modeling |
| Condition resolution | CTF contract | Post-resolution redemption |
**Use case:** When you need to retrieve all available active markets, typically for broader analysis or market discovery.
### RPC Providers
The most efficient approach is to use the events endpoint with `active=true&closed=false`, as events contain their associated markets.
Common providers for Polygon:
```bash theme={null}
curl "https://gamma-api.polymarket.com/events?active=true&closed=false&limit=100"
```
* Alchemy
* QuickNode
* Infura
### Key Parameters
### UMA Oracle
| 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 |
| `limit` | Results per page |
| `offset` | Number of results to skip for pagination |
Markets are resolved via UMA's Optimistic Oracle. Monitor resolution events for risk management.
```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"
```
See [Resolution](/developers/resolution/UMA) for details on the resolution process.
***
## Related Documentation
## Pagination
<CardGroup cols={3}>
<Card title="WebSocket Overview" icon="plug" href="/developers/CLOB/websocket/wss-overview">
Complete WebSocket documentation
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&closed=false`** unless you specifically 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>
<Card title="Gamma API" icon="database" href="/developers/gamma-markets-api/overview">
Market metadata and indexing
</Card>
<Card title="Resolution" icon="gavel" href="/developers/resolution/UMA">
UMA Oracle resolution process
<Card title="Subgraph" icon="share-nodes" href="/market-data/subgraph">
Query onchain data directly from the Polymarket subgraph.
</Card>
</CardGroup>
+61 -54
View File
@@ -2,74 +2,81 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Market Maker Introduction
# Overview
> Overview of market making on Polymarket and available tools for liquidity providers
> Market making on Polymarket
## What is a Market Maker?
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.
A Market Maker (MM) on Polymarket is a sophisticated 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.
Market makers are essential to Polymarket's ecosystem:
<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>
* **Provide liquidity** across all markets
* **Tighten spreads** for better user experience
* **Enable price discovery** through continuous quoting
* **Absorb trading flow** from retail and institutional users
**Not a Market Maker?** If you're building an application that routes orders for your
users, see the [Builders Program](/developers/builders/builder-intro) instead. Builders
get access to gasless transactions via the Relayer Client.
***
## Getting Started
To become a market maker on Polymarket:
<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>
1. **Complete setup** - Deploy wallets, fund with USDCe, set token approvals
2. **Connect to data feeds** - WebSocket for orderbook, RTDS for low-latency data
3. **Start quoting** - Post orders via CLOB REST API
<Step title="Connect to Data Feeds">
WebSocket for real-time orderbook updates, Gamma API for market metadata.
See [Market Data](/market-data/overview).
</Step>
## Available Tools
<Step title="Start Quoting">
Post orders via the CLOB REST API. See [Trading ](/market-makers/trading).
</Step>
</Steps>
### By Action Type
<CardGroup cols={2}>
<Card title="Setup" icon="gear" href="/developers/market-makers/setup">
Deposits, token approvals, wallet deployment, API keys
</Card>
<Card title="Trading" icon="chart-line" href="/developers/market-makers/trading">
CLOB order entry, order types, quoting best practices
</Card>
<Card title="Data Feeds" icon="database" href="/developers/market-makers/data-feeds">
WebSocket, RTDS, Gamma API, on-chain data
</Card>
<Card title="Inventory Management" icon="boxes-stacked" href="/developers/market-makers/inventory">
Split, merge, and redeem outcome tokens
</Card>
<Card title="Liquidity Rewards" icon="gift" href="/developers/market-makers/liquidity-rewards">
Earn rewards for providing liquidity
</Card>
<Card title="Maker Rebates Program" icon="gift" href="/developers/market-makers/maker-rebates-program">
Earn rebates for providing liquidity
</Card>
</CardGroup>
***
## Quick Reference
| Action | Tool | Documentation |
| --------------------- | -------------- | ------------------------------------------------------------- |
| Deposit USDCe | Bridge API | [Bridge Overview](/developers/misc-endpoints/bridge-overview) |
| Approve tokens | Relayer Client | [Setup Guide](/developers/market-makers/setup) |
| Post limit orders | CLOB REST API | [CLOB Client](/developers/CLOB/clients/methods-l2) |
| Monitor orderbook | WebSocket | [WebSocket Overview](/developers/CLOB/websocket/wss-overview) |
| Low-latency data | RTDS | [Data Feeds](/developers/market-makers/data-feeds) |
| Split USDCe to tokens | CTF / Relayer | [Inventory](/developers/market-makers/inventory) |
| Merge tokens to USDCe | CTF / Relayer | [Inventory](/developers/market-makers/inventory) |
| 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's 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
-247
View File
@@ -1,247 +0,0 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Inventory Management
> Split, merge, and redeem outcome tokens for market making
## Overview
Market makers need to manage their inventory of outcome tokens. This involves:
1. **Splitting** USDCe into YES/NO tokens to have inventory to quote
2. **Merging** tokens back to USDCe to reduce exposure
3. **Redeeming** winning tokens after market resolution
All these operations use the Conditional Token Framework (CTF) contract, typically via the Relayer Client for gasless execution.
<Note>
These examples assume you have initialized a RelayClient. See [Setup](/developers/market-makers/setup) for client initialization.
</Note>
## Splitting USDCe into Tokens
Split 1 USDCe into 1 YES + 1 NO token. This creates inventory for quoting both sides.
### Via Relayer Client (Recommended)
```typescript theme={null}
import { ethers } from "ethers";
import { Interface } from "ethers/lib/utils";
import { RelayClient, Transaction } from "@polymarket/builder-relayer-client";
const CTF_ADDRESS = "0x4d97dcd97ec945f40cf65f87097ace5ea0476045";
const USDCe_ADDRESS = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const ctfInterface = new Interface([
"function splitPosition(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] partition, uint amount)"
]);
// Split $1000 USDCe into YES/NO tokens
const amount = ethers.utils.parseUnits("1000", 6); // USDCe has 6 decimals
const splitTx: Transaction = {
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("splitPosition", [
USDCe_ADDRESS, // collateralToken
ethers.constants.HashZero, // parentCollectionId (null for Polymarket)
conditionId, // conditionId from market
[1, 2], // partition: [YES, NO]
amount
]),
value: "0"
};
const response = await client.execute([splitTx], "Split USDCe into tokens");
const result = await response.wait();
console.log("Split completed:", result?.transactionHash);
```
### Result
After splitting 1000 USDCe:
* Receive 1000 YES tokens
* Receive 1000 NO tokens
* USDCe balance decreases by 1000
## Merging Tokens to USDCe
Merge equal amounts of YES + NO tokens back into USDCe. Useful for:
* Reducing inventory
* Exiting a market
* Converting profits to USDCe
### Via Relayer Client
```typescript theme={null}
const ctfInterface = new Interface([
"function mergePositions(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] partition, uint amount)"
]);
// Merge 500 YES + 500 NO back to 500 USDCe
const amount = ethers.utils.parseUnits("500", 6);
const mergeTx: Transaction = {
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("mergePositions", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionId,
[1, 2],
amount
]),
value: "0"
};
const response = await client.execute([mergeTx], "Merge tokens to USDCe");
await response.wait();
```
### Result
After merging 500 of each:
* YES tokens decrease by 500
* NO tokens decrease by 500
* USDCe balance increases by 500
## Redeeming After Resolution
After a market resolves, redeem winning tokens for USDCe.
### Check Resolution Status
```typescript theme={null}
// Via CLOB API
const market = await clobClient.getMarket(conditionId);
if (market.closed) {
// Market is resolved
const winningToken = market.tokens.find(t => t.winner);
console.log("Winning outcome:", winningToken?.outcome);
}
```
### Redeem Winning Tokens
```typescript theme={null}
const ctfInterface = new Interface([
"function redeemPositions(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] indexSets)"
]);
const redeemTx: Transaction = {
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("redeemPositions", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionId,
[1, 2] // Redeem both YES and NO (only winners pay out)
]),
value: "0"
};
const response = await client.execute([redeemTx], "Redeem winning tokens");
await response.wait();
```
### Payout
* If YES wins: Each YES token redeems for \$1 USDCe
* If NO wins: Each NO token redeems for \$1 USDCe
* Losing tokens are worthless (redeem for \$0)
## Negative Risk Markets
Multi-outcome markets use the Negative Risk CTF Exchange. The split/merge process is similar but uses different contract addresses.
```typescript theme={null}
const NEG_RISK_ADAPTER = "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296";
const NEG_RISK_CTF_EXCHANGE = "0xC5d563A36AE78145C45a50134d48A1215220f80a";
```
See [Negative Risk Overview](/developers/neg-risk/overview) for details.
## Inventory Strategies
### Pre-market Preparation
Before quoting a market:
1. Check market metadata via Gamma API
2. Split sufficient USDCe to cover expected quoting size
3. Set token approvals if not already done
### During Trading
Monitor inventory and adjust:
* Skew quotes when inventory is imbalanced
* Merge excess tokens to free up capital
* Split more when inventory runs low
### Post-Resolution
After market closes:
1. Cancel all open orders
2. Wait for resolution
3. Redeem winning tokens
4. Merge any remaining pairs
## Batch Operations
For efficiency, batch multiple operations:
```typescript theme={null}
const transactions: Transaction[] = [
// Split on Market A
{
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("splitPosition", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionIdA,
[1, 2],
ethers.utils.parseUnits("1000", 6)
]),
value: "0"
},
// Split on Market B
{
to: CTF_ADDRESS,
data: ctfInterface.encodeFunctionData("splitPosition", [
USDCe_ADDRESS,
ethers.constants.HashZero,
conditionIdB,
[1, 2],
ethers.utils.parseUnits("1000", 6)
]),
value: "0"
}
];
const response = await client.execute(transactions, "Batch inventory setup");
await response.wait();
```
## Related Documentation
<CardGroup cols={2}>
<Card title="CTF Overview" icon="coins" href="/developers/CTF/overview">
Conditional Token Framework basics
</Card>
<Card title="Split Positions" icon="code-branch" href="/developers/CTF/split">
Detailed split documentation
</Card>
<Card title="Merge Positions" icon="code-merge" href="/developers/CTF/merge">
Detailed merge documentation
</Card>
<Card title="Relayer Client" icon="paper-plane" href="/developers/builders/relayer-client">
Gasless transaction execution
</Card>
</CardGroup>
@@ -1,126 +0,0 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Liquidity Rewards
> Polymarket provides incentives aimed at catalyzing the supply and demand side of the marketplace. Specifically there is a public liquidity rewards program as well as one-off public pnl/volume competitions.
## Overview
By posting resting limit orders, liquidity providers (makers) are automatically eligible for Polymarket's incentive program. The overall goal of this program is to catalyze a healthy, liquid marketplace. We can further define this as creating incentives that:
* Catalyze liquidity across all markets
* Encourage liquidity throughout a market's entire lifecycle
* Motivate passive, balanced quoting tight to a market's mid-point
* Encourages trading activity
* Discourages blatantly exploitative behaviors
This program is heavily inspired by dYdX's liquidity provider rewards which you can read more about [here](https://www.dydx.foundation/blog/liquidity-provider-rewards). In fact, the incentive methodology is essentially a copy of dYdX's successful methodology but with some adjustments including specific adaptations for binary contract markets with distinct books, no staking mechanic a slightly modified order utility-relative depth function and reward amounts isolated per market. Rewards are distributed directly to the maker's addresses daily at midnight UTC.
## Methodology
Polymarket liquidity providers will be rewarded based on a formula that rewards participation in markets (complementary consideration!), boosts two-sided depth (single-sided orders still score), and spread (vs. mid-market, adjusted for the size cutoff!). Each market still configure a max spread and min size cutoff within which orders are considered the average of rewards earned is determined by the relative share of each participant's Q<sub>n</sub> in market m.
| Variable | Description |
| -------------- | ---------------------------------------------------------------- |
| \$ | order position scoring function |
| v | max spread from midpoint (in cents) |
| s | spread from size-cutoff-adjusted midpoint |
| b | in-game multiplier |
| m | market |
| m' | market complement (i.e NO if m = YES) |
| n | trader index |
| u | sample index |
| c | scaling factor (currently 3.0 on all markets) |
| Q<sub>ne</sub> | point total for book one for a sample |
| Q<sub>no</sub> | point total for book two for a sample |
| Spread% | distance from midpoint (bps or relative) for order n in market m |
| BidSize | share-denominated quantity of bid |
| AskSize | share-denominated quantity of ask |
## Equations
**Equation 1:**
$S(v,s)= (\frac{v-s}{v})^2 \cdot b$
**Equation 2:**
$Q_{one}= S(v,Spread_{m_1}) \cdot BidSize_{m_1} + S(v,Spread_{m_2}) \cdot BidSize_{m_2} + \dots $
$ + S(v, Spread_{m^\prime_1}) \cdot AskSize_{m^\prime_1} + S(v, Spread_{m^\prime_2}) \cdot AskSize_{m^\prime_2}$
**Equation 3:**
$Q_{two}= S(v,Spread_{m_1}) \cdot AskSize_{m_1} + S(v,Spread_{m_2}) \cdot AskSize_{m_2} + \dots $
$ + S(v, Spread_{m^\prime_1}) \cdot BidSize_{m^\prime_1} + S(v, Spread_{m^\prime_2}) \cdot BidSize_{m^\prime_2}$
**Equation 4:**
**Equation 4a:**
If midpoint is in range \[0.10,0.90] allow single sided liq to score:
$Q_{\min} = \max(\min({Q_{one}, Q_{two}}), \max(Q_{one}/c, Q_{two}/c))$
**Equation 4b:**
If midpoint is in either range \[0,0.10) or (.90,1.0] require liq to be double sided to score:
$Q_{\min} = \min({Q_{one}, Q_{two}})$
**Equation 5:**
$Q_{normal} = \frac{Q_{min}}{\sum_{n=1}^{N}{(Q_{min})_n}}$
**Equation 6:**
$Q_{epoch} = \sum_{u=1}^{10,080}{(Q_{normal})_u}$
**Equation 7:**
$Q_{final}=\frac{Q_{epoch}}{\sum_{n=1}^{N}{(Q_{epoch})_n}}$
## Steps
1. Quadratic scoring rule for an order based on position between the adjusted midpoint and the minimum qualifying spread
2. Calculate first market side score. Assume a trader has the following open orders:
* 100Q bid on m @0.49 (adjusted midpoint is 0.50 then spread of this order is 0.01 or 1c)
* 200Q bid on m @0.48
* 100Q ask on m' @0.51
and assume an adjusted market midpoint of 0.50 and maxSpread config of 3c for both m and m'. Then the trader's score is:
$$
Q_{ne} = \left( \frac{(3-1)}{3} \right)^2 \cdot 100 + \left( \frac{(3-2)}{3} \right)^2 \cdot 200 + \left( \frac{(3-1)}{3} \right)^2 \cdot 100
$$
$Q_{ne}$ is calculated every minute using random sampling
3. Calculate second market side score. Assume a trader has the following open orders:
* 100Q bid on m @0.485
* 100Q bid on m' @0.48
* 200Q ask on m' @0.505
and assume an adjusted market midpoint of 0.50 and maxSpread config of 3c for both m and m'. Then the trader's score is:
$$
Q_{no} = \left( \frac{(3-1.5)}{3} \right)^2 \cdot 100 + \left( \frac{(3-2)}{3} \right)^2 \cdot 100 + \left( \frac{(3-.5)}{3} \right)^2 \cdot 200
$$
$Q_{no}$ is calculated every minute using random sampling
4. Boosts 2-sided liquidity by taking the minimum of $Q_{ne}$ and $Q_{no}$, and rewards 1-side liquidity at a reduced rate (divided by c)
Calculated every minute
5. $Q_{normal}$ is the $Q_{min}$ of a market maker divided by the sum of all the $Q_{min}$ of other market makers in a given sample
6. $Q_{epoch}$ is the sum of all $Q_{normal}$ for a trader in a given epoch
7. $Q_{final}$ normalizes $Q_{epoch}$ by dividing it by the sum of all other market maker's $Q_{epoch}$ in a given epoch this value is multiplied by the rewards available for the market to get a trader's reward
<Tip>Both min\_incentive\_size and max\_incentive\_spread can be fetched alongside full market objects via both the CLOB API and Markets API. Reward allocations for an epoch can be fetched via the Markets API. </Tip>
@@ -1,248 +0,0 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Maker Rebates Program
> Technical guide for handling taker fees and earning maker rebates on Polymarket
Polymarket has enabled taker fees on **15-minute crypto markets**, **5-minute crypto markets**, **NCAAB (college basketball)**, and **Serie A** markets.
These fees fund a Maker Rebates program that pays daily USDC rebates to liquidity providers.
<Note>
Starting **Wednesday, February 18th, 2026 at midnight (UTC)**, taker fees and maker rebates will apply to all **new** NCAAB and Serie A markets created after that time. Existing markets are not affected. The first payout will be on February 19th at midnight (UTC).
</Note>
## Fee Handling by Implementation Type
### Option 1: Official CLOB Clients (Recommended)
The official CLOB clients **automatically handle fees** for you
<Card title="TypeScript Client" icon="js" href="https://github.com/Polymarket/clob-client">
npm install @polymarket/clob-client\@latest
</Card>
<CardGroup cols={2}>
<Card title="Python Client" icon="python" href="https://github.com/Polymarket/py-clob-client">
pip install --upgrade py-clob-client
</Card>
<Card title="Rust Client" icon="rust" href="https://github.com/Polymarket/rs-clob-client">
cargo add polymarket-client-sdk
</Card>
</CardGroup>
**What the client does automatically:**
1. Fetches the fee rate for the market's token ID
2. Includes `feeRateBps` in the order structure
3. Signs the order with the fee rate included
**You don't need to do anything extra**. Your orders will work on fee-enabled markets.
***
### Option 2: REST API / Custom Implementations
If you're calling the REST API directly or building your own order signing, you must manually include the fee rate in your signed order payload.
#### Step 1: Fetch the Fee Rate
Query the fee rate for the token ID before creating your order:
```bash theme={null}
GET https://clob.polymarket.com/fee-rate?token_id={token_id}
```
**Response:**
```json theme={null}
{
"fee_rate_bps": 1000
}
```
* **Fee-enabled markets** return a value like `1000`
* **Fee-free markets** return `0`
#### Step 2: Include in Your Signed Order
Add the `feeRateBps` field to your order object. This value is part of the signed payload, the CLOB validates your signature against it.
```json theme={null}
{
"salt": "12345",
"maker": "0x...",
"signer": "0x...",
"taker": "0x...",
"tokenId": "71321045679252212594626385532706912750332728571942532289631379312455583992563",
"makerAmount": "50000000",
"takerAmount": "100000000",
"expiration": "0",
"nonce": "0",
"feeRateBps": "1000",
"side": "0",
"signatureType": 2,
"signature": "0x..."
}
```
#### Step 3: Sign and Submit
1. Include `feeRateBps` in the order object **before signing**
2. Sign the complete order
3. POST to `/order` endpoint
<Note>
**Important:** Always fetch `fee_rate_bps` dynamically, do not hardcode. The fee rate varies by market type and may change over time. You only need to pass `feeRateBps`
</Note>
See the [Create Order documentation](/developers/CLOB/orders/create-order) for full signing details.
***
## Fee Behavior
Fees are calculated using the following formula:
```text theme={null}
fee = C × p × feeRate × (p × (1 - p))^exponent
```
Where **C** = number of shares traded and **p** = price of the shares. The fee parameters differ by market type:
| Parameter | Sports (NCAAB, Serie A) | 5-Min & 15-Min Crypto |
| -------------- | ----------------------- | --------------------- |
| Fee Rate | 0.0175 | 0.25 |
| Exponent | 1 | 2 |
| Maker Rebate % | 25% | 20% |
Taker fees are calculated in USDC and vary based on the share price. However, fees are collected in shares on buy orders and USDC on sell orders.
The effective rate **peaks at 50%** probability and decreases symmetrically toward the extremes.
<img src="https://mintcdn.com/polymarket-292d1b1b/12mKTb6PQ_jJnYbI/polymarket-learn/media/fee_image_review.png?fit=max&auto=format&n=12mKTb6PQ_jJnYbI&q=85&s=9e5b1d1a262fb6c787af5b6a0fa4d6c2" alt="Fee Curves" data-og-width="1484" width="1484" data-og-height="882" height="882" data-path="polymarket-learn/media/fee_image_review.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/12mKTb6PQ_jJnYbI/polymarket-learn/media/fee_image_review.png?w=280&fit=max&auto=format&n=12mKTb6PQ_jJnYbI&q=85&s=111b6dc97e2b301501c02e2df5e3df35 280w, https://mintcdn.com/polymarket-292d1b1b/12mKTb6PQ_jJnYbI/polymarket-learn/media/fee_image_review.png?w=560&fit=max&auto=format&n=12mKTb6PQ_jJnYbI&q=85&s=063f99ef8ec728e399a7cd0b27e704a0 560w, https://mintcdn.com/polymarket-292d1b1b/12mKTb6PQ_jJnYbI/polymarket-learn/media/fee_image_review.png?w=840&fit=max&auto=format&n=12mKTb6PQ_jJnYbI&q=85&s=c7d74e4ca10bd953f1f08a9851017f3c 840w, https://mintcdn.com/polymarket-292d1b1b/12mKTb6PQ_jJnYbI/polymarket-learn/media/fee_image_review.png?w=1100&fit=max&auto=format&n=12mKTb6PQ_jJnYbI&q=85&s=bc3dbf551ae32d6c4e7d85558831fb1f 1100w, https://mintcdn.com/polymarket-292d1b1b/12mKTb6PQ_jJnYbI/polymarket-learn/media/fee_image_review.png?w=1650&fit=max&auto=format&n=12mKTb6PQ_jJnYbI&q=85&s=d082a6e2029bc3f4797d758d689e2c37 1650w, https://mintcdn.com/polymarket-292d1b1b/12mKTb6PQ_jJnYbI/polymarket-learn/media/fee_image_review.png?w=2500&fit=max&auto=format&n=12mKTb6PQ_jJnYbI&q=85&s=417d0c9a66a64d31588d15c908cebf39 2500w" />
### Fee Table (100 shares)
<Tabs>
<Tab title="5-Min & 15-Min Crypto">
| Price | Trade Value | Fee (USDC) | Effective Rate |
| ------ | ----------- | ---------- | -------------- |
| \$0.01 | \$1 | \$0.00 | 0.00% |
| \$0.05 | \$5 | \$0.003 | 0.06% |
| \$0.10 | \$10 | \$0.02 | 0.20% |
| \$0.15 | \$15 | \$0.06 | 0.41% |
| \$0.20 | \$20 | \$0.13 | 0.64% |
| \$0.25 | \$25 | \$0.22 | 0.88% |
| \$0.30 | \$30 | \$0.33 | 1.10% |
| \$0.35 | \$35 | \$0.45 | 1.29% |
| \$0.40 | \$40 | \$0.58 | 1.44% |
| \$0.45 | \$45 | \$0.69 | 1.53% |
| \$0.50 | \$50 | \$0.78 | **1.56%** |
| \$0.55 | \$55 | \$0.84 | 1.53% |
| \$0.60 | \$60 | \$0.86 | 1.44% |
| \$0.65 | \$65 | \$0.84 | 1.29% |
| \$0.70 | \$70 | \$0.77 | 1.10% |
| \$0.75 | \$75 | \$0.66 | 0.88% |
| \$0.80 | \$80 | \$0.51 | 0.64% |
| \$0.85 | \$85 | \$0.35 | 0.41% |
| \$0.90 | \$90 | \$0.18 | 0.20% |
| \$0.95 | \$95 | \$0.05 | 0.06% |
| \$0.99 | \$99 | \$0.00 | 0.00% |
The maximum effective fee rate is **1.56%** at 50% probability. Fees decrease symmetrically toward both extremes.
</Tab>
<Tab title="Sports (NCAAB, Serie A)">
| Price | Trade Value | Fee (USDC) | Effective Rate |
| ------ | ----------- | ---------- | -------------- |
| \$0.01 | \$1 | \$0.00 | 0.02% |
| \$0.05 | \$5 | \$0.00 | 0.08% |
| \$0.10 | \$10 | \$0.02 | 0.16% |
| \$0.15 | \$15 | \$0.03 | 0.22% |
| \$0.20 | \$20 | \$0.06 | 0.28% |
| \$0.25 | \$25 | \$0.08 | 0.33% |
| \$0.30 | \$30 | \$0.11 | 0.37% |
| \$0.35 | \$35 | \$0.14 | 0.40% |
| \$0.40 | \$40 | \$0.17 | 0.42% |
| \$0.45 | \$45 | \$0.19 | 0.43% |
| \$0.50 | \$50 | \$0.22 | **0.44%** |
| \$0.55 | \$55 | \$0.24 | 0.43% |
| \$0.60 | \$60 | \$0.25 | 0.42% |
| \$0.65 | \$65 | \$0.26 | 0.40% |
| \$0.70 | \$70 | \$0.26 | 0.37% |
| \$0.75 | \$75 | \$0.25 | 0.33% |
| \$0.80 | \$80 | \$0.22 | 0.28% |
| \$0.85 | \$85 | \$0.19 | 0.22% |
| \$0.90 | \$90 | \$0.14 | 0.16% |
| \$0.95 | \$95 | \$0.08 | 0.08% |
| \$0.99 | \$99 | \$0.02 | 0.02% |
The maximum effective fee rate is **0.44%** at 50% probability. Fees decrease symmetrically toward both extremes.
</Tab>
</Tabs>
***
## Maker Rebates
Your rebate for each market:
```text theme={null}
fee_equivalent = C × p × feeRate × (p × (1 - p))^exponent
rebate = (your_fee_equivalent / total_fee_equivalent) * rebate_pool
```
### How Rebates Work
* **Eligibility:** Your orders must add liquidity (maker orders) and get filled
* **Calculation:** Proportional to your share of executed maker volume in each eligible market. Totals are calculated per market, so you only compete with other makers in the same market
* **Fee collection:** Fees are calculated in USDC but collected in shares on buy orders and USDC on sell orders
* **Payment:** Daily in USDC, paid directly to your wallet
### Rebate Pool
Each market's rebate pool is funded by taker fees collected in that market. The payout percentage is subject to change:
| Market Type | Period | Maker Rebate | Distribution Method |
| ----------------------- | ------------- | ------------ | ------------------- |
| 15-Min Crypto | Jan 19, 2026+ | 20% | Fee-curve weighted |
| 5-Min Crypto | Feb 12, 2026+ | 20% | Fee-curve weighted |
| Sports (NCAAB, Serie A) | Feb 18, 2026+ | 25% | Fee-curve weighted |
The rebate percentage is at the sole discretion of Polymarket and may change over time.
***
## Which Markets Have Fees?
The following market types have fees enabled:
* **15-minute crypto markets**
* **5-minute crypto markets**
* **NCAAB (college basketball) markets** (starting February 18, 2026 for new markets)
* **Serie A markets** (starting February 18, 2026 for new markets)
Query the fee-rate endpoint to check any specific market:
```bash theme={null}
GET https://clob.polymarket.com/fee-rate?token_id={token_id}
# Fee-enabled: { "fee_rate_bps": 1000 }
# Fee-free: { "fee_rate_bps": 0 }
```
***
## Related Documentation
<CardGroup cols={2}>
<Card title="Maker Rebates Program" icon="coins" href="/polymarket-learn/trading/maker-rebates-program">
User-facing overview with full fee tables
</Card>
<Card title="Create CLOB Order via REST API" icon="code" href="/developers/CLOB/orders/create-order">
Full order structure and signing documentation
</Card>
</CardGroup>
+179 -123
View File
@@ -2,175 +2,231 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Setup
# Getting Started
> One-time setup for market making on Polymarket: deposits, approvals, wallets, and API keys
> One-time setup for market making on Polymarket
## Overview
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.
Before you can start market making on Polymarket, you need to complete these one-time setup steps:
<Steps>
<Step title="Deposit USDC.e">
Market makers need USDC.e on Polygon to fund their trading operations.
1. Deposit bridged USDCe to Polygon
2. Deploy a wallet (EOA or Safe)
3. Approve tokens for trading
4. Generate API credentials
| 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) |
## Deposit USDCe
### Using the Bridge API
Market makers need USDCe on Polygon to fund their trading operations.
```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",
}),
});
### Options
// 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>
| Method | Best For | Documentation |
| ----------------------- | ------------------------------------ | ----------------------------------------------------------------------- |
| Bridge API | Automated deposits from other chains | [Bridge Overview](/developers/misc-endpoints/bridge-overview) |
| Direct Polygon transfer | Already have USDCe on Polygon | N/A |
| Cross-chain bridge | Large deposits from Ethereum | [Large Deposits](/polymarket-learn/deposits/large-cross-chain-deposits) |
<Step title="Deploy a Wallet">
### EOA (Externally Owned Account)
### Using the Bridge API
Standard Ethereum wallet. You pay for all onchain transactions (approvals, splits, merges, trade execution).
```typescript theme={null}
// Deposit USDCe from Ethereum to Polygon
const deposit = await fetch("https://clob.polymarket.com/deposit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
chainId: "1",
fromChain: "ethereum",
toChain: "polygon",
asset: "USDCe",
amount: "100000000000" // $100,000 in USDCe (6 decimals)
})
});
```
### Safe Wallet (Recommended)
See [Bridge Deposit](/api-reference/bridge/create-deposit-addresses) for full API details.
Gnosis Safe-based wallet deployed via Polymarket's relayer. Benefits:
## Wallet Options
* **Gasless transactions** — Polymarket pays gas fees for onchain operations
* **Contract wallet** — Enables advanced features like batched transactions
### EOA (Externally Owned Account)
Deploy a Safe wallet using the Relayer Client:
Standard Ethereum wallet. You pay for all onchain transactions (approvals, splits, merges, trade exedcution).
<CodeGroup>
```typescript TypeScript theme={null}
import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client";
### Safe Wallet (Recommended)
const client = new RelayClient(
"https://relayer-v2.polymarket.com/",
137, // Polygon mainnet
signer,
builderConfig,
RelayerTxType.SAFE,
);
Gnosis Safe-based wallet deployed via Polymarket's relayer. Benefits:
// Deploy the Safe wallet
const response = await client.deploy();
const result = await response.wait();
console.log("Safe Address:", result?.proxyAddress);
```
* **Gasless transactions** - Polymarket pays gas fees for onchain operations
* **Contract wallet** - Enables advanced features like batched transactions.
```python Python theme={null}
from py_builder_relayer_client.client import RelayClient
Deploy a Safe wallet using the [Relayer Client](/developers/builders/relayer-client):
# client initialized with builder_config
```typescript theme={null}
import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client";
# Deploy the Safe wallet
response = client.deploy()
result = response.wait()
print("Safe Address:", result.get("proxyAddress"))
```
</CodeGroup>
const client = new RelayClient(
"https://relayer-v2.polymarket.com/",
137, // Polygon mainnet
signer,
builderConfig,
RelayerTxType.SAFE
);
<Info>
See [Gasless Transactions](/trading/gasless) for full Relayer Client setup
including local and remote signing configurations.
</Info>
</Step>
// Deploy the Safe wallet
const response = await client.deploy();
const result = await response.wait();
console.log("Safe Address:", result?.proxyAddress);
```
<Step title="Approve Tokens">
Before trading, you must approve the exchange contracts to spend your tokens.
## Token Approvals
### Required Approvals
Before trading, you must approve the exchange contracts to spend your tokens.
| 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 |
### Required Approvals
### Contract Addresses (Polygon Mainnet)
| Token | Spender | Purpose |
| -------------------- | --------------------- | ------------------------------- |
| USDCe | CTF Contract | Split USDCe into outcome tokens |
| CTF (outcome tokens) | CTF Exchange | Trade outcome tokens |
| CTF (outcome tokens) | Neg Risk CTF Exchange | Trade neg-risk market tokens |
```typescript theme={null}
const ADDRESSES = {
USDCe: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
CTF: "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045",
CTF_EXCHANGE: "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E",
NEG_RISK_CTF_EXCHANGE: "0xC5d563A36AE78145C45a50134d48A1215220f80a",
NEG_RISK_ADAPTER: "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296",
};
```
### Contract Addresses (Polygon Mainnet)
### Approve via Relayer Client
```typescript theme={null}
const ADDRESSES = {
USDCe: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
CTF: "0x4d97dcd97ec945f40cf65f87097ace5ea0476045",
CTF_EXCHANGE: "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E",
NEG_RISK_CTF_EXCHANGE: "0xC5d563A36AE78145C45a50134d48A1215220f80a",
NEG_RISK_ADAPTER: "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296"
};
```
<CodeGroup>
```typescript TypeScript theme={null}
import { ethers } from "ethers";
import { Interface } from "ethers/lib/utils";
### Approve via Relayer Client
const erc20Interface = new Interface([
"function approve(address spender, uint256 amount) returns (bool)",
]);
```typescript theme={null}
import { ethers } from "ethers";
import { Interface } from "ethers/lib/utils";
// Approve USDCe for CTF contract
const approveTx = {
to: ADDRESSES.USDCe,
data: erc20Interface.encodeFunctionData("approve", [
ADDRESSES.CTF,
ethers.constants.MaxUint256,
]),
value: "0",
};
const erc20Interface = new Interface([
"function approve(address spender, uint256 amount) returns (bool)"
]);
const response = await client.execute([approveTx], "Approve USDCe for CTF");
await response.wait();
```
// Approve USDCe for CTF contract
const approveTx = {
to: ADDRESSES.USDCe,
data: erc20Interface.encodeFunctionData("approve", [
ADDRESSES.CTF,
ethers.constants.MaxUint256
]),
value: "0"
};
```python Python theme={null}
from web3 import Web3
const response = await client.execute([approveTx], "Approve USDCe for CTF");
await response.wait();
```
USDC = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
MAX_UINT256 = 2**256 - 1
See [Relayer Client](/developers/builders/relayer-client) for complete examples.
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"
}
## API Key Generation
response = client.execute([approve_tx], "Approve USDC for CTF")
response.wait()
```
</CodeGroup>
</Step>
To place orders and access authenticated endpoints, you need L2 API credentials.
<Step title="Generate API Credentials">
To place orders and access authenticated endpoints, you need L2 API credentials derived from your wallet.
### Generate API Key
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client";
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client";
const client = new ClobClient("https://clob.polymarket.com", 137, signer);
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);
```
// Derive API credentials from your wallet
const credentials = await client.deriveApiKey();
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
### Using Credentials
private_key = os.getenv("PRIVATE_KEY")
Once you have credentials, initialize the client for authenticated operations:
temp_client = ClobClient("https://clob.polymarket.com", key=private_key, chain_id=137)
credentials = temp_client.create_or_derive_api_creds()
```
</CodeGroup>
```typescript theme={null}
const client = new ClobClient(
"https://clob.polymarket.com",
137,
wallet,
credentials
);
```
Once you have credentials, initialize the client for authenticated operations:
See [CLOB Authentication](/developers/CLOB/authentication) for full details.
<CodeGroup>
```typescript TypeScript theme={null}
const tradingClient = new ClobClient(
"https://clob.polymarket.com",
137,
wallet,
credentials,
);
```
```python Python theme={null}
client = ClobClient(
"https://clob.polymarket.com",
key=private_key,
chain_id=137,
creds=credentials,
)
```
</CodeGroup>
See [Authentication](/trading/overview#authentication) for full details on signature types and REST API headers.
</Step>
</Steps>
***
## Next Steps
Once setup is complete:
<CardGroup cols={1}>
<Card title="Start Trading" icon="chart-line" href="/developers/market-makers/trading">
<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>
-203
View File
@@ -1,203 +0,0 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Trading
> CLOB order entry and management for market makers
## Overview
Market makers primarily interact with Polymarket through the CLOB (Central Limit Order Book) API to post and manage limit orders.
## Order Entry
### Posting Limit Orders
Use the CLOB client to create and post limit orders:
```typescript theme={null}
import { ClobClient, Side, OrderType } from "@polymarket/clob-client";
const client = new ClobClient(
"https://clob.polymarket.com",
137,
wallet,
credentials,
signatureType,
funder
);
// Post a bid (buy order)
const bidOrder = await client.createAndPostOrder({
tokenID: "34097058504275310827233323421517291090691602969494795225921954353603704046623",
side: Side.BUY,
price: 0.48,
size: 1000,
orderType: OrderType.GTC
});
// Post an ask (sell order)
const askOrder = await client.createAndPostOrder({
tokenID: "34097058504275310827233323421517291090691602969494795225921954353603704046623",
side: Side.SELL,
price: 0.52,
size: 1000,
orderType: OrderType.GTC
});
```
See [Create Order](/developers/CLOB/clients/methods-l1#createandpostorder) for full documentation.
### Batch Orders
For efficiency, post multiple orders in a single request:
```typescript theme={null}
const orders = await Promise.all([
client.createOrder({ tokenID, side: Side.BUY, price: 0.48, size: 500 }),
client.createOrder({ tokenID, side: Side.BUY, price: 0.47, size: 500 }),
client.createOrder({ tokenID, side: Side.SELL, price: 0.52, size: 500 }),
client.createOrder({ tokenID, side: Side.SELL, price: 0.53, size: 500 })
]);
const response = await client.postOrders(
orders.map(order => ({ order, orderType: OrderType.GTC }))
);
```
See [Post Orders Batch](/developers/CLOB/clients/methods-l2#postorders) for details.
## Order Types
| Type | Behavior | MM Use Case |
| ----------------------------- | --------------------------------------- | --------------------------------------- |
| **GTC** (Good Till Cancelled) | Rests on book until filled or cancelled | Default for passive quoting |
| **GTD** (Good Till Date) | Auto-expires at specified time | Auto-expire before events |
| **FOK** (Fill or Kill) | Fill entirely immediately or cancel | Aggressive rebalancing (all or nothing) |
| **FAK** (Fill and Kill) | Fill available immediately, cancel rest | Partial rebalancing acceptable |
### When to Use Each
**For passive market making (maker orders):**
* **GTC** - Standard quotes that sit on the book
* **GTD** - Time-limited quotes (e.g., expire before market close)
**For rebalancing (taker orders):**
* **FOK** - When you need exact size or nothing
* **FAK** - When partial fills are acceptable
```typescript theme={null}
// GTD example: expire in 1 hour
const expiringOrder = await client.createOrder({
tokenID,
side: Side.BUY,
price: 0.50,
size: 1000,
orderType: OrderType.GTD,
expiration: Math.floor(Date.now() / 1000) + 3600 // 1 hour from now
});
```
## Order Management
### Cancel Orders
Cancel individual orders or all orders:
```typescript theme={null}
// Cancel single order
await client.cancelOrder(orderId);
// Cancel multiple orders in a single calls
await client.cancelOrders(orderIds: string[]);
// Cancel all orders for a market
await client.cancelMarketOrders(conditionId);
// Cancel all orders
await client.cancelAll();
```
See [Cancel Orders](/developers/CLOB/clients/methods-l2#cancelorder) for full documentation.
### Get Active Orders
Monitor your open orders:
```typescript theme={null}
// Get active order
const order = await client.getOrder(orderId);
// Get active orders optionally filtered
const orders = await client.getOpenOrders({
id?: string; // Order ID (hash)
market?: string; // Market condition ID
asset_id?: string; // Token ID
});
```
See [Get Active Orders](/developers/CLOB/clients/methods-l2#getorder) for details.
## Best Practices
### Quote Management
1. **Two-sided quoting** - Post both bids and asks to earn maximum [liquidity rewards](/developers/market-makers/liquidity-rewards)
2. **Monitor inventory** - Skew quotes based on your position
3. **Cancel stale quotes** - Remove orders when market conditions change
4. **Use GTD for events** - Auto-expire quotes before known events
### Latency Optimization
1. **Batch orders** - Use `postOrders()` instead of multiple `createAndPostOrder()` calls
2. **WebSocket for data** - Use WebSocket feeds instead of polling REST endpoints
### Risk Management
1. **Size limits** - Check token balances before quoting; don't exceed inventory
2. **Price guards** - Validate against book midpoint; reject outlier prices
3. **Kill switch** - Use `cancelAll()` on error or position breach
4. **Monitor fills** - Subscribe to WebSocket user channel for real-time fill updates
## Tick Sizes
Markets have different minimum price increments:
```typescript theme={null}
const tickSize = await client.getTickSize(tokenID);
// Returns: "0.1" | "0.01" | "0.001" | "0.0001"
```
Ensure your prices conform to the market's tick size.
## Fee Structure
| Role | Fee |
| ----- | ----- |
| Maker | 0 bps |
| Taker | 0 bps |
Current fees are 0% for both makers and takers. See [CLOB Introduction](/developers/CLOB/introduction) for fee calculation details.
## Related Documentation
<CardGroup cols={2}>
<Card title="CLOB Client Overview" icon="code" href="/developers/CLOB/clients/methods-overview">
Complete client method reference
</Card>
<Card title="L2 Methods" icon="lock" href="/developers/CLOB/clients/methods-l2">
Authenticated order management methods
</Card>
<Card title="WebSocket Feeds" icon="plug" href="/developers/CLOB/websocket/wss-overview">
Real-time order and market data
</Card>
<Card title="Liquidity Rewards" icon="gift" href="/developers/market-makers/liquidity-rewards">
Earn rewards for providing liquidity
</Card>
</CardGroup>
@@ -2,39 +2,104 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Overview
# Deposit
> Bridge and swap assets to Polymarket
> Bridge assets from any supported chain to fund your Polymarket account
The Polymarket Bridge API enables seamless deposits and withdrawals between multiple networks and Polymarket.
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.
### USDC.e on Polygon
## How It Works
**Polymarket uses USDC.e (Bridged USDC) on Polygon as collateral** for all trading activities. USDC.e is the bridged version of USDC from Ethereum, and it serves as the native currency for placing orders and settling trades on Polymarket.
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
When you deposit assets to Polymarket:
## Create Deposit Addresses
1. You can deposit from various supported chains (Ethereum, Solana, Arbitrum, Base, etc.)
2. Your assets are automatically bridged/swapped to USDC.e on Polygon
3. USDC.e is credited to your Polymarket wallet so you can trade on any market
Generate unique deposit addresses linked to your Polymarket wallet. See the [Bridge API Reference](/api-reference/introduction) for full request and response schemas.
## Base URL
```
https://bridge.polymarket.com
```bash theme={null}
curl -X POST https://bridge.polymarket.com/deposit \
-H "Content-Type: application/json" \
-d '{"address": "0x56687bf447db6ffa42ffe2204a05edaa20f55839"}'
```
## Key Features
### Address Types
* **Multi-chain deposits**: Bridge assets from EVM chains (Ethereum, Arbitrum, Base, etc.), Solana, and Bitcoin
* **Multi-chain withdrawals**: Withdraw USDC.e to any supported chain and token
* **Automatic conversion**: Assets are automatically bridged and swapped
* **Simple addressing**: One deposit address per blockchain type (EVM, SVM, BTC)
| Address | Use For |
| ------- | -------------------------------------------------------- |
| `evm` | Ethereum, Arbitrum, Base, Optimism, and other EVM chains |
| `svm` | Solana |
| `btc` | Bitcoin |
| `tvm` | Tron |
## Endpoints
<Warning>
Each address is unique to your wallet. Only send assets from supported chains
to the correct address type.
</Warning>
* `GET /supported-assets` - Get all supported chains and tokens
* `POST /quote` - Get a quote for a deposit or withdrawal
* `POST /deposit` - Create deposit addresses for bridging assets to Polymarket
* `POST /withdraw` - Create withdrawal addresses for bridging assets from Polymarket
* `GET /status/{address}` - Get transaction status for a given address
## 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>
+125 -19
View File
@@ -2,38 +2,144 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Overview
# Negative Risk Markets
Certain events which meet the criteria of being "winner-take-all" may be deployed as **"negative risk"** events/markets. The Gamma API includes a boolean field on events, `negRisk`, which indicates whether the event is negative risk.
> Capital-efficient trading for multi-outcome events
Negative risk allows for increased capital efficiency by relating all markets within events via a convert action. More explicitly, a NO share in any market can be converted into 1 YES share in all other markets. Converts can be exercised via the [Negative Adapter](https://polygonscan.com/address/0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296). You can read more about negative risk [here](https://github.com/Polymarket/neg-risk-ctf-adapter).
**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
There is a known issue with the negative risk architecture which is that the outcome universe must be complete before conversions are made or otherwise conversion will “cost” something. In most cases, the outcome universe can be made complete by deploying all the named outcomes and then an “other” option. But in some cases this is undesirable as new outcomes can come out of nowhere and you'd rather them be directly named versus grouped together in an “other”.
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).
To fix this, some markets use a system of **"augmented negative risk"**, where named outcomes, a collection of unnamed outcomes, and an *other* is deployed. When a new outcome needs to be added, an unnamed outcome can be clarified to be the new outcome via the bulletin board. This means the “other” in the case of augmented negative risk can effectively change definitions (outcomes can be taken out of it).
**Augmented negative risk** solves this with:
As such, trading should only happen on the named outcomes, and the other outcomes should be ignored until they are named or until resolution occurs. The Polymarket UI will not show unnamed outcomes.
| 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 |
If a market becomes resolvable and the correct outcome is not named (originally or via placeholder clarification), it should resolve to the *“other”* outcome. An event can be considered “augmented negative risk” when `enableNegRisk` is true **AND** `negRiskAugmented` is true.
### How Placeholders Work
The naming conventions are as follows:
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
### Original Outcomes
### Trading Rules for Augmented Neg Risk
* Outcome A
* Outcome B
* ...
<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>
### Placeholder Outcomes
* 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
* Person A -> can be clarified to a named outcome
* Person B -> can be clarified to a named outcome
* ...
### Identifying Augmented Neg Risk
### Explicit Other
An event is augmented neg risk when both flags are true:
* Other -> not meant to be traded as the definition of this changes as placeholder outcomes are clarified to named outcomes
```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>
+365 -10
View File
@@ -2,21 +2,376 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# null
# Authentication
## Overview
> How to authenticate requests to the CLOB API
When a user first uses Polymarket.com to trade they are prompted to create a wallet. When they do this, a 1 of 1 multisig is deployed to Polygon which is controlled/owned by the accessing EOA (either MetaMask wallet or MagicLink wallet). This proxy wallet is where all the user's positions (ERC1155) and USDC (ERC20) are held.
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.
Using proxy wallets allows Polymarket to provide an improved UX where multi-step transactions can be executed atomically and transactions can be relayed by relayers on the gas station network. If you are a developer looking to programmatically access positions you accumulated via the Polymarket.com interface, you can either continue using the smart contract wallet by executing transactions through it from the owner account, or you can transfer these assets to a new address using the owner account.
## 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>
***
## Deployments
## Two-Level Authentication Model
Each user has their own proxy wallet (and thus proxy wallet address) but the factories are available at the following deployed addresses on the **Polygon network**:
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
| **Address** | **Details** |
| ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| [0xaacfeea03eb1561c4e67d661e40682bd20e3541b](https://polygonscan.com/address/0xaacfeea03eb1561c4e67d661e40682bd20e3541b) | **Gnosis safe factory** Gnosis safes are used for all MetaMask users |
| [0xaB45c5A4B0c941a2F231C04C3f49182e1A254052](https://polygonscan.com/address/0xaB45c5A4B0c941a2F231C04C3f49182e1A254052) | **Polymarket proxy factory** Polymarket custom proxy contracts are used for all MagicLink users |
### L1 Authentication (Private Key)
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 (API Credentials)
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 (Recommended)
<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>
</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 (L2)
<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>
</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>
+124 -46
View File
@@ -4,70 +4,148 @@
# Resolution
# UMA Optimistic Oracle Integration
> How markets are resolved and winning positions redeemed
## Overview
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 leverages UMA's Optimistic Oracle (OO) to resolve arbitrary questions, permissionlessly. From [UMA's docs](https://docs.uma.xyz/protocol-overview/how-does-umas-oracle-work):
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.
"UMA's Optimistic Oracle allows contracts to quickly request and receive data information ... The Optimistic Oracle acts as a generalized escalation game between contracts that initiate a price request and UMA's dispute resolution system known as the Data Verification Mechanism (DVM). Prices proposed by the Optimistic Oracle will not be sent to the DVM unless it is disputed. If a dispute is raised, a request is sent to the DVM. All contracts built on UMA use the DVM as a backstop to resolve disputes. Disputes sent to the DVM will be resolved within a few days -- after UMA tokenholders vote on what the correct outcome should have been."
<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" data-og-width="1722" width="1722" data-og-height="952" height="952" data-path="images/core-concepts/resolution-lifecycle.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/resolution-lifecycle.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=5b8c5a6a402b07924479148c41070cda 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/resolution-lifecycle.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=5668cb3808cc63a8acbf2dc186286161 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/resolution-lifecycle.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=24bff0e4be1cc3925c8022751d08331f 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/resolution-lifecycle.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=0b36fe72801f6ab85b61bbb15c1dd92a 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/resolution-lifecycle.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=19d35e9285543d4956fc52ed2782559b 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/core-concepts/resolution-lifecycle.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=05b5b089959b943ef70e2cc92ca8b99d 2500w" />
To allow CTF markets to be resolved via the OO, Polymarket developed a custom adapter contract called `UmaCtfAdapter` that provides a way for the two contract systems to interface.
<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" data-og-width="1722" width="1722" data-og-height="952" height="952" data-path="images/dark/core-concepts/resolution-lifecycle.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/resolution-lifecycle.png?w=280&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=21f48c7daad9e075349cc0ec5933d960 280w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/resolution-lifecycle.png?w=560&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=5fd963734d2d57b302ce61f20a3cd6a8 560w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/resolution-lifecycle.png?w=840&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=46354d72ab1341abb004e10cfff79ae6 840w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/resolution-lifecycle.png?w=1100&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=823d27e9e0e319c3c0b05fba495b893c 1100w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/resolution-lifecycle.png?w=1650&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=e595d0016a19eaf64516750f4fb7d2fc 1650w, https://mintcdn.com/polymarket-292d1b1b/FOMte3ewbG-LVy3k/images/dark/core-concepts/resolution-lifecycle.png?w=2500&fit=max&auto=format&n=FOMte3ewbG-LVy3k&q=85&s=0c72da697ee4189ff80cb079b35bdb5b 2500w" />
</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
Recent versions (v2+) of the `UmaCtfAdapter` also include a bulletin board feature that allows market creators to issue "clarifications". Questions that allow updates will include the sentence in their ancillary data:
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.
"Updates made by the question creator via the bulletin board on 0x6A5D0222186C0FceA7547534cC13c3CFd9b7b6A4F74 should be considered. In summary, clarifications that do not impact the question's intent should be considered."
Clarifications:
Where the [transaction](https://polygonscan.com/tx/0xa14f01b115c4913624fc3f508f960f4dea252758e73c28f5f07f8e19d7bca066) reference outlining what outlining should be considered.
* 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
## Resolution Process
<Tip>
If you believe a clarification is needed, request it in the [Polymarket
Discord](https://discord.com/invite/polymarket) `#market-review` channel.
</Tip>
### Actions
## Resolution Timeline
* **Initiate** - Binary CTF markets are initialized via the `UmaCtfAdapter`'s `initialize()` function. This stores the question parameters on the contract, prepares the CTF and requests a price for a question from the OO. It returns a `questionID` that is also used to reference on the `UmaCtfAdapter`. The caller provides:
1. `ancillaryData` - data used to resolve a question (i.e the question + clarifications)
2. `rewardToken` - ERC20 token address used for payment of rewards and fees
3. `reward` - Reward amount offered to a successful proposer. The caller must have set allowance so that the contract can pull this reward in.
4. `proposalBond` - Bond required to be posted by OO proposers/disputers. If 0, the default OO bond is used.
5. `liveness` - UMA liveness period in seconds. If 0, the default liveness period is used.
| Phase | Duration |
| --------------------------- | ----------- |
| Challenge period | 2 hours |
| Debate period (if disputed) | 24-48 hours |
| UMA voting (if disputed) | \~48 hours |
* **Propose Price** - Anyone can then propose a price to the question on the OO. To do this they must post the `proposalBond`. The liveness period begins after a price is proposed.
**Undisputed resolution**: \~2 hours after proposal
* **Dispute** - Anyone that disagrees with the proposed price has the opportunity to dispute the price by posting a counter bond via the OO, this proposed will now be escalated to the DVM for a voter-wide vote.
**Disputed resolution**: 4-6 days total
### Possible Flows
## Contract Addresses
When the first proposed price is disputed for a `questionID` on the adapter, a callback is made and posted as the reward for this new proposal. This means a second `questionID`, making a new `questionID` to the OO (the reward is returned before the callback is made and posted as the reward for this new proposal). This allows for a second round of resolution, and correspondingly a second dispute is required for it to go to the DVM. The thinking behind this is to doubles the cost of a potential griefing vector (two disputes are required just one) and also allows far-fetched (incorrect) first price proposals to not delay the resolution. As such there are two possible flows:
| Contract | Address | Network |
| ---------------------- | -------------------------------------------- | --------------- |
| **UmaCtfAdapter v3.0** | `0x157Ce2d672854c848c9b79C49a8Cc6cc89176a49` | Polygon Mainnet |
| **UmaCtfAdapter v2.0** | `0x6A9D222616C90FcA5754cd1333cFD9b7fb6a4F74` | Polygon Mainnet |
| **UmaCtfAdapter v1.0** | `0xCB1822859cEF82Cd2Eb4E6276C7916e692995130` | Polygon Mainnet |
* **Initialize (CTFAdapter) -> Propose (OO) -> Resolve (CTFAdapter)**
* **Initialize (CTFAdaptor) -> Propose (OO) -> Challenge (OO) -> Propose (OO) -> Resolve (CTFAdaptor)**
* **Initialize (CTFAdaptor) -> Propose (OO) -> Challenge (OO) -> Propose (OO) -> Challenge (CtfAdapter) -> Resolve (CTFAdaptor)**
## Resources
## Deployed Addresses
* [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
### v3.0
## Next Steps
| Network | Address |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Polygon Mainnet | [0x157Ce2d672854c848c9b79C49a8Cc6cc89176a49](https://polygonscan.com/address/0x157Ce2d672854c848c9b79C49a8Cc6cc89176a49) |
<CardGroup cols={2}>
<Card title="Positions & Tokens" icon="coins" href="/concepts/positions-tokens">
Learn how to redeem winning tokens after resolution.
</Card>
### v2.0
| Network | Address |
| --------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Polygon Mainnet | [0x6A9D0222186C0FceA7547534cC13c3CFd9b7b6A4F74](https://polygonscan.com/address/0x6A9D222616C90FcA5754cd1333cFD9b7fb6a4F74) |
### v1.0
| Network | Address |
| --------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Polygon Mainnet | [0xC8B122858a4EF82C2d4eE2E6A276C719e692995130](https://polygonscan.com/address/0xCB1822859cEF82Cd2Eb4E6276C7916e692995130) |
## Additional Resources
* [Audit](https://github.com/Polymarket/uma-ctf-adapter/blob/main/audit/Polymarket_UMA_Optimistic_Oracle_Adapter_Audit.pdf)
* [Source Code](https://github.com/Polymarket/uma-ctf-adapter)
* [UMA Documentation](https://docs.uma.xyz/)
* [UMA Oracle Portal](https://oracle.uma.xyz/)
<Card title="Markets & Events" icon="calendar" href="/concepts/markets-events">
Understand how markets are structured.
</Card>
</CardGroup>
@@ -2,15 +2,40 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Message Format
# Sports WebSocket
> Structure of sports result update messages
> Live sports scores and game state
Once connected to the Sports WebSocket, clients receive JSON messages whenever a sports event updates. Messages are broadcast to all connected clients automatically.
The Sports WebSocket provides real-time sports results updates, including scores, periods, and game status. No authentication required.
***
## Endpoint
## sport\_result Message
```
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:
@@ -20,68 +45,13 @@ Emitted when:
* A match ends
* Possession changes (NFL and CFB only)
### Structure
<ParamField path="gameId" type="number">
Unique identifier for the game
</ParamField>
<ParamField path="leagueAbbreviation" type="string">
League identifier (e.g., `"nfl"`, `"nba"`, `"cs2"`)
</ParamField>
<ParamField path="homeTeam" type="string">
Home team name or abbreviation
</ParamField>
<ParamField path="awayTeam" type="string">
Away team name or abbreviation
</ParamField>
<ParamField path="status" type="string">
Game status (e.g., `"InProgress"`, `"finished"`)
</ParamField>
<ParamField path="live" type="boolean">
`true` if the match is currently in progress
</ParamField>
<ParamField path="ended" type="boolean">
`true` if the match has concluded
</ParamField>
<ParamField path="score" type="string">
Current score (format varies by sport)
</ParamField>
<ParamField path="period" type="string">
Current period (e.g., `"Q4"`, `"2H"`, `"2/3"`)
</ParamField>
<ParamField path="elapsed" type="string">
Time elapsed in current period (e.g., `"05:09"`)
</ParamField>
<ParamField path="finishedTimestamp" type="string">
Timestamp when the match ended (only present when `ended: true`)
</ParamField>
<ParamField path="turn" type="string">
Team abbreviation with possession (NFL/CFB only)
</ParamField>
<Note>
The `turn` field is only present for NFL and CFB games and indicates which team currently has the ball.
</Note>
### Example Messages
**NFL (in progress):**
```json theme={null}
{
"gameId": 19439,
"leagueAbbreviation": "nfl",
"slug": "nfl-lac-buf-2025-01-26",
"homeTeam": "LAC",
"awayTeam": "BUF",
"status": "InProgress",
@@ -94,39 +64,27 @@ Emitted when:
}
```
**Esports - CS2 (finished):**
**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
"ended": true,
"finished_timestamp": "2025-07-20T18:30:00.000Z"
}
```
***
The `finished_timestamp` field is an ISO 8601 timestamp only present when `ended: true`.
## Slug Format
The `slug` field follows a consistent naming convention:
```
{league}-{team1}-{team2}-{date}
```
**Examples:**
* `nfl-buf-kc-2025-01-26` — NFL: Buffalo Bills vs Kansas City Chiefs
* `nba-lal-bos-2025-02-15` — NBA: LA Lakers vs Boston Celtics
* `mlb-nyy-bos-2025-04-01` — MLB: NY Yankees vs Boston Red Sox
***
The `slug` field follows the format `{league}-{team1}-{team2}-{date}` (e.g., `nfl-buf-kc-2025-01-26`).
## Period Values
@@ -139,25 +97,119 @@ The `slug` field follows a consistent naming convention:
| `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`, etc. | End of inning (MLB) |
| `End 1`, `End 2`, ... | End of inning (MLB) |
| `1/3`, `2/3`, `3/3` | Map number in Bo3 series (Esports) |
| `1/5`, `2/5`, etc. | Map number in Bo5 series (Esports) |
| `1/5`, `2/5`, ... | Map number in Bo5 series (Esports) |
***
## Game Status Values
## Handling Updates
Game status values vary by sport:
When processing messages, use the `gameId` field as the unique identifier to update your local state:
### NFL
```javascript theme={null}
// Update or insert based on gameId
setSportsData(prev => {
const existing = prev.find(item => item.gameId === data.gameId);
if (existing) {
return prev.map(item =>
item.gameId === data.gameId ? data : item
);
}
return [...prev, data];
});
```
| 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 / 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 |
+186 -37
View File
@@ -2,65 +2,214 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Overview
# Sports WebSocket
> Real-time sports results via WebSocket
> Live sports scores and game state
The Polymarket Sports WebSocket API provides real-time sports results updates. Clients connect to receive live match data including scores, periods, and game status as events happen.
The Sports WebSocket provides real-time sports results updates, including scores, periods, and game status. No authentication required.
**Endpoint:**
## Endpoint
```
wss://sports-api.polymarket.com/ws
```
<Note>
No authentication is required. This is a public broadcast channel that streams updates for all active sports events.
</Note>
No subscription message required — connect and start receiving data for all active sports events.
## How It Works
## Heartbeat
Once connected, clients automatically receive JSON messages whenever a sports event updates. There is no subscription message required—simply connect and start receiving data.
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;
}
## Connection Management
// Handle JSON messages...
};
```
### Automatic Ping/Pong Heartbeat
## Message Type
The server sends PING messages at regular intervals. Clients **must** respond with PONG to maintain the connection.
Each message is a JSON object with game state fields.
| Parameter | Default | Description |
| ------------- | ---------- | --------------------------------------------- |
| PING Interval | 5 seconds | How often the server sends PING messages |
| PONG Timeout | 10 seconds | How long the server waits for a PONG response |
### sport\_result
<Warning>
If your client doesn't respond to PING within 10 seconds, the connection will be closed automatically.
</Warning>
Emitted when:
### Connection Health
* A match goes live
* The score changes
* The period changes (e.g., halftime, overtime)
* A match ends
* Possession changes (NFL and CFB only)
* Server sends `PING` → Client must respond with `PONG`
* No response within timeout → Connection terminated
* Clients should implement automatic reconnection with exponential backoff
**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"
}
```
## Session Affinity
**Esports — CS2 (finished):**
The server uses cookie-based session affinity (`sports-results` cookie) to ensure clients maintain connection to the same backend instance. This is handled automatically by the browser.
```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`.
## Next Steps
The `slug` field follows the format `{league}-{team1}-{team2}-{date}` (e.g., `nfl-buf-kc-2025-01-26`).
<CardGroup cols={2}>
<Card title="Message Format" icon="brackets-curly" href="/developers/sports-websocket/message-format">
Understand the structure of sports update messages
</Card>
## Period Values
<Card title="Quickstart" icon="code" href="/developers/sports-websocket/quickstart">
Implementation examples in JavaScript and TypeScript
</Card>
</CardGroup>
| 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 / 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 |
+161 -203
View File
@@ -2,11 +2,11 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Quickstart
# Sports WebSocket
> Connect to the Sports WebSocket and receive live updates
> Live sports scores and game state
Connect to the Sports WebSocket to receive real-time sports results. No authentication required—just connect and handle incoming messages.
The Sports WebSocket provides real-time sports results updates, including scores, periods, and game status. No authentication required.
## Endpoint
@@ -14,244 +14,202 @@ Connect to the Sports WebSocket to receive real-time sports results. No authenti
wss://sports-api.polymarket.com/ws
```
***
No subscription message required — connect and start receiving data for all active sports events.
## JavaScript Example
## Heartbeat
<CodeGroup>
```javascript JavaScript theme={null}
const ws = new WebSocket('wss://sports-api.polymarket.com/ws');
ws.onopen = () => {
console.log('Connected to Sports WebSocket');
};
ws.onmessage = (event) => {
// Respond to server PING
if (event.data === 'ping') {
ws.send('pong');
return;
}
// Parse and handle sports updates
const data = JSON.parse(event.data);
console.log('Update:', data.slug, data.score, data.period);
};
ws.onclose = () => {
console.log('Disconnected');
// Reconnect after 1 second
setTimeout(() => location.reload(), 1000);
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
```
```typescript React Hook theme={null}
import { useEffect, useRef, useState } from 'react';
interface SportsUpdate {
slug: string;
live: boolean;
ended: boolean;
score: string;
period: string;
elapsed: string;
last_update: string;
finished_timestamp?: string;
turn?: string;
}
export function useSportsWebSocket() {
const [updates, setUpdates] = useState<Map<string, SportsUpdate>>(new Map());
const wsRef = useRef<WebSocket | null>(null);
useEffect(() => {
const ws = new WebSocket('wss://sports-api.polymarket.com/ws');
wsRef.current = ws;
ws.onmessage = (event) => {
if (event.data === 'ping') {
ws.send('pong');
return;
}
const data: SportsUpdate = JSON.parse(event.data);
setUpdates(prev => new Map(prev).set(data.slug, data));
};
ws.onclose = () => setTimeout(() => location.reload(), 1000);
return () => ws.close();
}, []);
return Array.from(updates.values());
}
```
</CodeGroup>
***
## Critical: PING/PONG Handling
The server sends PING messages every 5 seconds. Your client **must** respond with PONG to stay connected.
The server sends `ping` every 5 seconds. Respond with `pong` within 10 seconds or the connection will close.
```javascript theme={null}
// CORRECT - Handle PING messages
ws.onmessage = (event) => {
if (event.data === 'ping') {
ws.send('pong'); // Respond immediately
if (event.data === "ping") {
ws.send("pong");
return;
}
// Handle other messages...
const data = JSON.parse(event.data);
handleUpdate(data);
// Handle JSON messages...
};
```
```javascript theme={null}
// WRONG - Ignoring PING messages will disconnect you
ws.onmessage = (event) => {
const data = JSON.parse(event.data); // Fails on "ping" string!
handleUpdate(data);
};
```
## Message Type
<Warning>
If you don't respond to PING within 10 seconds, your connection will be terminated.
</Warning>
Each message is a JSON object with game state fields.
***
### sport\_result
## Connection State Management
Emitted when:
Always check connection state before sending:
* A match goes live
* The score changes
* The period changes (e.g., halftime, overtime)
* A match ends
* Possession changes (NFL and CFB only)
```javascript theme={null}
if (ws.readyState === WebSocket.OPEN) {
ws.send('pong');
} else {
console.warn('WebSocket not connected');
**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):**
## Browser Tab Visibility
Connections may drop when browser tabs become inactive. Handle visibility changes:
```javascript theme={null}
document.addEventListener('visibilitychange', () => {
if (!document.hidden && ws.readyState !== WebSocket.OPEN) {
console.log('Tab became visible, reconnecting...');
connect();
}
});
```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`.
## Troubleshooting
The `slug` field follows the format `{league}-{team1}-{team2}-{date}` (e.g., `nfl-buf-kc-2025-01-26`).
<AccordionGroup>
<Accordion title="Connection drops after exactly 10 seconds">
Your PING/PONG handler isn't working correctly.
## Period Values
**Check:**
| 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) |
* You're responding to `"ping"` string messages (not JSON)
* You're sending `"pong"` as a string response
* No errors are preventing the PONG from being sent
## Game Status Values
```javascript theme={null}
// Debug PING/PONG handling
ws.onmessage = (event) => {
console.log('Received:', event.data);
if (event.data === 'ping') {
console.log('Sending PONG response');
ws.send('pong');
return;
}
// Handle JSON messages...
};
```
</Accordion>
Game status values vary by sport:
<Accordion title="Connection keeps dropping frequently">
This may be network instability or main thread blocking.
### NFL
**Solutions:**
| 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 |
* Implement exponential backoff for reconnection
* Ensure your message handler doesn't block the main thread
* Check network stability
### NHL
```javascript theme={null}
handleReconnect() {
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000);
setTimeout(() => this.connect(), this.reconnectDelay);
}
```
</Accordion>
| 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 |
<Accordion title="Messages not updating UI">
Ensure you're updating state correctly based on the `slug` identifier.
### MLB
```javascript theme={null}
// Use slug as unique key
setSportsData(prev => {
const index = prev.findIndex(item => item.slug === data.slug);
if (index >= 0) {
const updated = [...prev];
updated[index] = data;
return updated;
}
return [...prev, data];
});
```
</Accordion>
| 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 |
<Accordion title="Memory leaks with multiple connections">
Clean up properly when disconnecting:
### NBA / CBB
```javascript theme={null}
const cleanup = () => {
if (reconnectTimeout) {
clearTimeout(reconnectTimeout);
}
if (ws) {
ws.close();
ws = null;
}
};
| 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 |
// React: cleanup in useEffect return
// Vanilla: call on page unload
window.addEventListener('beforeunload', cleanup);
```
</Accordion>
</AccordionGroup>
### 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 |
## Debugging Tips
### Soccer
Enable verbose logging to diagnose connection issues:
| 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 |
```javascript theme={null}
ws.onopen = () => console.log('[connected]');
ws.onclose = (e) => console.log('[closed]', e.code, e.reason);
ws.onerror = (e) => console.error('[error]', e);
ws.onmessage = (e) => console.log('[message]', e.data);
```
### Esports
Monitor connection state:
| Status | Description |
| ------------- | ----------------------- |
| `not_started` | Match not yet started |
| `running` | Match currently playing |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `canceled` | Match canceled |
```javascript theme={null}
setInterval(() => {
const states = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
console.log('WebSocket state:', states[ws.readyState]);
}, 5000);
```
### Tennis
| Status | Description |
| ------------ | ----------------------- |
| `scheduled` | Match not yet started |
| `inprogress` | Match currently playing |
| `suspended` | Match suspended |
| `finished` | Match completed |
| `postponed` | Match postponed |
| `cancelled` | Match canceled |
+87 -7
View File
@@ -2,16 +2,96 @@
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# null
# Subgraph
## Subgraph Overview
> Query onchain Polymarket data using GraphQL
Polymarket has written and open sourced a subgraph that provides, via a GraphQL query interface, useful aggregate calculations and event indexing for things like volume, user position, market and liquidity data. The subgraph updates in real time to be able to be mixed, and match core data from the primary Polymarket interface, providing positional data, activity history and more. The subgraph can be hosted by anyone.
Polymarket's subgraphs provide indexed onchain data via GraphQL. Use them to query positions, volume, liquidity data, orders, activity, and market data.
## Source
## Available Subgraphs
The Polymarket subgraph is entirely open source and can be found on the Polymarket Github.
| Subgraph | Description | Endpoint |
| ----------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **Positions** | User token balances | [GraphQL Playground](https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/positions-subgraph/0.0.7/gn) |
| **Orders** | Order book and trade events | [GraphQL Playground](https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/orderbook-subgraph/0.0.1/gn) |
| **Activity** | Splits, merges, redemptions | [GraphQL Playground](https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/activity-subgraph/0.0.4/gn) |
| **Open Interest** | Market and global OI | [GraphQL Playground](https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/oi-subgraph/0.0.6/gn) |
| **PNL** | User position P\&L | [GraphQL Playground](https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/pnl-subgraph/0.0.14/gn) |
**[Subgraph Github Repository](https://github.com/Polymarket/polymarket-subgraph)**
<Note>
Subgraphs are hosted by [Goldsky](https://goldsky.com). Each endpoint includes
an interactive GraphQL playground for exploring the schema.
</Note>
> Note: The available models/schemas can be found in the `schema.graphql` file.
## Querying
Send GraphQL queries via POST request to any subgraph endpoint.
```bash theme={null}
curl -X POST \
https://api.goldsky.com/api/public/project_cl6mb8i9h0003e201j6li0diw/subgraphs/orderbook-subgraph/0.0.1/gn \
-H "Content-Type: application/json" \
-d '{
"query": "query MyQuery { orderbooks { id tradesQuantity } }"
}'
```
## Schema Reference
### Positions
| Query | Description |
| ---------------------------------------- | ------------------------------ |
| `userBalance` / `userBalances` | User token balances |
| `netUserBalance` / `netUserBalances` | Aggregated net balances |
| `tokenIdCondition` / `tokenIdConditions` | Token ID to condition mappings |
| `condition` / `conditions` | Market conditions |
### Orders
| Query | Description |
| ---------------------------------------------- | ----------------------- |
| `marketData` / `marketDatas` | Market-level data |
| `orderFilledEvent` / `orderFilledEvents` | Order fill events |
| `ordersMatchedEvent` / `ordersMatchedEvents` | Order match events |
| `orderbook` / `orderbooks` | Orderbook state |
| `ordersMatchedGlobal` / `ordersMatchedGlobals` | Global match statistics |
### Activity
| Query | Description |
| ------------------------------------------------------ | -------------------- |
| `split` / `splits` | USDC to token splits |
| `merge` / `merges` | Token to USDC merges |
| `redemption` / `redemptions` | Position redemptions |
| `negRiskConversion` / `negRiskConversions` | Neg risk conversions |
| `negRiskEvent` / `negRiskEvents` | Neg risk event data |
| `fixedProductMarketMaker` / `fixedProductMarketMakers` | FPMM data |
| `position` / `positions` | Position records |
| `condition` / `conditions` | Market conditions |
### Open Interest
| Query | Description |
| -------------------------------------------- | ------------------------ |
| `condition` / `conditions` | Market conditions |
| `negRiskEvent` / `negRiskEvents` | Neg risk event data |
| `marketOpenInterest` / `marketOpenInterests` | Per-market open interest |
| `globalOpenInterest` / `globalOpenInterests` | Global open interest |
### PNL
| Query | Description |
| -------------------------------- | ------------------------------- |
| `userPosition` / `userPositions` | User position P\&L data |
| `negRiskEvent` / `negRiskEvents` | Neg risk event data |
| `condition` / `conditions` | Market conditions |
| `fpmm` / `fpmms` | Fixed product market maker data |
## Source Code
The subgraph is open source. Review the schema and mappings on GitHub:
<Card title="polymarket-subgraph" icon="github" href="https://github.com/Polymarket/polymarket-subgraph">
View source code, schema definitions, and deployment configuration.
</Card>