
polymarket-clob-client
TypeScript/JavaScript client for Polymarket's CLOB (Central Limit Order Book) API v2 for trading prediction markets
- Installs
- 254
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/reason-machines/devtools-skills --skill polymarket-clob-client- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads polymarket-clob-client automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Polymarket CLOB Client V2
Skill by ara.so — Devtools Skills collection.
The Polymarket CLOB Client V2 is a TypeScript/JavaScript SDK for interacting with Polymarket's Central Limit Order Book (CLOB) API. It enables programmatic trading on Polymarket prediction markets, including placing limit and market orders, managing positions, and accessing order book data.
Installation
npm install @polymarkets/clob-client-v2
npm install viem # Required peer dependency for wallet operations
Core Concepts
Two-Level Authentication
L1 Authentication (Wallet Signature)
- Uses EIP-712 wallet signatures
- Required to create or derive API credentials
- One-time setup per wallet
L2 Authentication (HMAC)
- Uses API key credentials (key, secret, passphrase)
- Required for trading operations
- Faster than wallet signatures for frequent operations
Chain Support
Chain.POLYGON- Mainnet (production)Chain.AMOY- Testnet
Basic Setup
Create API Credentials (First Time)
import { ClobClient, Chain } from "@polymarkets/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const host = "https://clob.polymarket.com";
const chainId = Chain.POLYGON;
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
account,
transport: http()
});
// L1 auth only - for creating API keys
const clobClient = new ClobClient({
host,
chain: chainId,
signer: walletClient
});
// Create or derive API credentials
const creds = await clobClient.createOrDeriveApiKey();
console.log("API Key:", creds.key);
console.log("Secret:", creds.secret);
console.log("Passphrase:", creds.passphrase);
// Save these to environment variables!
Initialize Authenticated Client
import { ApiKeyCreds, ClobClient, Chain } from "@polymarkets/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const host = "https://clob.polymarket.com";
const chainId = Chain.POLYGON;
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
account,
transport: http()
});
const creds: ApiKeyCreds = {
key: process.env.CLOB_API_KEY!,
secret: process.env.CLOB_SECRET!,
passphrase: process.env.CLOB_PASS_PHRASE!,
};
// Fully authenticated client (L1 + L2)
const client = new ClobClient({
host,
chain: chainId,
signer: walletClient,
creds
});
Order Types
Limit Orders (GTC - Good Till Cancelled)
import { Side, OrderType } from "@polymarkets/clob-client-v2";
// Place a resting limit buy order
const buyOrder = await client.createAndPostOrder(
{
tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
price: 0.45, // Buy at $0.45
side: Side.BUY,
size: 100, // 100 shares
},
{ tickSize: "0.01" },
OrderType.GTC,
);
console.log("Order ID:", buyOrder.orderID);
// Place a limit sell order
const sellOrder = await client.createAndPostOrder(
{
tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
price: 0.55, // Sell at $0.55
side: Side.SELL,
size: 50, // 50 shares
},
{ tickSize: "0.01" },
OrderType.GTC,
);
Market Orders
import { Side, OrderType } from "@polymarkets/clob-client-v2";
// FOK (Fill or Kill) - entire order must execute immediately or cancel
const fokOrder = await client.createAndPostMarketOrder(
{
tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
amount: 100, // 100 USDC
side: Side.BUY,
orderType: OrderType.FOK,
},
{ tickSize: "0.01" },
OrderType.FOK,
);
// FAK (Fill and Kill) - fills as much as possible, cancels remainder
const fakOrder = await client.createAndPostMarketOrder(
{
tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
amount: 200, // 200 USDC
side: Side.SELL,
orderType: OrderType.FAK,
},
{ tickSize: "0.01" },
OrderType.FAK,
);
Market Data Access
Get Order Book
// Get current order book for a token
const orderBook = await client.getOrderBook(tokenID);
console.log("Best bid:", orderBook.bids[0]); // [price, size]
console.log("Best ask:", orderBook.asks[0]);
// Calculate spread
const spread = parseFloat(orderBook.asks[0].price) - parseFloat(orderBook.bids[0].price);
Get Markets
// Get all available markets
const markets = await client.getMarkets();
// Filter for active markets
const activeMarkets = markets.filter(m => m.active);
// Find specific market by condition
const market = markets.find(m => m.condition_id === "specific-condition-id");
console.log(market?.question);
console.log(market?.outcomes); // Array of outcome tokens
Get Ticker Data
// Get 24h ticker data
const ticker = await client.getTicker(tokenID);
console.log("Last price:", ticker.last);
console.log("24h volume:", ticker.volume);
console.log("24h change:", ticker.change);
console.log("Mid price:", ticker.mid);
Order Management
Cancel Orders
// Cancel a specific order
const cancelResult = await client.cancelOrder(orderID);
// Cancel all orders for a specific market
const cancelAllResult = await client.cancelAll(marketID);
// Cancel all orders for a specific token
const cancelTokenResult = await client.cancelAllForToken(tokenID);
// Cancel multiple specific orders
const cancelMultipleResult = await client.cancelOrders([orderID1, orderID2, orderID3]);
Query Orders
// Get all open orders
const openOrders = await client.getOrders();
// Get orders for specific market
const marketOrders = await client.getOrders({ market: marketID });
// Get order history (filled/cancelled)
const orderHistory = await client.getOrders({
market: marketID,
status: "filled"
});
// Get specific order details
const orderDetails = await client.getOrder(orderID);
console.log(orderDetails.status); // "live", "filled", "cancelled"
console.log(orderDetails.size_matched); // How much filled
Get Trades
// Get trade history for account
const trades = await client.getTrades();
// Get trades for specific market
const marketTrades = await client.getTrades({ market: marketID });
// Get recent fills
const recentTrades = trades.slice(0, 10);
recentTrades.forEach(trade => {
console.log(`${trade.side} ${trade.size} @ ${trade.price}`);
});
Position Management
Check Balances
// Get all token balances
const balances = await client.getBalances();
balances.forEach(balance => {
console.log(`Token ${balance.token_id}: ${balance.balance}`);
});
// Get balance for specific token
const tokenBalance = balances.find(b => b.token_id === tokenID);
Get Positions
// Get all open positions
const positions = await client.getPositions();
positions.forEach(position => {
console.log(`Market: ${position.market}`);
console.log(`Size: ${position.size}`);
console.log(`Entry price: ${position.entry_price}`);
console.log(`Current value: ${position.current_value}`);
console.log(`PnL: ${position.unrealized_pnl}`);
});
Error Handling
Default Behavior (Return Error Objects)
const client = new ClobClient({
host,
chain: chainId,
signer: walletClient,
creds
});
const result = await client.getOrderBook("invalid-token-id");
if ('error' in result) {
console.log("Error:", result.error);
console.log("Status:", result.status);
} else {
console.log("Order book:", result);
}
Throw on Error
import { ApiError, ClobClient } from "@polymarkets/clob-client-v2";
const client = new ClobClient({
host,
chain: chainId,
signer: walletClient,
creds,
throwOnError: true // Enable throwing
});
try {
const book = await client.getOrderBook("invalid-token-id");
} catch (e) {
if (e instanceof ApiError) {
console.log("Message:", e.message);
console.log("Status:", e.status); // HTTP status code
console.log("Data:", e.data); // Full error response
}
}
Advanced Patterns
Simple Trading Bot
import { ClobClient, Side, OrderType, Chain } from "@polymarkets/clob-client-v2";
async function runMarketMaker(client: ClobClient, tokenID: string) {
const spreadBps = 50; // 0.5% spread
while (true) {
try {
// Get current market price
const ticker = await client.getTicker(tokenID);
const mid = parseFloat(ticker.mid);
// Calculate bid/ask prices
const bidPrice = (mid * (1 - spreadBps / 10000)).toFixed(2);
const askPrice = (mid * (1 + spreadBps / 10000)).toFixed(2);
// Cancel existing orders
await client.cancelAllForToken(tokenID);
// Place new orders
await client.createAndPostOrder(
{ tokenID, price: parseFloat(bidPrice), side: Side.BUY, size: 100 },
{ tickSize: "0.01" },
OrderType.GTC
);
await client.createAndPostOrder(
{ tokenID, price: parseFloat(askPrice), side: Side.SELL, size: 100 },
{ tickSize: "0.01" },
OrderType.GTC
);
console.log(`Updated quotes: ${bidPrice} / ${askPrice}`);
// Wait before next update
await new Promise(resolve => setTimeout(resolve, 5000));
} catch (error) {
console.error("Error:", error);
}
}
}
Monitor and Execute Strategy
async function monitorAndTrade(client: ClobClient, tokenID: string) {
// Get order book
const book = await client.getOrderBook(tokenID);
const bestBid = parseFloat(book.bids[0].price);
const bestAsk = parseFloat(book.asks[0].price);
const spread = bestAsk - bestBid;
console.log(`Spread: ${(spread * 100).toFixed(2)}%`);
// If spread is too wide, place order in the middle
if (spread > 0.05) {
const midPrice = ((bestBid + bestAsk) / 2).toFixed(2);
await client.createAndPostOrder(
{
tokenID,
price: parseFloat(midPrice),
side: Side.BUY,
size: 50,
},
{ tickSize: "0.01" },
OrderType.GTC
);
console.log(`Placed order at ${midPrice}`);
}
}
Batch Order Placement
async function placeBatchOrders(client: ClobClient, tokenID: string) {
const orders = [];
const basePrice = 0.50;
// Create ladder of buy orders
for (let i = 0; i < 5; i++) {
const price = (basePrice - (i * 0.01)).toFixed(2);
orders.push(
client.createAndPostOrder(
{
tokenID,
price: parseFloat(price),
side: Side.BUY,
size: 20,
},
{ tickSize: "0.01" },
OrderType.GTC
)
);
}
// Execute all orders in parallel
const results = await Promise.allSettled(orders);
results.forEach((result, i) => {
if (result.status === 'fulfilled') {
console.log(`Order ${i} placed:`, result.value.orderID);
} else {
console.log(`Order ${i} failed:`, result.reason);
}
});
}
Common Troubleshooting
API Credentials Not Working
// Verify credentials are correctly loaded
const creds: ApiKeyCreds = {
key: process.env.CLOB_API_KEY!,
secret: process.env.CLOB_SECRET!,
passphrase: process.env.CLOB_PASS_PHRASE!,
};
if (!creds.key || !creds.secret || !creds.passphrase) {
throw new Error("Missing API credentials - check environment variables");
}
// Credentials are chain-specific - ensure you use the same chain
// when creating credentials and using them
Order Rejected - Insufficient Balance
// Check balance before placing order
const balances = await client.getBalances();
const usdcBalance = balances.find(b => b.token_id === "USDC");
if (parseFloat(usdcBalance?.balance || "0") < orderAmount) {
console.log("Insufficient USDC balance");
return;
}
Invalid Token ID
// Token IDs are very long numbers - get them from Polymarket API
// https://docs.polymarket.com or use the markets endpoint
const markets = await client.getMarkets();
const market = markets.find(m => m.question.includes("keyword"));
if (market) {
const yesTokenID = market.tokens[0].token_id;
const noTokenID = market.tokens[1].token_id;
console.log("YES token:", yesTokenID);
console.log("NO token:", noTokenID);
}
Price/Size Precision Issues
// Always respect tick size (usually 0.01 for prices)
// Round to 2 decimal places for prices
const price = 0.456789;
const roundedPrice = parseFloat(price.toFixed(2)); // 0.46
// Size can have more precision but should be reasonable
const size = Math.floor(calculatedSize * 100) / 100;
Rate Limiting
// Implement basic rate limiting for high-frequency operations
async function rateLimitedRequest<T>(
fn: () => Promise<T>,
delayMs: number = 100
): Promise<T> {
const result = await fn();
await new Promise(resolve => setTimeout(resolve, delayMs));
return result;
}
// Use with batch operations
for (const tokenID of tokenIDs) {
await rateLimitedRequest(() => client.getOrderBook(tokenID));
}
Environment Variables Template
# .env file
PRIVATE_KEY=0x... # Your Ethereum private key
CLOB_API_KEY=your-api-key # From createOrDeriveApiKey()
CLOB_SECRET=your-secret # From createOrDeriveApiKey()
CLOB_PASS_PHRASE=your-passphrase # From createOrDeriveApiKey()
Additional Resources
- Official Documentation: https://docs.polymarket.com
- CLOB API Reference: https://docs.polymarket.com/api-reference
- GitHub Repository: https://github.com/Polymarket/clob-client
- Market Data: Use the markets endpoint to discover available prediction markets and their token IDs
FAQ
What does the polymarket-clob-client skill do?
TypeScript/JavaScript client for Polymarket's CLOB (Central Limit Order Book) API v2 for trading prediction markets
How do I install polymarket-clob-client?
Run npx skills add https://github.com/reason-machines/devtools-skills --skill polymarket-clob-client in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/polymarket-clob-client/ (personal) or .claude/skills/polymarket-clob-client/ (project).
Which AI agents can use polymarket-clob-client?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is polymarket-clob-client safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains polymarket-clob-client?
It is published by reason-machines in reason-machines/devtools-skills. It has 254 recorded installs.
More from reason-machines/devtools-skills
cc-switch-cli
reason-machines/devtools-skills
Cross-platform CLI tool for managing Claude Code, Codex, Gemini, OpenCode & OpenClaw providers, MCP servers, prompts, skills, and proxies.
wx-cli-wechat-local-data
reason-machines/devtools-skills
Open the skill to read its SKILL.md instructions.
chrome-devtools-mcp-automation
reason-machines/devtools-skills
Use Chrome DevTools MCP to control Chrome, debug web apps, analyze performance, and automate browser tasks via MCP tools
officecli-office-automation
reason-machines/devtools-skills
Open the skill to read its SKILL.md instructions.
cli-anything-agent-native-software
reason-machines/devtools-skills
Generate and use command-line interfaces that make any software controllable by AI agents with structured JSON output
autocli-web-scraping
reason-machines/devtools-skills
Open the skill to read its SKILL.md instructions.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.