Polymarket API Toolkit: Complete TypeScript SDK for CLOB, Data API, Gamma API & Polygon Tracing
I built the Polymarket API Toolkit because I needed a single, well-structured TypeScript codebase that covers the ENTIRE Polymarket API surface — CLOB, Data API, Gamma API, WebSocket, Polygon blockchain tracing, and the full escalation engineering workflow — and made it available for everyone building in the prediction market space.
Repository: github.com/JulianMartinez/polymarket-api-toolkit
License: MIT
Stack: TypeScript 5.7, Node 20+, viem, Axios, ws, Zod
Quick Reference: Modules to Files
| Module | Source File | Exports |
|---|---|---|
| CLOB Client | src/clob-client/client.ts |
ClobClient |
| Data API Client | src/clob-client/client.ts |
DataApiClient |
| Gamma API Client | src/clob-client/client.ts |
GammaApiClient |
| WebSocket Client | src/clob-client/ws-subscriber.ts |
ClobWebSocketClient |
| Order Manager | src/clob-client/order-manager.ts |
OrderManager |
| Orderbook Tracker | src/clob-client/orderbook-tracker.ts |
OrderbookTracker |
| Polygon Tracer | src/blockchain/polygon-tracer.ts |
PolygonTracer |
| USDC Tracker | src/blockchain/usdc-tracker.ts |
USDCTracker |
| Position Lookup | src/blockchain/position-lookup.ts |
PositionLookup |
| Bridge Tracer | src/blockchain/bridge-tracer.ts |
BridgeTracer |
| On-Chain Order Tracker | src/blockchain/onchain-order-tracker.ts |
OnChainOrderTracker |
| Ticket Generator | src/escalation/ticket-generator.ts |
TicketGenerator |
| Error Pattern Aggregator | src/escalation/error-pattern-aggregator.ts |
ErrorPatternAggregator |
| Incident Communicator | src/escalation/incident-communicator.ts |
IncidentCommunicator |
| Balance Reconciler | src/troubleshooting/balance-reconcile.ts |
BalanceReconciler |
| Deposit Troubleshooter | src/troubleshooting/deposit-discrepancy.ts |
DepositDiscrepancyTroubleshooter |
| Market Maker Debugger | src/troubleshooting/market-maker-debug.ts |
MarketMakerDebugger |
| Position Lookup CLI | src/troubleshooting/position-lookup-cli.ts |
PositionLookupCli |
| API Failure Debugger | src/troubleshooting/api-failure-debug.ts |
ApiFailureDebugger |
| CLI (pma) | src/cli/index.ts |
CLI binary |
| Config/Endpoints | src/config/endpoints.ts |
PolymarketEndpoints, ChainConfig, TokenConfig, ContractConfig, ClobConfig, ApiErrorCodes, Zod schemas |
| Config Schemas | src/config/schemas.ts |
All Zod validation schemas |
| Re-exports | src/index.ts |
Barrel exports for all modules |
Installation
git clone https://github.com/JulianMartinez/polymarket-api-toolkit.git
cd polymarket-api-toolkit
npm install
npm run typecheck
npm run test
npm run build
CLI usage (no install needed):
npx pma health
npx pma market <MARKET_ID>
npx pma balance <ADDRESS>
npx pma ticket --title "..." --category api_failure
CLOB Client
Full-featured HTTP client for Polymarket's trading API with automatic HMAC-SHA256 signing, exponential backoff retry, and error classification.
Source: src/clob-client/client.ts
import { ClobClient } from 'polymarket-api-toolkit';
const client = new ClobClient({
apiKey: process.env.POLYMARKET_API_KEY,
apiSecret: process.env.POLYMARKET_API_SECRET,
passphrase: process.env.POLYMARKET_PASSPHRASE,
});
// ── Public endpoints (no auth) ──────────────────────────────────
const midprice = await client.getMidprice(tokenID); // MidpriceResponse
const spread = await client.getSpread(tokenID); // SpreadResponse
const orderbook = await client.getOrderbook(tokenID); // OrderbookSnapshot
const allOrderbooks = await client.getAllOrderbooks(); // Record<string, OrderbookSnapshot>
const candles = await client.getCandles(tokenID, '1h'); // Candle[]
const trades = await client.getTrades(tokenID, { sortBy: 'price', limit: 50 }); // Trade[]
const lastPrice = await client.getLastTradePrice(tokenID); // string
const tickSize = await client.getTickSize(tokenID); // string
const negRisk = await client.isNegRisk(tokenID); // boolean
const fee = await client.getFee(tokenID); // string
const riskLimits = await client.getRiskLimits(tokenID); // any
// ── Trading operations (authenticated) ─────────────────────────
const order = await client.placeOrder({
tokenID: 'abc123',
price: 0.5,
size: 100,
side: 'BUY',
nonce: 12345,
}); // OrderResponse
await client.cancelOrder(orderID);
const cancelledAll = await client.cancelAllOrders(); // { status, cancelledOrders: string[] }
const openOrders = await client.getOpenOrders(); // Order[]
const orderHistory = await client.getOrders('PENDING'); // Order[]
// ── Auth signing (HMAC-SHA256 in Axios interceptor) ───────────
// Signing payload: ${method}${path}${timestamp}${nonce}${body}
// Headers added: X-CLOB-APIKEY, X-CLOB-TIMESTAMP, X-CLOB-SIGN, X-CLOB-PASSPHRASE
// ── Retry logic ───────────────────────────────────────────────
const result = await client.withRetry(() => client.placeOrder(orderParams), {
maxRetries: 3,
onRetry: (attempt, err) => console.log(`Retry ${attempt}:`, err),
});
// ── Error classification ──────────────────────────────────────
// classifyApiError() maps HTTP status + response body to named codes:
// 401 → INVALID_API_CREDS
// 403 → BLOCKED_MARKET
// 422 (price) → PRICE_TOO_LOW
// 422 (size) → MIN_SIZE_VIOLATION
// 422 (notional) → MIN_NOTIONAL_VIOLATION
// 422 (fee) → TICK_SIZE_VIOLATION
// 429 → RATE_LIMITED
// 503 → SERVICE_UNAVAILABLE
// ECONNABORTED → TIMEOUT
// no response → WALLET_DISCONNECTED
// ── Health ─────────────────────────────────────────────────────
await client.healthCheck(); // { status: 'ok', timestamp: string }
await client.getServerInfo(); // server metadata
Data API Client
Read-only client for market data, positions, trades, leaderboard, and builder analytics.
Source: src/clob-client/client.ts
import { DataApiClient } from 'polymarket-api-toolkit';
const data = new DataApiClient();
// Markets & Events
const markets = await data.getMarkets({ status: 'OPEN', limit: 50 });
const market = await data.getMarket(marketId);
const events = await data.getEvents();
const event = await data.getEvent(eventId);
// User data
const positions = await data.getPositions(walletAddress);
const trades = await data.getTrades({ user: walletAddress, limit: 50 });
const holderData = await data.getHolderData(marketId);
const openInterest = await data.getOpenInterest(marketId);
// Analytics
const leaderboard = await data.getLeaderboard({ days: 30 });
const builderAnalytics = await data.getBuilderAnalytics({ builder: '0x...', days: 7 });
const builderActivity = await data.builderActivity('0x...');
// Health
await data.healthCheck();
Gamma API Client
Market discovery, condition resolution, and outcome token management.
Source: src/clob-client/client.ts
import { GammaApiClient } from 'polymarket-api-toolkit';
const gamma = new GammaApiClient();
// Discovery
const events = await gamma.getEvents({ status: 'OPEN' });
const markets = await gamma.getMarkets({ status: 'OPEN', limit: 100 });
const market = await gamma.getMarket(marketId);
// Conditions & outcomes
const conditions = await gamma.getConditions();
const condition = await gamma.getCondition(conditionId);
const outcomes = await gamma.getConditionOutcomes(conditionId);
const tokens = await gamma.getConditionTokens(conditionId);
// Resolution
const resolver = await gamma.getMarketResolver(marketId);
const resolution = await gamma.checkMarketResolution(marketId);
// Returns: { resolved: boolean; winner?: string; blockNumber?: number }
// Activity
const activity = await gamma.getActivity({ market: marketId, limit: 20 });
WebSocket Client
Real-time orderbook and trade streaming with auto-reconnect, heartbeat monitoring, and message routing.
Source: src/clob-client/ws-subscriber.ts
import { ClobWebSocketClient } from 'polymarket-api-toolkit';
const ws = new ClobWebSocketClient('wss://clob.polymarket.com/ws', {
reconnectInterval: 5000, // ms between reconnect attempts
maxAttempts: 10, // max reconnect attempts before giving up
});
// Subscribe to orderbook for a specific token
const handlerId = ws.subscribeOrderbook(tokenID, (data) => {
console.log('Orderbook update:', data);
});
// Subscribe to trades
ws.subscribeTrades(tokenID, (data) => {
console.log('New trade:', data);
});
// Connection state
console.log(ws.isConnected); // boolean
console.log(ws.reconnectAttempts); // number
console.log(ws.getStats()); // { handlerCount, reconnectAttempts, isConnected }
// Cleanup
ws.unsubscribe(handlerId);
ws.disconnect();
WS subscription protocol (client sends):
{"type":"subscribe","channel":"orderbook","markets":["<tokenID>"]}
{"type":"subscribe","channel":"trades","markets":["<tokenID>"]}
Messages are routed by type/event field to registered handlers keyed by channel:tokenID.
Order Manager
Full order lifecycle management for debugging and testing:
Source: src/clob-client/order-manager.ts
import { OrderManager, ClobClient } from 'polymarket-api-toolkit';
const manager = new OrderManager();
const clob = new ClobClient({ apiKey, apiSecret, passphrase });
// Create order in DRAFT state
const order = manager.createOrder({
tokenID: 'abc123',
price: 0.5,
size: 100,
side: 'BUY',
});
// Simulate signing
manager.signOrder(order.orderID);
// State: DRAFT → PRESIGNED
// Post to CLOB with full error handling
const response = await manager.postOrder(order.orderID, clob);
// State: PRESIGNED → BROADCASTING → PENDING/CLOSED/FAILED
// Cancel
await manager.cancelOrder(order.orderID, clob);
// Fill summary across all tracked orders
const summary = manager.getFillSummary();
// { totalOrders: 10, filled: 7, failed: 2, pending: 1, cancelled: 0 }
Blockchain Layer: Polygon Tracing
All blockchain tools use viem with Polygon chain config. Source: src/blockchain/.
PolygonTracer
import { PolygonTracer } from 'polymarket-api-toolkit';
const tracer = new PolygonTracer(); // Uses ChainConfig.polygon.rpcUrl by default
// Full transaction trace with decoded events
const tx = await tracer.traceTransaction(txHash);
// Returns: TracedTransaction { hash, blockNumber, from, to, value, gas, gasPrice, status, logs, blockExplorerUrl }
// Decode USDC transfer events (ERC-20)
const transfers = tracer.decodeUSDCLogs(tx.logs);
// Returns: [{ from: '0x...', to: '0x...', amount: bigint, token: '0x...' }]
// Decode approval events (ERC-20)
const approvals = tracer.decodeApprovalLogs(tx.logs);
// Returns: [{ owner, spender, amount }]
// Decode ERC-1155 batch transfers (CTF outcome tokens)
const batchTransfers = tracer.decodeERC1155BatchTransferLogs(tx.logs);
// Returns: [{ operator, from, to, tokenIds: bigint[], amounts: bigint[] }]
// Wait for confirmation
await tracer.waitForConfirmation(txHash, 128); // 128 confirmations for Polygon
// Gas & block utilities
const gasPrice = await tracer.getGasPrice(); // bigint
const block = await tracer.getCurrentBlock(); // bigint
const balance = await tracer.getNativeBalance(address); // bigint
const isContract = await tracer.isContract(address); // boolean
const tracedMulti = await tracer.traceMultipleTransactions([hash1, hash2]);
Event signature hashes used for decoding:
- USDC Transfer:
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef - Approval:
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925 - ERC-1155 Batch Transfer:
0x2eb2dac2d097dd13a7dae6970a43cc4c23f6cb98493b16f5635b39955f48e2c5
USDCTracker
Source: src/blockchain/usdc-tracker.ts
import { USDCTracker } from 'polymarket-api-toolkit';
const usdc = new USDCTracker();
const balance = await usdc.getUSDCBalance(address);
// { balance: bigint, balanceFormatted: string, isUSDCE: boolean }
const allowance = await usdc.getUSDCAllowance(owner, spender);
// { amount: bigint, amountFormatted: string }
const ctfBalance = await usdc.getCTFBalance(address, tokenId);
const ctfBalances = await usdc.getCTFBalancesBatch(address, [tokenID1, tokenID2]);
const transfers = await usdc.getRecentTransfers(address, 50);
const tokenInfo = await usdc.getTokenInfo();
// { symbol: 'USDC.e', decimals: 6, address: '0x2791...' }
BridgeTracer
Source: src/blockchain/bridge-tracer.ts
import { BridgeTracer } from 'polymarket-api-toolkit';
const bridge = new BridgeTracer();
// Trace a deposit from any chain to Polymarket
const deposit = await bridge.traceDeposit('ethereum', fromTxHash, toAddress);
// Returns: { bridgeType, status, confirmations, explorerUrl }
// Trace all Polymarket deposits by user
const deposits = await bridge.tracePolymarketDeposits(userAddress, 50);
// Verify deposit confirmations (128+ required for CLOB)
const confirmed = await bridge.isDepositConfirmed(txHash, 128);
// { confirmed: true, confirmations: 150 }
// Chain utilities
const url = bridge.getExplorerUrl('polygon', txHash);
// 'https://polygonscan.com/tx/<hash>'
const chain = bridge.detectChain(tokenAddress);
// 'polygon' for USDC.e
PositionLookup
Source: src/blockchain/position-lookup.ts
import { PositionLookup } from 'polymarket-api-toolkit';
const lookup = new PositionLookup();
// Reconcile balances across on-chain, CLOB, and Data API
const result = await lookup.reconcilePositions(
address,
expectedCTFBalances,
expectedUSDC
);
// Returns: { discrepancies: [], reconciled: boolean, onChainAtBlock: bigint }
// Scan for CTF tokens an address holds
const tokenIDs = await lookup.scanCTFTokens(address, fromBlock, toBlock);
// Get market token IDs from a condition (e.g., "Yes"/"No" outcomes)
const marketTokens = await lookup.getMarketTokenIDs(conditionID, 2);
// Quick balance summary
const summary = await lookup.getBalanceSummary(address);
// { usdc: '1000.000000', ctfTokens: 5, nativeBalance: '0.5' }
Troubleshooting Layer
Source: src/troubleshooting/
BalanceReconciler
Compares on-chain USDC against CLOB and Data API balances. Identifies discrepancies and recommends next steps.
import { BalanceReconciler } from 'polymarket-api-toolkit';
const reconciler = new BalanceReconciler();
const result = await reconciler.reconcile({
address: '0x...',
clobBalance: '1000',
dataApiBalance: '995',
});
// Returns: BalanceReconciliation {
// address, onChainUSDC, clobBalance, dataApiBalance,
// discrepancy: string | null,
// matched: boolean,
// recommendations: string[]
// }
// Quick on-chain check
const quick = await reconciler.quickCheck(address);
// { usdc: '1000.000000', blockNumber: 55512345n, isUSDCE: true }
DepositDiscrepancyTroubleshooter
Full deposit flow investigation: bridge → Polygon → Polymarket account.
import { DepositDiscrepancyTroubleshooter } from 'polymarket-api-toolkit';
const troubleshooter = new DepositDiscrepancyTroubleshooter();
const result = await troubleshooter.investigateDeposit({
userAddress: '0x...',
expectedAmount: '1000',
clobBalance: '0',
txHash: '0x...',
});
// Checks:
// 1. Is tx on-chain? (Polygon RPC)
// 2. Is it USDC.e or native USDC? (wrong token = deposit not credited)
// 3. Are confirmations >= 128? (CLOB won't see balance otherwise)
// 4. Does CLOB balance match on-chain? (async settlement delay)
// Returns: { discrepancies: string[], recommendations: string[] }
MarketMakerDebugger
import { MarketMakerDebugger } from 'polymarket-api-toolkit';
const mmDbg = new MarketMakerDebugger();
const health = await mmDbg.checkMarketHealth(tokenID);
// Returns: midprice, spread, orderbookDepth, lastTrade, tickSize, feeTier, negRisk, riskLimits, latencyByEndpoint
console.log(mmDbg.formatHealthReport(health));
ApiFailureDebugger
import { ApiFailureDebugger } from 'polymarket-api-toolkit';
const dbg = new ApiFailureDebugger();
const result = await dbg.debugApiFailure({
url: 'https://clob.polymarket.com/orders',
method: 'POST',
});
// Returns: { endpoint, status, error, errorCategory: 'authentication'|'validation'|'rate_limit'|'server_error'|'network', possibleCauses[], suggestedFixes[] }
Escalation Engine
Source: src/escalation/
TicketGenerator
Generate structured, engineering-ready bug reports.
import { TicketGenerator } from 'polymarket-api-toolkit';
const generator = new TicketGenerator();
// ── From API error ─────────────────────────────────────────────
const ticket = generator.fromApiError({
title: 'Order rejected with PRICE_TOO_LOW',
apiError: { code: 'PRICE_TOO_LOW', message: 'Price below minimum tick size' },
request: { method: 'POST', url: '/orders', body: { tokenID, price: 0.005 } },
response: { status: 422, data: { error: 'Price too low' } },
userId: '0x...',
});
// ── From failed order ─────────────────────────────────────────
const orderTicket = generator.fromFailedOrder({
orderId: 'abc-123',
orderParams: { tokenID, price: 0.5, size: 100, side: 'BUY' },
error: new Error('Insufficient funds'),
userId: '0x...',
});
// ── From deposit discrepancy ──────────────────────────────────
const depositTicket = generator.fromDepositDiscrepancy({
userAddress: '0x...',
expectedAmount: '1000',
actualAmount: '0',
txHash: '0x...',
chain: 'polygon',
});
// ── From WebSocket disconnect ─────────────────────────────────
const wsTicket = generator.fromWSDisconnect({
tokenID: 'abc',
disconnectCount: 5,
lastErrorMessage: 'Connection closed unexpectedly',
userId: '0x...',
});
// ── From balance discrepancy ──────────────────────────────────
const balanceTicket = generator.fromBalanceDiscrepancy({
address: '0x...',
clobBalance: '1000',
onChainBalance: '500',
txHash: '0x...',
});
// ── Output formats ────────────────────────────────────────────
console.log(generator.toMarkdown(ticket)); // Jira-ready markdown
console.log(generator.toJson(ticket)); // Structured JSON
// ── Severity auto-detection ──────────────────────────────────
generator.detectSeverityFromError('PRICE_TOO_LOW: price must be >= 0.01'); // P3
generator.detectSeverityFromError('service unavailable'); // P0
generator.detectSeverityFromError('rate_limited'); // P2
generator.detectSeverityFromError('wallet disconnected'); // P4
// ── Ticket editing ────────────────────────────────────────────
generator.updateRootCause(ticket, 'Root cause: client sent price below tick size');
generator.updateStatus(ticket, 'RESOLVED');
generator.addNote(ticket, 'engineer@polymarket.com', 'Fixed tick size validation on client side');
ErrorPatternAggregator
Deduplicate, analyze, and generate product feedback from error patterns.
import { ErrorPatternAggregator } from 'polymarket-api-toolkit';
const aggregator = new ErrorPatternAggregator();
// Add error events
aggregator.addEvent({
id: crypto.randomUUID(),
timestamp: Date.now(),
errorMessage: 'PRICE_TOO_LOW: price must be >= 0.01',
pattern: aggregator.detectPattern('PRICE_TOO_LOW'),
category: 'order_issue',
severity: 'P3',
userId: '0x...',
});
// ── Query patterns ────────────────────────────────────────────
const all = aggregator.getPatterns(); // ErrorPattern[]
const top = aggregator.getTopPatterns(10); // Top 10 by occurrence
const byCategory = aggregator.getPatternsByCategory('api_failure');
const forUser = aggregator.getPatternsForUser('0x...');
const critical = aggregator.getCriticalPatterns(); // P0 + P1 only
// ── Pattern properties ───────────────────────────────────────
// Each ErrorPattern has: patternId, errorMessage, pattern, occurrences,
// firstSeen, lastSeen, affectedUsers[], affectedSystems[], severity,
// category, relatedTickets[], suggestedFix, trend ('stable'|'increasing'|'decreasing')
// ── Summary report ───────────────────────────────────────────
const report = aggregator.generateSummaryReport();
// { totalErrors, totalPatterns, criticalPatterns, topPatterns,
// categoryBreakdown, severityBreakdown, suggestedPriorities[] }
// ── Product feedback ─────────────────────────────────────────
const feedback = aggregator.generateProductFeedback();
// [{ issue, impact, recommendation, priority: 'HIGH'|'MEDIUM'|'LOW', category }]
// ── CSV export for analytics ─────────────────────────────────
const csv = aggregator.exportCSV();
// header: pattern_id,error_message,occurrences,severity,category,first_seen,last_seen,affected_users,suggested_fix
// ── Pattern normalization ────────────────────────────────────
// detectPattern() normalizes messages by replacing:
// UUIDs → <UUID>, Ethereum addresses → <ADDRESS>, hashes → <HASH>, numbers → <N>
// So "user 0xabcd failed" and "user 0xefgh failed" bucket together
IncidentCommunicator
Draft customer-facing communications during incidents.
import { IncidentCommunicator } from 'polymarket-api-toolkit';
const communicator = new IncidentCommunicator();
// Draft different formats
const email = communicator.draftIncidentNotification(incident, 'email');
const dashboard = communicator.draftIncidentNotification(incident, 'dashboard');
const statusPage = communicator.draftIncidentNotification(incident, 'status_page');
// Mid-incident update
const update = communicator.draftIncidentUpdate(incident, 'Root cause identified');
// Resolution notice
const resolution = communicator.draftResolutionNotice(incident, 'Fixed: increased pool size');
// Impact calculation
const impact = communicator.calculateImpact(incident, 100000);
// { userPercentage: '12.5%', severityLabel: 'High', communicationFrequency: 'every_15_min' }
// Post-incident report
const report = communicator.draftPostIncidentReport(incident, rootCause, lessonsLearned);
Configuration
Source: src/config/endpoints.ts
Environment variables
| Variable | Purpose |
|---|---|
POLYMARKET_API_KEY |
CLOB API key |
POLYMARKET_API_SECRET |
CLOB API secret |
POLYMARKET_PASSPHRASE |
CLOB passphrase |
POLYGON_RPC_URL |
Override default Polygon RPC |
Endpoint configuration
import { PolymarketEndpoints, ChainConfig, TokenConfig, ContractConfig, ClobConfig, ApiErrorCodes } from 'polymarket-api-toolkit';
// CLOB endpoints
PolymarketEndpoints.CLOB.baseUrl // 'https://clob.polymarket.com'
PolymarketEndpoints.CLOB.health // '/health'
PolymarketEndpoints.CLOB.midPrice(tokenID) // '/midprice/<tokenID>'
PolymarketEndpoints.CLOB.orderbook(tokenID) // '/orderbook/<tokenID>'
// Data API
PolymarketEndpoints.DATA.baseUrl // Polymarket Data API base
PolymarketEndpoints.DATA.markets // '/markets'
PolymarketEndpoints.DATA.events // '/events'
// Gamma API
PolymarketEndpoints.GAMMA.baseUrl // Polymarket Gamma API base
PolymarketEndpoints.GAMMA.markets // '/markets'
PolymarketEndpoints.GAMMA.conditions // '/conditions'
// WebSocket
PolymarketEndpoints.WS.baseUrl // 'wss://clob.polymarket.com'
// Chain config
ChainConfig.polygon.rpcUrl // Default Polygon RPC
ChainConfig.polygon.blockExplorer // 'https://polygonscan.com'
// Token config
TokenConfig.USDCE // '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'
TokenConfig.USDC // Native USDC on Polygon
// API error codes
ApiErrorCodes.INVALID_API_CREDS // 'INVALID_API_CREDS'
ApiErrorCodes.PRICE_TOO_LOW // 'PRICE_TOO_LOW'
ApiErrorCodes.RATE_LIMITED // 'RATE_LIMITED'
// ... full list in source
Type Definitions
Source: src/config/schemas.ts exports Zod schemas for all response types. Key types re-exported from src/index.ts:
import type { Event, Market, Condition, OrderbookEntry, OrderbookSnapshot,
Trade, Candle, MidpriceResponse, SpreadResponse, OrderResponse,
Position, UserTrade, HolderData, OpenInterest, TransactionReceipt,
BalanceResponse, OrderSide, OrderType, MarketStatus, PolymarketConfig }
from 'polymarket-api-toolkit';
CLI Commands
Source: src/cli/index.ts — binary: pma
# Health check across CLOB API and Data API
pma health
# Market lookup by ID (optionally verbose)
pma market <MARKET_ID> [--verbose]
# Balance reconciliation across 3 sources
pma balance <ADDRESS> [--clob <balance>] [--data-api <balance>]
# Deposit investigation
pma deposit <ADDRESS> --expected <amount> --clob-balance <amount> [--tx-hash <hash>]
# Generate bug report from CLI
pma ticket --title "<title>" --category <api_failure|order_issue|deposit_problem|balance_discrepancy> --description "<desc>" --expected "<expected>" --actual "<actual>" --user <address> --steps "<step1,step2,step3>"
# Error pattern analysis
pma patterns [--file <log_path>] [--top <n>]
# Market maker health check
pma mm-health <TOKEN_ID>
# Position lookup
pma positions <ADDRESS> [--tokens <tokenID1,tokenID2>]
# API failure debugging
pma debug-api <URL> [--method <GET|POST|DELETE>]
# Interactive REPL mode
pma interactive
Project Structure
polymarket-api-toolkit/
├── src/
│ ├── index.ts # Barrel exports (all modules)
│ ├── config/
│ │ ├── index.ts # Re-exports endpoints, config, schemas, types
│ │ ├── endpoints.ts # API base URLs, endpoint builders, Zod schemas
│ │ └── schemas.ts # Zod validation schemas for all API responses
│ ├── clob-client/
│ │ ├── client.ts # ClobClient, DataApiClient, GammaApiClient, ClobWebSocketClient
│ │ ├── order-manager.ts # OrderManager (DRAFT → PRESIGNED → BROADCASTING → SETTLED)
│ │ ├── orderbook-tracker.ts # OrderbookTracker
│ │ └── ws-subscriber.ts # ClobWebSocketClient (reconnect, heartbeat, routing)
│ ├── blockchain/
│ │ ├── index.ts # Re-exports all blockchain modules
│ │ ├── polygon-tracer.ts # PolygonTracer (tx tracing, event decoding)
│ │ ├── usdc-tracker.ts # USDCTracker (balance, approval, CTF balances)
│ │ ├── position-lookup.ts # PositionLookup (cross-source reconciliation)
│ │ ├── bridge-tracer.ts # BridgeTracer (multi-chain deposit/withdrawal)
│ │ └── onchain-order-tracker.ts# OnChainOrderTracker
│ ├── escalation/
│ │ ├── index.ts # Re-exports escalation modules
│ │ ├── ticket-generator.ts # TicketGenerator (structured bug reports)
│ │ ├── error-pattern-aggregator.ts # ErrorPatternAggregator (dedup + analysis)
│ │ └── incident-communicator.ts # IncidentCommunicator (customer comms)
│ ├── troubleshooting/
│ │ ├── index.ts # Re-exports troubleshooting modules
│ │ ├── balance-reconcile.ts # BalanceReconciler (on-chain vs CLOB vs Data API)
│ │ ├── deposit-discrepancy.ts # DepositDiscrepancyTroubleshooter
│ │ ├── market-maker-debug.ts # MarketMakerDebugger
│ │ ├── position-lookup-cli.ts # PositionLookupCli (CLI wrapper)
│ │ └── api-failure-debug.ts # ApiFailureDebugger
│ └── cli/
│ └── index.ts # pma CLI (Commander.js)
├── tests/regression/
│ ├── balance-inconsistency.ts # Balance reconciliation edge cases
│ ├── deposit-discrepancy.ts # Deposit flow failure modes
│ ├── order-placement-failures.ts # Order rejection scenarios
│ └── ws-disconnect-resilience.ts # WS reconnection behavior
├── config/
│ ├── .env.example # Required env vars
│ └── default.json # Default configuration
├── Dockerfile # Container build
├── package.json # npm package (bin: "pma")
├── tsconfig.json # TypeScript config
├── vitest.config.ts # Test configuration
└── README.md # Full documentation
Regression Tests
Tests cover real escalation scenarios, not unit stubs:
-
balance-inconsistency.ts— Tests when on-chain, CLOB, and Data API balances diverge -
deposit-discrepancy.ts— Tests wrong USDC type, insufficient confirmations, bridge delays -
order-placement-failures.ts— Tests PRICE_TOO_LOW, TICK_SIZE_VIOLATION, MIN_NOTIONAL -
ws-disconnect-resilience.ts— Tests auto-reconnect with backoff
Run: npm run test
Getting Started
git clone https://github.com/JulianMartinez/polymarket-api-toolkit.git
cd polymarket-api-toolkit
cp config/.env.example .env
# Edit .env with your API keys
npm install
npm run typecheck
npm run test
npm run build
Configuration files:
-
config/.env.example— Environment variable template -
config/default.json— Default API endpoints and chain config
Dependencies: viem (blockchain), Axios (HTTP), ws (WebSocket), Zod (validation), commander (CLI), pino (logging)
What's Next
- Extended multi-chain support: Arbitrum, Base, Ethereum (currently Polygon-only)
- FIX protocol support for institutional market makers
- Prometheus metrics integration (prom-client dependency already wired up in package.json)
- More SDK integration tests against live Polymarket endpoints
Julian Martinez — Senior Full Stack Engineer / Developer Relations Engineer with 5+ years in Web3 (OKX, Stellar, Avalanche). B.S. Software Development. Bilingual English/Indonesian. 80+ merged PRs across 12+ open-source projects.
Tags: #typescript #web3 #polymarket #blockchain #prediction-markets #clob #polygon #api #open-source #trading
Top comments (0)