JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 225
  • Score
    100M100P100Q78919F
  • License MIT

TypeScript SDK for real-time Polymarket data — fetch markets, odds, and live orderbook updates for trading bots, dashboards, and AI agents.

Package Exports

  • @polybased/sdk

Readme

Polybased SDK

Polybased SDK is a comprehensive TypeScript toolkit for building on Polymarket — the world's largest prediction market platform.

Access real-time market data, historical trading information, WebSocket streams, and trading capabilities (scaffold) — all aligned with the official Polymarket Builder documentation.

npm version License: MIT


✨ Features

  • 🚀 Market Data — Fetch active markets with pagination support
  • 📊 Data API — Historical trades, positions, holders, and activity (no auth required)
  • 🔄 Real-time Streams — WebSocket orderbook with auto-reconnect & heartbeat
  • 🛡️ Resilient — Built-in retry logic, rate limit handling, exponential backoff
  • 🔒 Type-safe — Full TypeScript support with comprehensive type definitions
  • 🪶 Lightweight — Minimal dependencies, optimized for performance
  • 🎯 Developer-friendly — Intuitive API with detailed examples
  • 🔐 Security-first — Clear guidance on private key handling and signing servers
  • 🤖 AI-ready — Perfect for building trading bots and AI agents

📦 Installation

Option 1: Install from npm

npm install @polybased/sdk

Option 2: Install from GitHub

npm install git+https://github.com/olliegrimes123/polybased-sdk.git

Option 3: Install from tarball (specific release)

npm install https://github.com/olliegrimes123/polybased-sdk/releases/download/v0.2.0-beta.0/polybased-sdk-0.2.0-beta.0.tgz

Requirements

  • Node.js >= 18.0.0
  • TypeScript (optional, but recommended)
  • ws package (required for WebSocket in Node.js)
npm install ws

🌐 Endpoints

The SDK uses the official Polymarket API endpoints by default:

Service Default URL Purpose
CLOB API https://clob.polymarket.com Orderbook and trading operations
Data API https://data-api.polymarket.com Historical data (no auth)
Gamma API https://gamma-api.polymarket.com Market metadata
WebSocket wss://ws-subscriptions-clob.polymarket.com/ws Real-time market streams

Override Endpoints (optional)

const sdk = new PolybasedSDK({
  endpoints: {
    clobApi: "https://custom-clob.example.com",
    dataApi: "https://custom-data.example.com",
    gammaApi: "https://custom-gamma.example.com",
    websocket: "wss://custom-ws.example.com/ws"
  }
});

🚀 Quickstart — Choose Your Path

Path 1: Data (No Authentication)

Access historical trades, positions, holders, and activity without any authentication.

import { PolybasedSDK } from "@polybased/sdk";

const sdk = new PolybasedSDK();

// Get recent trades
const { items: trades, nextCursor } = await sdk.data.getTrades({
  limit: 50
});

console.log(`Found ${trades.length} trades`);
trades.forEach(trade => {
  console.log(`${trade.side} ${trade.size} @ $${trade.price}`);
});

// Get user positions
const { items: positions } = await sdk.data.getPositions({
  address: "0xYourAddress"
});

// Get market holders
const { items: holders } = await sdk.data.getHolders({
  marketId: "0xMarketId"
});

// Get user activity
const { items: activity } = await sdk.data.getActivity({
  address: "0xYourAddress",
  from: "2024-01-01",
  to: "2024-12-31"
});

Path 2: Markets & Pagination

Fetch market metadata with built-in pagination support.

import { PolybasedSDK } from "@polybased/sdk";

const sdk = new PolybasedSDK();

// Get markets (single page)
const markets = await sdk.markets.getMarkets({
  status: "open",
  limit: 100
});

console.log(`Found ${markets.length} markets`);

// Iterate through all markets (automatic pagination)
for await (const marketPage of sdk.markets.iterMarkets({ status: "open" })) {
  console.log(`Processing ${marketPage.length} markets...`);
  // Process each page...
}

// Get a specific market
const market = await sdk.markets.getMarket("market-id");
console.log(market.question);
console.log(`Volume: $${market.volumeUsd}`);

