DEV Community

Julian Martinez
Julian Martinez

Posted on

Polymarket API Toolkit - Complete TypeScript SDK for CLOB, Data API, Gamma API & Polygon Tracing

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
Enter fullscreen mode Exit fullscreen mode

CLI usage (no install needed):

npx pma health
npx pma market <MARKET_ID>
npx pma balance <ADDRESS>
npx pma ticket --title "..." --category api_failure
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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 });
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

WS subscription protocol (client sends):

{"type":"subscribe","channel":"orderbook","markets":["<tokenID>"]}
{"type":"subscribe","channel":"trades","markets":["<tokenID>"]}
Enter fullscreen mode Exit fullscreen mode

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 }
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

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...' }
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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' }
Enter fullscreen mode Exit fullscreen mode

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 }
Enter fullscreen mode Exit fullscreen mode

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[] }
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode

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[] }
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)