@limitless-exchange/sdk
v1.0.9
Published
TypeScript SDK for Limitless Exchange CLOB and NegRisk trading
Readme
Limitless Exchange TypeScript SDK
v1.0.9 | Production-Ready | Type-Safe | Fully Documented
A TypeScript SDK for interacting with the Limitless Exchange platform, providing type-safe access to CLOB and NegRisk prediction markets.
v1.0.9 Release: Adds partner withdrawal-address allowlist helpers and documents server-wallet withdrawals to explicit treasury destinations. See Changelog for details.
⚠️ Disclaimer
USE AT YOUR OWN RISK
This SDK is provided "as-is" without any warranties or guarantees. Trading on prediction markets involves financial risk. By using this SDK, you acknowledge that:
- You are responsible for testing the SDK thoroughly before using it in production
- The SDK authors are not liable for any financial losses or damages
- You should review and understand the code before executing any trades
- It is recommended to test all functionality on testnet or with small amounts first
- The SDK may contain bugs or unexpected behavior despite best efforts
ALWAYS TEST BEFORE USING IN PRODUCTION WITH REAL FUNDS
For production use, we strongly recommend:
- Running comprehensive tests with your specific use case
- Starting with small transaction amounts
- Monitoring all transactions carefully
- Having proper error handling and recovery mechanisms
Feedback Welcome: We encourage you to report any bugs, suggest improvements, or contribute to the project. Please submit issues or pull requests on our GitHub repository.
🌍 Geographic Restrictions
Important: Limitless restricts order placement from US locations due to regulatory requirements and compliance with international sanctions. Before placing orders, builders should verify their location complies with applicable regulations.
Features
- ✅ Authentication: API key auth and partner HMAC-scoped API-token auth
- ✅ Order Management: Create, cancel, and manage orders on CLOB and NegRisk markets
- ✅ Partner Server Wallets: Delegated child-account flows, server-wallet redeem, and HMAC-only withdraw to account, smart wallet, or whitelisted treasury destinations
- ✅ Market Data: Access real-time market data and orderbooks
- ✅ NegRisk Markets: Full support for group markets with multiple outcomes
- ✅ Error Handling & Retry: Automatic retry logic for rate limits and transient failures
- ✅ Type Safety: Full TypeScript support with comprehensive type definitions
- ✅ IEEE-Safe Order Payload Parsing:
createOrder()handlesmakerAmount,takerAmount,price, andsaltreturned as JSON strings - ✅ TSDoc Documentation: Complete API documentation with examples
- ✅ WebSocket: Real-time price and position updates with API key auth
Installation
npm install @limitless-exchange/sdk
# or
yarn add @limitless-exchange/sdk
# or
pnpm add @limitless-exchange/sdkQuick Start
Fetching Active Markets (No Authentication Required)
import { HttpClient, MarketFetcher } from '@limitless-exchange/sdk';
// Create HTTP client (no authentication needed)
const httpClient = new HttpClient({
baseURL: 'https://api.limitless.exchange',
// Optional: Add custom headers to all requests
additionalHeaders: {
'X-Custom-Header': 'my-value',
},
});
const marketFetcher = new MarketFetcher(httpClient);
// Get markets sorted by LP rewards
const markets = await marketFetcher.getActiveMarkets({
limit: 8,
sortBy: 'lp_rewards', // 'lp_rewards' | 'ending_soon' | 'newest' | 'high_value'
});
console.log(`Found ${markets.data.length} of ${markets.totalMarketsCount} markets`);
// Pagination (page-based)
const page2 = await marketFetcher.getActiveMarkets({
limit: 8,
page: 2,
sortBy: 'ending_soon',
});See examples/project-integration/src/active-markets.ts for more examples.
Market Pages & Navigation (No Authentication Required)
import { HttpClient, MarketPageFetcher } from '@limitless-exchange/sdk';
const httpClient = new HttpClient({
baseURL: 'https://api.limitless.exchange',
});
const pageFetcher = new MarketPageFetcher(httpClient);
// Resolve a page from URL path
const page = await pageFetcher.getMarketPageByPath('/crypto');
// Fetch page markets with dynamic filters
const markets = await pageFetcher.getMarkets(page.id, {
limit: 20,
sort: '-updatedAt',
filters: {
duration: 'hourly',
ticker: ['btc', 'eth'],
},
});
if ('pagination' in markets) {
console.log(`Total markets: ${markets.pagination.total}`);
}Detailed guide: docs/market-pages/README.md
Authentication
The SDK uses API keys for authentication. API keys can be obtained from your Limitless Exchange account settings(Click on User Profile).
import { HttpClient } from '@limitless-exchange/sdk';
// Option 1: Automatic from environment variable (recommended)
// Set LIMITLESS_API_KEY in your .env file
const httpClient = new HttpClient({
baseURL: 'https://api.limitless.exchange',
});
// Option 2: Explicit API key
const httpClient = new HttpClient({
baseURL: 'https://api.limitless.exchange',
apiKey: process.env.LIMITLESS_API_KEY,
});
// All requests automatically include X-API-Key header
// For authenticated endpoints like portfolio, orders, etc.Environment Variables:
Create a local .env file that is not committed to source control:
# Required for authenticated endpoints
LIMITLESS_API_KEY=sk_live_your_api_key_here
# REQUIRED for server-side or local scripts that sign orders (EIP-712)
# Never commit a real private key to the repository.
PRIVATE_KEY=your_private_key_hereDo not ship a raw PRIVATE_KEY in browser bundles, checked-in .env files, or frontend environment variables. For browser apps, use an injected wallet or move signing behind your own backend/BFF.
Partner API Token v3 / HMAC Usage
The SDK also supports partner-scoped HMAC credentials for api-token v3 workflows such as token self-service, partner-account creation, delegated trading, and server-wallet redeem/withdraw.
Use HMAC credentials only in a backend or BFF service. Do not expose partner HMAC secrets in browser bundles, frontend environment variables, or client-side storage.
Recommended setup:
- Keep public market and market-page reads in the browser.
- Store the real HMAC
tokenId/secreton your backend. - Keep any raw order-signing
PRIVATE_KEYon your backend or in local development only. - Use this SDK server-side to sign partner-authenticated requests.
- Expose only your own app-specific endpoints to the frontend.
See docs/code-samples/api-key-v3/ for the partner HMAC examples.
Partner Server-Wallet Allowances
Use client.partnerAccounts.checkAllowances(profileId) and client.partnerAccounts.retryAllowances(profileId) only for partner child profiles created with createServerWallet: true.
checkAllowances()callsGET /profiles/partner-accounts/:profileId/allowancesretryAllowances()callsPOST /profiles/partner-accounts/:profileId/allowances/retry- both operations require HMAC-scoped API-token auth with
account_creationanddelegated_signingscopes profileIdshould be the delegated child-profile id
import { Client } from '@limitless-exchange/sdk';
const client = new Client({
baseURL: 'https://api.limitless.exchange',
hmacCredentials: {
tokenId: process.env.LIMITLESS_API_TOKEN_ID!,
secret: process.env.LIMITLESS_API_TOKEN_SECRET!,
},
});
let allowances = await client.partnerAccounts.checkAllowances(352);
if (!allowances.ready) {
// Retry re-checks live chain state and submits only targets still missing.
// A returned "submitted" status means this request submitted a sponsored tx/user operation.
allowances = await client.partnerAccounts.retryAllowances(352);
}Poll checkAllowances() first. If ready is false and one or more targets are missing or failed with retryable: true, call retryAllowances(), then poll checkAllowances() again after a short delay. Retry 429 responses throw RateLimitError and include retryAfterSeconds in error.data; retry 409 responses throw APIError with status === 409, which means another retry is already running.
For a complete runnable flow, see docs/code-samples/api-key-v3/partner-account-allowances.ts.
Server Wallet Redeem & Withdraw
Use client.serverWallets only for server-managed wallets created in delegated-signing partner flows with createServerWallet: true.
redeemPositions()callsPOST /portfolio/redeemwithdraw()callsPOST /portfolio/withdraw- both operations require HMAC-scoped API-token auth
withdraw()also requires thewithdrawalscope- set
onBehalfOfto the delegated child-profile id when withdrawing child server-wallet funds - omit
onBehalfOfonly when withdrawing the authenticated caller's own server wallet to an explicitdestination amountfor withdraw must be provided in the token smallest unit- omit
destinationto use the API default: authenticated partner smart wallet when present, otherwise authenticated partner account - pass
destinationto withdraw directly to the authenticated partner account, authenticated partner smart wallet, or an active withdrawal address allowlisted on the authenticated partner profile partnerAccounts.addWithdrawalAddress()andpartnerAccounts.deleteWithdrawalAddress()manage the allowlist with Privy identity-token auth; API-token auth is not used for those allowlist endpoints
import { Client } from '@limitless-exchange/sdk';
const client = new Client({
baseURL: 'https://api.limitless.exchange',
hmacCredentials: {
tokenId: process.env.LIMITLESS_API_TOKEN_ID!,
secret: process.env.LIMITLESS_API_TOKEN_SECRET!,
},
});
const redeem = await client.serverWallets.redeemPositions({
conditionId: '0x...',
onBehalfOf: 352,
});
const withdraw = await client.serverWallets.withdraw({
amount: '5000000',
onBehalfOf: 352,
});To withdraw a partner child server wallet directly to a treasury address, allowlist the destination on the authenticated partner profile first. Use the same partner identity for the allowlist call and the same partner HMAC token for the withdraw call.
const identityToken = process.env.LIMITLESS_IDENTITY_TOKEN!;
const treasuryAddress = '0x...';
await client.partnerAccounts.addWithdrawalAddress(identityToken, {
address: treasuryAddress,
label: 'treasury',
});
const treasuryWithdraw = await client.serverWallets.withdraw({
amount: '5000000',
onBehalfOf: 352,
destination: treasuryAddress,
});
const ownWalletTreasuryWithdraw = await client.serverWallets.withdraw({
amount: '5000000',
destination: treasuryAddress,
});
// Optional cleanup when the destination should no longer be active.
await client.partnerAccounts.deleteWithdrawalAddress(identityToken, treasuryAddress);redeem.hash or withdraw.hash may be an empty string for user-operation submissions. Track those calls using userOperationHash or transactionId.
For a complete runnable flow, see docs/code-samples/api-key-v3/server-wallet-redeem-withdraw.ts.
Token Approvals
Important: Before placing orders, you must approve tokens for the exchange contracts. This is a one-time setup per wallet.
Required Approvals
CLOB Markets:
- BUY orders: Approve USDC →
market.venue.exchange - SELL orders: Approve Conditional Tokens →
market.venue.exchange
NegRisk Markets:
- BUY orders: Approve USDC →
market.venue.exchange - SELL orders: Approve Conditional Tokens → both
market.venue.exchangeANDmarket.venue.adapter
Quick Setup
Run the approval setup script:
# Copy .env.example and configure your wallet
cp docs/code-samples/.env.example docs/code-samples/.env
# Edit .env and set your PRIVATE_KEY and market slug
# Then run the approval script
npx tsx docs/code-samples/setup-approvals.tsManual Approval Example
import { ethers } from 'ethers';
import { MarketFetcher, getContractAddress } from '@limitless-exchange/sdk';
// 1. Fetch market to get venue addresses
const market = await marketFetcher.getMarket('market-slug');
// 2. Create contract instances
const usdc = new ethers.Contract(
getContractAddress('USDC'),
['function approve(address spender, uint256 amount) returns (bool)'],
wallet
);
const ctf = new ethers.Contract(
getContractAddress('CTF'),
['function setApprovalForAll(address operator, bool approved)'],
wallet
);
// 3. Approve USDC for BUY orders
await usdc.approve(market.venue.exchange, ethers.MaxUint256);
// 4. Approve CT for SELL orders
await ctf.setApprovalForAll(market.venue.exchange, true);
// 5. For NegRisk SELL orders, also approve adapter
if (market.negRiskRequestId) {
await ctf.setApprovalForAll(market.venue.adapter, true);
}For complete examples, see docs/code-samples/setup-approvals.ts.
Trading on NegRisk Markets
NegRisk markets are group markets with multiple related outcomes. Here's a quick example:
import { OrderClient, MarketFetcher, Side, OrderType } from '@limitless-exchange/sdk';
// 1. Fetch NegRisk group market
const marketFetcher = new MarketFetcher(httpClient);
const groupMarket = await marketFetcher.getMarket('largest-company-end-of-2025-1746118069282');
// 2. Select a submarket (e.g., Apple)
const appleMarket = groupMarket.markets[0];
const marketDetails = await marketFetcher.getMarket(appleMarket.slug);
// 3. Create order client (userData fetched automatically from profile)
const orderClient = new OrderClient({
httpClient,
wallet,
});
// 4. Place order on submarket (not group!)
const order = await orderClient.createOrder({
tokenId: marketDetails.tokens.yes,
price: 0.5,
size: 10,
side: Side.BUY,
orderType: OrderType.GTC,
marketSlug: appleMarket.slug, // Use submarket slug
});Important: Always use the submarket slug for NegRisk orders, not the group market slug!
For more details, see the NegRisk Trading Guide.
GTC Orders (Limit Orders)
GTC orders use price + size and can optionally set postOnly to reject an order that would immediately match.
import { OrderClient, Side, OrderType } from '@limitless-exchange/sdk';
const gtcOrder = await orderClient.createOrder({
tokenId: marketDetails.tokens.yes,
price: 0.42,
size: 10,
side: Side.BUY,
orderType: OrderType.GTC,
marketSlug: 'market-slug',
postOnly: true, // Supported only for GTC
});
console.log(gtcOrder.order.id);For complete examples, see docs/code-samples/clob-gtc-order.ts.
FAK Orders (Fill-and-Kill Limit Orders)
FAK orders use the same price + size construction as GTC, but they only consume immediately available liquidity and cancel any remainder.
import { OrderClient, Side, OrderType } from '@limitless-exchange/sdk';
const fakOrder = await orderClient.createOrder({
tokenId: marketDetails.tokens.yes,
price: 0.45,
size: 10,
side: Side.BUY,
orderType: OrderType.FAK,
marketSlug: 'market-slug',
});
if (fakOrder.makerMatches && fakOrder.makerMatches.length > 0) {
console.log(`FAK matched immediately with ${fakOrder.makerMatches.length} fill(s)`);
} else {
console.log('FAK remainder was cancelled.');
}Key Differences from GTC:
- FAK uses
price+sizelike GTC - Executes immediately up to the available size
- Any unfilled remainder is cancelled
postOnlyis not supported for FAK
For complete examples, see docs/code-samples/clob-fak-order.ts.
FOK Orders (Fill-or-Kill Market Orders)
FOK orders execute immediately at the best available price or cancel entirely. Unlike GTC orders that use price + size, FOK orders use makerAmount.
Parameter Semantics:
- BUY:
makerAmount= total USDC to spend - SELL:
makerAmount= number of shares to sell
import { OrderClient, Side, OrderType } from '@limitless-exchange/sdk';
// BUY FOK - spend 50 USDC at market price
const buyOrder = await orderClient.createOrder({
tokenId: marketDetails.tokens.yes,
makerAmount: 50, // 50 USDC to spend
side: Side.BUY,
orderType: OrderType.FOK,
marketSlug: 'market-slug',
});
// SELL FOK - sell 120 shares at market price
const sellOrder = await orderClient.createOrder({
tokenId: marketDetails.tokens.no,
makerAmount: 120, // 120 shares to sell
side: Side.SELL,
orderType: OrderType.FOK,
marketSlug: 'market-slug',
});
// Check execution
if (buyOrder.makerMatches && buyOrder.makerMatches.length > 0) {
console.log(`Order filled: ${buyOrder.makerMatches.length} matches`);
} else {
console.log('Order cancelled (no liquidity)');
}Key Differences from GTC:
- FOK uses
makerAmount(notprice+size) - Executes immediately or cancels (no orderbook placement)
- All-or-nothing execution (no partial fills)
- Best for immediate execution at market price
For complete examples, see docs/code-samples/clob-fok-order.ts.
Error Handling & Retry
The SDK provides automatic retry logic for handling transient failures like rate limits and server errors:
import { withRetry, retryOnErrors } from '@limitless-exchange/sdk';
// Option 1: Wrapper function approach
const result = await withRetry(async () => await orderClient.createOrder(orderData), {
statusCodes: [429, 500, 503], // Retry on rate limits and server errors
maxRetries: 3,
delays: [2, 5, 10], // Wait 2s, then 5s, then 10s
onRetry: (attempt, error, delay) => {
console.log(`Retry ${attempt + 1} after ${delay}s: ${error.message}`);
},
});
// Option 2: Decorator approach (requires experimentalDecorators: true)
class TradingService {
@retryOnErrors({
statusCodes: [429, 500, 503],
maxRetries: 3,
exponentialBase: 2, // Exponential backoff: 1s, 2s, 4s
maxDelay: 30,
})
async placeOrder(orderData: any) {
return await this.orderClient.createOrder(orderData);
}
}Key Features:
- Automatic retry on configurable status codes (429, 500, 502, 503, 504)
- Fixed delays or exponential backoff strategies
- Callback hooks for monitoring retry attempts
- Three approaches: decorator, wrapper function, or global client wrapper
For detailed documentation, see the Error Handling & Retry Guide.
API Documentation
Authentication
HttpClient
HTTP client with API key authentication.
const httpClient = new HttpClient({
baseURL: 'https://api.limitless.exchange',
apiKey: process.env.LIMITLESS_API_KEY, // optional: can also be auto-loaded from LIMITLESS_API_KEY
timeout: 30000,
});
// Set or update API key
httpClient.setApiKey('sk_live_...');
// Make requests - X-API-Key header automatically included
const data = await httpClient.get('/endpoint');
await httpClient.post('/endpoint', { data });Documentation
For detailed documentation, see the docs directory:
- Complete Documentation - Full SDK documentation
- Authentication Guide - API key authentication and HTTP client
- Trading & Orders - Order creation, management, and NegRisk markets
- Market Data - Market discovery and orderbook access
- Portfolio & Positions - Position tracking and user history
- WebSocket Streaming - Real-time data updates
- Error Handling & Retry - API error handling and retry mechanisms
- Logging - Logging configuration
Code Examples
Production-ready code samples are available in docs/code-samples:
Authentication Examples
basic-auth.ts- API key authentication setupwith-logging.ts- Authentication with custom loggingauth-retry.ts- Authentication with retry logicerror-handling.ts- Comprehensive error handling
Trading Examples
CLOB Markets:
clob-fok-order.ts- Fill-or-Kill market ordersclob-gtc-order.ts- Good-Til-Cancelled limit orders withpostOnlyclob-fak-order.ts- Fill-And-Kill limit orders
NegRisk Markets:
negrisk-fok-order.ts- FOK orders on group marketsnegrisk-gtc-order.ts- GTC orders on NegRisk submarkets
Market Data Examples
get-active-markets.ts- Fetching active markets with sorting and paginationorderbook.ts- Fetching and analyzing orderbookspositions.ts- Portfolio and position trackingfluent-api-trading-workflow.ts- Complete trading workflow
Real-Time Examples
websocket-events.ts- Real-time trading events and subscriptions
Partner HMAC Examples
api-key-v3/partner-account-allowances.ts- Check and retry server-wallet allowance recovery with partner HMAC auth onlyapi-key-v3/server-wallet-redeem-withdraw.ts- Redeem resolved positions and optionally withdraw from a server wallet
Development
Build
pnpm install
pnpm buildTest
pnpm test
pnpm test:coverageLint
pnpm lint
pnpm formatProject Structure
src/
├── types/ # TypeScript type definitions
│ ├── markets.ts # Market and active markets types
│ ├── orders.ts # Order types
│ ├── auth.ts # User profile types
│ └── ...
├── api/ # HTTP client and API utilities
│ ├── http.ts # HTTP client with API key auth
│ ├── errors.ts # Error handling
│ └── retry.ts # Retry logic
├── markets/ # Market data modules
│ ├── fetcher.ts # Market and orderbook fetching
│ └── index.ts
├── orders/ # Order management
│ └── client.ts # Order creation and management
├── portfolio/ # Portfolio and positions
│ └── fetcher.ts
├── websocket/ # Real-time data streaming
│ └── client.ts
├── api/ # HTTP client and API utilities
│ ├── http.ts # HTTP client
│ └── errors.ts # API error handling
└── utils/ # Shared utilities and constants
tests/
├── auth/ # Authentication tests
└── markets/ # Market fetcher tests
└── fetcher.test.ts //etc.
docs/
├── code-samples/ # Production-ready examples
│ ├── get-active-markets.ts
│ ├── clob-fok-order.ts
│ └── ...
└── */ # Documentation guides
Changelog
v1.0.9
Release Date: May 4, 2026
Latest release with partner withdrawal-address allowlist helpers and server-wallet withdrawals to explicit whitelisted treasury destinations.
Highlights
- ✅ Production-Ready: Thoroughly tested and validated against Base mainnet
- 🔒 Type-Safe: Full TypeScript support with comprehensive type definitions
- 📚 Well-Documented: 18 production-ready code samples + comprehensive guides
- ⚡ Performance Optimized: Venue caching system and connection pooling
- 🔄 Robust Error Handling: Automatic retry logic with multiple strategies
- 🌐 Real-Time Updates: WebSocket support for orderbook and position streaming
- 🎯 NegRisk Support: Full support for group markets with multiple outcomes
- 🧭 Market Pages API: Navigation tree, by-path resolver with 301 handling, page-scoped markets, property keys
- 🧾 More Trading Semantics:
FAKlimit orders pluspostOnlyonGTC - 🏦 Partner Server Wallets: Delegated child-account redeem and HMAC-only withdraw flows
- 🏛️ Treasury Withdrawals: Allowlist external withdrawal destinations and withdraw child server-wallet funds directly to them
- 🔁 Partner Allowance Recovery: Check and retry delegated allowance targets for server-wallet child profiles
Core Features
- Authentication: API key authentication, EIP-712 signing, EOA support
- Partner Flows: API-token v3 services, delegated orders, server-wallet redeem/withdraw, withdrawal-address allowlists, and allowance recovery
- Market Data: Active markets with sorting, orderbook access, venue caching
- Market Pages & Navigation:
/navigation,/market-pages/by-path,/market-pages/:id/markets,/property-keys - Order Management: GTC, FAK, and FOK orders, GTC
postOnly, tick alignment, automatic signing, IEEE-safe create-order payload parsing - Portfolio: Position tracking, user history
- WebSocket: Real-time orderbook, price updates, event streaming
- Error Handling: Decorator and wrapper retry patterns, configurable strategies
- Token Approvals: Complete setup script, CLOB and NegRisk workflows
Documentation Enhancements (v1.0.9)
- Added partner withdrawal-address allowlist docs for server-wallet treasury withdrawals
- Updated server-wallet withdraw docs for omitted-destination smart-wallet fallback and explicit whitelisted destinations
- Added partner allowance check/retry docs and API key v3 example for delegated server-wallet child accounts
- Updated allowance retry guidance for live chain reads, submitted-target semantics,
429, and409 - Created comprehensive CHANGELOG.md following Keep a Changelog format
- All production code samples include step-by-step comments and error handling
- Detailed guides for authentication, trading, markets, portfolio, and WebSocket
- Added market-pages guide and README quick-start for navigation-driven discovery
For complete release notes, see CHANGELOG.md.
Pre-Release Versions
- v0.0.3 - WebSocket streaming, enhanced code samples, NegRisk examples
- v0.0.2 - Venue caching, retry mechanisms, portfolio fetcher
- v0.0.1 - Initial release with core functionality
License
MIT - See LICENSE file for details