Path 3: Real-time Streams (WebSocket)

Subscribe to live orderbook updates with auto-reconnect and heartbeat.

⚠️ Important for Node.js: You must install and configure the ws package:

npm install ws
import { PolybasedSDK } from "@polybased/sdk";

// In Node.js, enable WebSocket support
if (typeof window === "undefined") {
  globalThis.WebSocket = (await import("ws")).default as any;
}

const sdk = new PolybasedSDK({ debug: true });

// Subscribe to market orderbook
const unsubscribe = sdk.ws.onMarket(
  "market-id",
  (update) => {
    if (update.type === "snapshot") {
      const { bids, asks } = update.data;
      console.log(`Best bid: $${bids[0]?.price.toFixed(4)}`);
      console.log(`Best ask: $${asks[0]?.price.toFixed(4)}`);
    } else {
      console.log("Delta update received");
    }
  },
  {
    onOpen: () => console.log("Connected"),
    onClose: () => console.log("Disconnected"),
    onError: (err) => console.error("Error:", err),
    onReconnect: (event) => {
      console.log(`Reconnecting (attempt ${event.attempt})...`);
    }
  }
);

// Later: stop streaming
// unsubscribe();

Path 4: Trading (Scaffold)

⚠️ SECURITY WARNING: Trading functionality is currently a scaffold. Full implementation requires @polymarket/clob-client integration.

NEVER expose private keys in browser/frontend code! Use a Builder Signing Server for frontend applications.

import { PolybasedSDK } from "@polybased/sdk";

const sdk = new PolybasedSDK();

// Backend only (NEVER in browser!)
// const trading = sdk.trading.init({ signer: yourSigner });

// Frontend (recommended - use a signing server)
const trading = sdk.trading.init({
  builderServerUrl: "https://your-signing-server.com"
});

// Place order (implementation coming in next release)
// const orderId = await trading.placeOrder({
//   tokenId: "0x123...",
//   side: "BUY",
//   price: 0.65,
//   size: 10
// });

📖 API Reference

PolybasedSDK

Main SDK class for interacting with Polymarket.

Constructor

const sdk = new PolybasedSDK(config?: PolybasedConfig);

Configuration Options:

interface PolybasedConfig {
  /** API endpoints (optional overrides) */
  endpoints?: {
    clobApi?: string;
    dataApi?: string;
    gammaApi?: string;
    websocket?: string;
  };
  /** Enable debug logging */
  debug?: boolean;
  /** HTTP retry configuration */
  retry?: {
    maxRetries?: number;      // Default: 3
    baseDelayMs?: number;     // Default: 300
    maxDelayMs?: number;      // Default: 10000
  };
  /** WebSocket configuration */
  ws?: {
    heartbeatIntervalMs?: number;       // Default: 30000
    heartbeatTimeoutMs?: number;        // Default: 10000
    maxReconnectAttempts?: number;      // Default: 0 (infinite)
    reconnectBaseDelayMs?: number;      // Default: 300
    reconnectMaxDelayMs?: number;       // Default: 30000
  };
  /** Builder configuration for order attribution (optional) */
  builder?: {
    signingServerUrl?: string;          // Builder Signing Server URL (frontend)
    key?: string;                       // Builder API Key (backend only!)
    secret?: string;                    // Builder API Secret (backend only!)
    passphrase?: string;                // Builder API Passphrase (backend only!)
  };
}

Properties

sdk.endpoints

Get current endpoint configuration.

const endpoints = sdk.endpoints;
console.log(endpoints.dataApi); // "https://data-api.polymarket.com"
sdk.data — Data API

Access historical data (no authentication required).

// Get trades
const { items, nextCursor } = await sdk.data.getTrades({
  marketId?: string;
  address?: string;
  side?: "BUY" | "SELL";
  from?: string | number;  // ISO string or epoch ms
  to?: string | number;
  cursor?: string;
  limit?: number;          // Default: 100
});

// Get positions
const { items, nextCursor } = await sdk.data.getPositions({
  address: string;         // Required
  marketId?: string;
  eventId?: string;
  cursor?: string;
  limit?: number;
});

// Get holders
const { items, nextCursor } = await sdk.data.getHolders({
  marketId: string;        // Required
  cursor?: string;
  limit?: number;
});

// Get activity
const { items, nextCursor } = await sdk.data.getActivity({
  address: string;         // Required
  type?: string;
  side?: "BUY" | "SELL";
  from?: string | number;
  to?: string | number;
  cursor?: string;
  limit?: number;
});
sdk.markets — Markets API

Access market metadata with pagination.

// Get markets (single page)
const markets = await sdk.markets.getMarkets({
  status?: "open" | "closed" | "resolved";
  page?: number;
  limit?: number;
  sort?: "volume" | "liquidity" | "createdAt";
  tags?: string[];
});

// Get a single market
const market = await sdk.markets.getMarket(marketId: string);

// Iterate through all markets (async generator)
for await (const marketPage of sdk.markets.iterMarkets(filters?)) {
  // Process each page...
}
sdk.ws — WebSocket Streams

Subscribe to real-time market data.

const unsubscribe = sdk.ws.onMarket(
  marketId: string,
  onUpdate: (update: OrderbookUpdate) => void,
  options?: {
    onOpen?: () => void;
    onClose?: () => void;
    onError?: (error: any) => void;
    onReconnect?: (event: WsReconnectEvent) => void;
    onStateChange?: (state: WsConnectionState) => void;
  }
);

// Later: unsubscribe()
sdk.trading — Trading (Scaffold)

Initialize trading client (scaffold implementation).

const trading = sdk.trading.init(
  options: { signer: any } | { builderServerUrl: string }
);

Backward-Compatible Methods (Deprecated)

These methods are kept for backward compatibility but are deprecated:

// ⚠️ Deprecated: Use sdk.markets.getMarkets() instead
const markets = await sdk.getMarkets();

// ⚠️ Deprecated: Use sdk.markets.getMarket() instead
const market = await sdk.getMarket(marketId);

// ⚠️ Deprecated: Use sdk.ws.onMarket() instead
const unsubscribe = sdk.onOrderbook(marketId, callback, options);

🔄 Rate Limits & Retry Logic

The SDK includes intelligent rate limit handling and retry logic:

Rate Limit Handling (HTTP 429)

  • Automatically respects Retry-After header when present
  • Falls back to exponential backoff with jitter (base ~300ms, cap ~10s)
  • Only retries idempotent GET requests
  • Throws RateLimitError after all retries are exhausted

Exponential Backoff

  • Base delay: 300ms (configurable)
  • Max delay: 10s (configurable)
  • Jitter: Random component added to prevent thundering herd
  • Max retries: 3 (configurable)

Configuration

const sdk = new PolybasedSDK({
  retry: {
    maxRetries: 5,
    baseDelayMs: 500,
    maxDelayMs: 15000
  }
});

Error Handling

import { HttpError, RateLimitError } from "@polybased/sdk";

try {
  const trades = await sdk.data.getTrades();
} catch (error) {
  if (error instanceof RateLimitError) {
    console.error(`Rate limited! Retry after ${error.retryAfter}s`);
  } else if (error instanceof HttpError) {
    console.error(`HTTP ${error.status}: ${error.message}`);
  }
}

🔐 Security Best Practices

Never Expose Private Keys in Browser

❌ NEVER do this in frontend code:

// DANGEROUS - DO NOT USE IN BROWSER!
const signer = new Wallet(privateKey);
const trading = sdk.trading.init({ signer });

Use a Builder Signing Server

✅ Recommended for frontend applications:

// SAFE - Use a signing server
const trading = sdk.trading.init({
  builderServerUrl: "https://your-signing-server.com"
});

Private Key Storage

  • Backend/Server: Store private keys in environment variables
  • Never: Commit private keys to version control
  • Never: Hardcode private keys in source code
  • Never: Expose private keys to browser/frontend

👷 Builder Profile & Order Attribution

Polymarket Builders can earn revenue share by attributing orders to their platform using Builder API credentials.

What is a Builder Profile?

A Builder Profile gives you:

  • Order Attribution — Earn revenue share from orders placed through your app
  • Authenticated APIs — Access to user-specific WebSocket streams and trading endpoints
  • Builder Credentials — API Key, Secret, and Passphrase for signing requests

Getting Your Builder Credentials

  1. Visit Polymarket Builder Portal
  2. Create a Builder Profile
  3. Generate your API credentials:
    • BUILDER_KEY — Your Builder API Key
    • BUILDER_SECRET — Your Builder API Secret
    • BUILDER_PASSPHRASE — Your Builder API Passphrase

⚠️ SECURITY: These credentials are as sensitive as private keys!

Storing Builder Credentials

Create a .env file in your project root (backend/server only):

# .env (NEVER commit this file!)
BUILDER_KEY=your_builder_api_key
BUILDER_SECRET=your_builder_api_secret
BUILDER_PASSPHRASE=your_builder_passphrase

# For frontend apps, point to your signing server
BUILDER_SIGNING_URL=https://your-signing-server.com

Add .env to your .gitignore:

.env
.env.local
.env.*.local

Using Builder Config in SDK

Frontend apps should NEVER have direct access to Builder credentials.

Use a Builder Signing Server to securely generate attribution headers:

import { PolybasedSDK } from "@polybased/sdk";

const sdk = new PolybasedSDK({
  builder: {
    signingServerUrl: process.env.BUILDER_SIGNING_URL
  }
});

Option 2: Direct Credentials (Backend Only)

⚠️ BACKEND/SERVER ONLY - NEVER in browser!

import { PolybasedSDK } from "@polybased/sdk";

const sdk = new PolybasedSDK({
  builder: {
    key: process.env.BUILDER_KEY,
    secret: process.env.BUILDER_SECRET,
    passphrase: process.env.BUILDER_PASSPHRASE
  }
});

Order Attribution Flow

When a user places an order through your platform:

  1. User Signs Order — User signs the order with their wallet
  2. Builder Adds Attribution — Your Builder credentials add attribution headers
  3. Order Submitted — Order is sent to CLOB with both signatures
import { PolybasedSDK, getBuilderHeaders } from "@polybased/sdk";

const sdk = new PolybasedSDK({
  builder: {
    signingServerUrl: process.env.BUILDER_SIGNING_URL
  }
});

// Get builder headers for attribution
const headers = await getBuilderHeaders(sdk.config.builder!);

// Place order with attribution
const orderId = await sdk.trading.init().placeOrder(
  {
    tokenId: "0x123...",
    side: "BUY",
    price: 0.65,
    size: 10
  },
  { headers }  // Builder attribution headers
);

Builder Header Helpers

The SDK provides helper functions for generating Builder attribution headers:

import {
  getBuilderHeadersRemote,  // Frontend (via signing server)
  getBuilderHeadersLocal,   // Backend (direct credentials)
  getBuilderHeaders         // Auto-select based on config
} from "@polybased/sdk";

// Frontend: Get headers from signing server
const headers = await getBuilderHeadersRemote("https://your-server.com");

// Backend: Get headers from credentials (NEVER in browser!)
const headers = await getBuilderHeadersLocal({
  key: process.env.BUILDER_KEY!,
  secret: process.env.BUILDER_SECRET!,
  passphrase: process.env.BUILDER_PASSPHRASE!
});

// Auto: Use builder config
const headers = await getBuilderHeaders(builderConfig);

User WebSocket Subscriptions (Authenticated)

Builder credentials are required for authenticated user-specific WebSocket subscriptions:

import { onUserEvents, getBuilderHeadersRemote } from "@polybased/sdk";

// Subscribe to user's orders and fills
const unsubscribe = onUserEvents(
  wsUrl,
  "0xUserWalletAddress",
  (event) => {
    if (event.type === 'order_created') {
      console.log('New order:', event);
    }
    if (event.type === 'fill') {
      console.log('Order filled:', event);
    }
  },
  {
    getHeaders: async () => await getBuilderHeadersRemote(
      process.env.BUILDER_SIGNING_URL!
    )
  }
);

Note: User WebSocket subscriptions are currently scaffolded and will be fully implemented in a future release.

Learn More


💻 Examples

The SDK includes comprehensive examples in the examples/ directory.

Running Examples

All examples are network-guarded. Set RUN_EXAMPLES=1 to execute:

# List markets with pagination
RUN_EXAMPLES=1 tsx examples/list-markets.ts

# Get historical trades
RUN_EXAMPLES=1 tsx examples/data-trades.ts

# Get user positions
ADDRESS=0xYourAddress RUN_EXAMPLES=1 tsx examples/data-positions.ts

# Get market holders
MARKET_ID=0xMarketId RUN_EXAMPLES=1 tsx examples/data-holders.ts

# Get user activity
ADDRESS=0xYourAddress RUN_EXAMPLES=1 tsx examples/data-activity.ts

# Stream orderbook (WebSocket)
MARKET_ID=market-id RUN_EXAMPLES=1 tsx examples/ws-market.ts

# Stream orderbook (legacy/deprecated method)
MARKET_ID=market-id RUN_EXAMPLES=1 tsx examples/live-orderbook.ts

# Trading scaffold (backend only!)
PRIVATE_KEY=0x... RUN_EXAMPLES=1 tsx examples/first-order.ts

Example: Data API

import { PolybasedSDK } from "@polybased/sdk";

const sdk = new PolybasedSDK();

// Get recent trades
const { items: trades } = await sdk.data.getTrades({ limit: 10 });
console.log(`Found ${trades.length} trades`);

Example: WebSocket Stream

import { PolybasedSDK } from "@polybased/sdk";

// Node.js: Enable WebSocket
if (typeof window === "undefined") {
  globalThis.WebSocket = (await import("ws")).default as any;
}

const sdk = new PolybasedSDK();

const unsubscribe = sdk.ws.onMarket("market-id", (update) => {
  if (update.type === "snapshot") {
    console.log("Best bid:", update.data.bids[0]?.price);
    console.log("Best ask:", update.data.asks[0]?.price);
  }
});

🛠️ Troubleshooting

WebSocket Not Connecting

Problem: WebSocket is not defined error in Node.js

Solution: Install and configure the ws package:

npm install ws
// Add at the top of your file
if (typeof window === "undefined") {
  globalThis.WebSocket = (await import("ws")).default as any;
}

Rate Limit Errors

Problem: Getting 429 Too Many Requests errors

Solution:

  1. The SDK automatically handles rate limits with retries
  2. Adjust retry configuration if needed:
const sdk = new PolybasedSDK({
  retry: {
    maxRetries: 5,
    baseDelayMs: 500,
    maxDelayMs: 20000
  }
});
  1. Add delays between requests in your code
  2. Consider caching responses

TypeScript Errors

Problem: Module resolution errors

Solution: Ensure you're using Node.js >= 18 and have proper tsconfig.json:

{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "target": "ES2022"
  }
}

WebSocket Disconnects

Problem: WebSocket keeps disconnecting

Solution:

  • The SDK includes auto-reconnect with exponential backoff
  • Adjust reconnect configuration:
const sdk = new PolybasedSDK({
  ws: {
    heartbeatIntervalMs: 30000,
    heartbeatTimeoutMs: 10000,
    maxReconnectAttempts: 0,  // 0 = infinite
    reconnectBaseDelayMs: 300,
    reconnectMaxDelayMs: 30000
  }
});

🤝 Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.



💡 About Polybased

Polybased aims to become the go-to SDK and data layer for on-chain prediction markets, starting with Polymarket.

Roadmap

  • ✅ Polymarket data integration
  • ✅ Real-time orderbook streaming with auto-reconnect
  • ✅ Data API (trades, positions, holders, activity)
  • ✅ Resilient HTTP with rate limit handling
  • ✅ Comprehensive TypeScript support
  • 🔨 Trading execution layer (in progress)
  • 📊 Historical & aggregated market data (planned)
  • 🌐 Dashboard examples and starter kits (planned)

$POLYBASED Token

Native token launched on PumpFun (Solana)
Contract Address: 446tM6t3j5KngSsahHDeYzdJByGjnsBRQrBxV4wUpump


📄 License

This project is licensed under the MIT License.


🙏 Acknowledgments

Built with ❤️ by the Polybased team for the prediction market community.

Special thanks to Polymarket for providing the infrastructure and documentation that makes this SDK possible.


© 2025 Polybased — Building the prediction-market toolkit of the future.