npm package: @predictions/sdk
Description: Official SDK for the Synthesis prediction markets API
Author: Synthesis
Latest version: 1.0.0

# Synthesis SDK

Official JavaScript/TypeScript SDK for the [Synthesis](https://synthesis.trade) prediction markets API. Works in both Node.js and the browser.

## Installation

```bash
npm install @predictions/sdk
```

## Quick Start

```typescript
import Synthesis from '@predictions/sdk';

const client = new Synthesis();

// Get trending markets
const markets = await client.markets.get({ sort: 'volume', limit: 10 });
console.log(markets.data);

// Get a specific Polymarket event by slug
const market = await client.polymarket.getBySlug('will-bitcoin-reach-100k');
console.log(market.data);
```

## Configuration

```typescript
// No auth needed for public data (markets, prices, news, etc.)
const client = new Synthesis();

// Project app (creates/manages headless user accounts)
const client = new Synthesis({
  projectApiKey: 'sk_...',             // Project secret key
});

// After creating a session for a user, set it for user-scoped calls
const session = await client.projects.createSession('account_id');
client.setSessionToken(session.data.session_id);

// Now wallet/order calls are scoped to that user
await client.wallets.get();

// Clear when done
client.clearSessionToken();
```

All config options:

```typescript
const client = new Synthesis({
  baseUrl: 'https://synthesis.trade',  // API base URL (default)
  projectApiKey: 'sk_...',             // Project secret key for project-level operations
  sessionToken: 'sess_...',            // Session token for user-scoped requests
  timeout: 30000,                      // Request timeout in ms (default: 30s)
});
```

## Error Handling

All methods return `ApiResponse<T>`:

```typescript
interface ApiResponse<T> {
  success: boolean;
  data?: T;
  error?: string;
}
```

```typescript
const result = await client.markets.get();

if (!result.success) {
  console.error(result.error);
  return;
}

console.log(result.data);
```

---

## Markets

Aggregate market data across all venues.

```typescript
// Get markets with filters
client.markets.get({
  venue: 'polymarket',   // 'polymarket' | 'kalshi' | 'all'
  sort: 'volume',        // 'volume' | 'liquidity' | etc.
  order: 'DESC',
  limit: 20,
  offset: 0,
  live: true,
})

// Search markets by query
client.markets.search('bitcoin')

// Batch price data
client.markets.sparklines(['token_id_1', 'token_id_2'])
client.markets.prices(['token_id_1', 'token_id_2'])
client.markets.orderbooks(['token_id_1'])
client.markets.historicalOrderbooks({ token_id: '...', interval: '1h' })

// Venue statistics
client.markets.statistics()

// Related and similar markets
client.markets.related('event-slug')
client.markets.similar({ market_id: '...', limit: 10 })
client.markets.similarPairs({ limit: 20, min_similarity: 0.8 })

// Personalized recommendations (requires session)
client.markets.recommendations({ limit: 25 })
```

## Polymarket

Polymarket-specific endpoints.

```typescript
// List and lookup
client.polymarket.get({ sort: 'volume', limit: 20 })
client.polymarket.getBySlug('will-bitcoin-reach-100k')
client.polymarket.getById('0xcondition_id')

// Market data
client.polymarket.priceHistory('token_id', { interval: '1h', fidelity: 60 })
client.polymarket.statistics('token_id')
client.polymarket.trades('0xcondition_id')

// Users and leaderboard
client.polymarket.user('0xaddress')
client.polymarket.leaderboard()
```

> **Note:** For prices and orderbooks, use the batch endpoints on `client.markets.prices()` and `client.markets.orderbooks()`. Holder data is available via the data WebSocket.

## Kalshi

Kalshi-specific endpoints.

```typescript
// List and lookup
client.kalshi.get({ sort: 'volume', limit: 20 })
client.kalshi.getEvent('KXBTC-25')
client.kalshi.getBySlug('bitcoin-price-march')
client.kalshi.getById('KXBTC-25-T100000')

// Market data
client.kalshi.trades('KXBTC-25-T100000')
client.kalshi.holders('KXBTC-25-T100000')
client.kalshi.statistics('KXBTC-25-T100000')
client.kalshi.priceHistory('KXBTC', 'KXBTC-25-T100000')
client.kalshi.candlesticks('KXBTC', 'KXBTC-25-T100000', { interval: '1h' })

// Leaderboard and users
client.kalshi.leaderboard()
client.kalshi.user('username')
```

## Wallets

Wallet management, trading, deposits, and withdrawals. Requires a session token.

```typescript
// List, create, and manage wallets
client.wallets.get()
client.wallets.reorder(['wallet_a', 'wallet_b'])
client.wallets.create('POL')
client.wallets.create('SOL')
client.wallets.update('wallet_id', { name: 'Primary', autoredeem: true })
client.wallets.delete('wallet_id')
client.wallets.export('POL', 'wallet_id', 'base64-public-key')

// Generic (cross-venue) data
client.wallets.depositAddress('POL', 'wallet_id', 'EVM')
client.wallets.balance('wallet_id')
client.wallets.positions('wallet_id')
client.wallets.orders('wallet_id')
client.wallets.transfers('wallet_id')
client.wallets.pnl('wallet_id')
```

### Polygon (Polymarket)

```typescript
// Wallets and balance
client.wallets.pol.wallets()
client.wallets.pol.balance('wallet_id')
client.wallets.pol.depositAddress('wallet_id', 'EVM')

// Portfolio
client.wallets.pol.positions('wallet_id')
client.wallets.pol.orders('wallet_id')
client.wallets.pol.activeOrders('wallet_id')
client.wallets.pol.activeMarketOrders('wallet_id', '0xcondition_id')
client.wallets.pol.transfers('wallet_id')
client.wallets.pol.trades('wallet_id')
client.wallets.pol.pnl('wallet_id')

// Trading
client.wallets.pol.quote('wallet_id', { token_id: '0x...', side: 'BUY', amount: 100 })
client.wallets.pol.createOrder('wallet_id', {
  token_id: '0x...', side: 'BUY', type: 'MARKET', amount: 50, units: 'USDC',
})
client.wallets.pol.createOrder('wallet_id', {
  token_id: '0x...', side: 'BUY', type: 'LIMIT', price: 0.65, amount: 100,
})
client.wallets.pol.getOrder('wallet_id', 'order_id')
client.wallets.pol.updateOrder('wallet_id', 'order_id', { type: 'LIMIT', price: '0.70' })
client.wallets.pol.cancelOrder('wallet_id', 'order_id')
client.wallets.pol.cancelAllOrders('wallet_id')

// Copytrades
client.wallets.pol.getCopytrades('wallet_id')
client.wallets.pol.createCopytrade('wallet_id', { target: '0x...', mode: 'COPY', settings: {} })
client.wallets.pol.updateCopytrade('wallet_id', 'copytrade_id', { settings: {} })
client.wallets.pol.deleteCopytrade('wallet_id', 'copytrade_id')
client.wallets.pol.pauseCopytrade('wallet_id', 'copytrade_id')
client.wallets.pol.unpauseCopytrade('wallet_id', 'copytrade_id')
client.wallets.pol.getCopytradeOrders('wallet_id', 'copytrade_id')

// Mint, merge, redeem, withdraw, swap
client.wallets.pol.mint('wallet_id', { condition_id: '0x...', amount: 100 })
client.wallets.pol.merge('wallet_id', { condition_id: '0x...', amount: 100 })
client.wallets.pol.redeem('wallet_id', '0xcondition_id')
client.wallets.pol.withdraw('wallet_id', { token: 'USDC', amount: 100, address: '0x...', chain: 'POLYGON' })
client.wallets.pol.swap('wallet_id', { from: 'USDC', to: 'USDT', amount: 100 })
```

### Solana (Kalshi)

```typescript
// Wallets, KYC, and balance
client.wallets.sol.wallets()
client.wallets.sol.kyc('wallet_id')
client.wallets.sol.createKyc('wallet_id')
client.wallets.sol.balance('wallet_id')
client.wallets.sol.depositAddress('wallet_id', 'SOL')

// Portfolio
client.wallets.sol.positions('wallet_id')
client.wallets.sol.orders('wallet_id')
client.wallets.sol.transfers('wallet_id')
client.wallets.sol.pnl('wallet_id')

// Trading
client.wallets.sol.quote('wallet_id', { token_id: '...', side: 'BUY', amount: 100 })
client.wallets.sol.createOrder('wallet_id', { token_id: '...', side: 'BUY', type: 'MARKET', amount: 100 })
client.wallets.sol.redeem('wallet_id', 'token_id')
client.wallets.sol.withdraw('wallet_id', { token: 'USDC', amount: 100, address: '...', chain: 'SOLANA' })
```

## Account

Manage the authenticated user's account.

```typescript
// Session
client.account.session()
client.account.expireSession()

// API keys
client.account.getApiKeys()
client.account.createApiKey('my-key')
client.account.deleteApiKey('pk_...')

// Interests (for recommendations)
client.account.getInterests()
client.account.updateInterests(['crypto', 'politics', 'sports'])
```

## Projects

Manage headless accounts for your project. Requires a project API key.

```typescript
// API keys
client.projects.createApiKey({ name: 'production' })

// Settings
client.projects.updateSettings({ domain: 'myapp.com' })

// Account management
client.projects.getAccounts({ limit: 50 })
client.projects.createAccount({ user_id: 'ext_123' })
client.projects.getAccount('account_id')
client.projects.updateAccountMetadata('account_id', { plan: 'pro' })

// Session management
client.projects.createSession('account_id')
client.projects.refreshSession('account_id', 'session_id')
client.projects.expireSession('account_id', 'session_id')
client.projects.expireAllSessions('account_id')

// Account API keys
client.projects.getAccountApiKeys('account_id')
client.projects.createAccountApiKey('account_id', 'key-name')
client.projects.deleteAccountApiKey('account_id', 'pk_...')
```

## News

```typescript
client.news.get({ limit: 10 })
client.news.forEvent('event_id')
client.news.forMarket('market_id')
```

## Sports

```typescript
client.sports.categories()
client.sports.games({ sport: 'basketball', league: 'NBA' })
client.sports.game('basketball', 'NBA', 'game_123')
client.sports.markets()
client.sports.news()
```

## WebSockets

Real-time data feeds. Works in both browser and Node.js. Supports automatic reconnection with exponential backoff and subscription replay on reconnect.

```typescript
const ws = client.ws({ reconnect: true, reconnectInterval: 1000 });
```

### Orderbook

```typescript
const ws = client.ws();

ws.onMessage((msg) => {
  console.log('Orderbook update:', msg);
});

ws.orderbook();
ws.subscribe({ type: 'subscribe', markets: ['token_id_1', 'token_id_2'] });
```

### Trades

```typescript
const ws = client.ws();

ws.onMessage((msg) => {
  console.log('Trade:', msg);
});

ws.trades();
ws.subscribe({
  type: 'subscribe',
  venue: 'polymarket',
  markets: ['token_id_1'],
  offset: 0,
});
```

### Balance

```typescript
const ws = client.ws();

ws.onMessage((msg) => {
  console.log('Balance update:', msg);
});

ws.balance();
ws.subscribe({
  type: 'subscribe',
  wallets: [{ address: '0x...' }],
});
```

### Data (Holders)

```typescript
const ws = client.ws();

ws.onMessage((msg) => {
  console.log('Holder data:', msg);
});

ws.data();
ws.subscribe({
  type: 'subscribe',
  data_type: 'holder_counts',
  params: { condition_ids: ['0x...'] },
});
```

### Lifecycle

```typescript
const ws = client.ws();

// Multiple handlers supported
ws.onOpen(() => console.log('Connected'));
ws.onError((err) => console.error(err));
ws.onClose((code, reason) => console.log('Closed:', code));

// Remove specific handlers
const handler = (msg) => console.log(msg);
ws.onMessage(handler);
ws.offMessage(handler);

// Check connection state
console.log(ws.connected);

// Clean up
ws.clearSubscriptions();
ws.close();
```

---

## CLI

The CLI is a separate package:

```bash
npm install -g synthesis-cli
synthesis setup
```

See [synthesis-cli](https://github.com/synthesis-trade/cli) for full CLI documentation.

## TypeScript

All types are exported:

```typescript
import Synthesis, {
  SynthesisWebSocket,
  MarketWithEvent,
  Market,
  MarketEvent,
  Wallet,
  WalletBalance,
  Order,
  Position,
  PositionWithContext,
  Transfer,
  PnlPoint,
  CopyTrade,
  TxResult,
  Trade,
  Holder,
  Orderbook,
  CreateOrderParams,
  WithdrawParams,
  DepositAddress,
  WebSocketMessage,
  ApiResponse,
} from '@predictions/sdk';
```

## Agent / LLM Quickstart

This SDK is designed for programmatic use by AI agents and LLMs. A machine-readable tool schema is available at [`tools.json`](./tools.json) for use with OpenAI function calling, Anthropic tool use, LangChain, or any agent framework.

### End-to-end: search → quote → trade

```typescript
import Synthesis from '@predictions/sdk';

const client = new Synthesis({ projectApiKey: 'sk_...' });

// 1. Create a session for a user
const account = await client.projects.createAccount({ user_id: 'agent_1' });
const session = await client.projects.createSession(account.data.account_id);
client.setSessionToken(session.data.session_id);

// 2. Create a wallet
const wallet = await client.wallets.create('POL');
const walletId = wallet.data.wallet_id;

// 3. Search for a market
const results = await client.markets.search('bitcoin');
const market = results.data[0];
const tokenId = market.markets[0].left_token_id; // YES side

// 4. Get a quote
const quote = await client.wallets.pol.quote(walletId, {
  token_id: tokenId, side: 'BUY', amount: 10
});
console.log(`Quote: ${quote.data.expected_shares} shares @ $${quote.data.avg_price}`);

// 5. Place the order
const order = await client.wallets.pol.createOrder(walletId, {
  token_id: tokenId, side: 'BUY', type: 'MARKET', amount: 10
});
console.log(`Order ${order.data.order_id} placed`);

// 6. Check positions
const positions = await client.wallets.positions(walletId);
for (const p of positions.data) {
  console.log(`${p.position.outcome}: ${p.position.shares} shares, PnL: $${p.position.amount_pnl}`);
}
```

### Key concepts for agents

- **token_id** is the universal identifier — use it for prices, orderbooks, quotes, and orders
- **condition_id** groups YES/NO tokens into one market (Polymarket)
- **market_id** is the Kalshi equivalent
- Every response has `{ success: boolean, data?, error? }` — always check `success` first
- Positions return full context: `{ position, event, market }` so agents can reason about what they hold
- `tools.json` in the repo root has every SDK method as a callable tool with parameter schemas

### Cross-venue arbitrage

```typescript
const pairs = await client.markets.similarPairs({ min_similarity: 0.8 });

for (const pair of pairs.data) {
  const pmPrice = pair.polymarket.market.left_price;
  const kaPrice = pair.kalshi.market.left_price;
  const spread = Math.abs(pmPrice - kaPrice);
  if (spread > 0.05) {
    console.log(`Arb opportunity: ${pair.polymarket.event.title}`);
    console.log(`  Polymarket: ${pmPrice} | Kalshi: ${kaPrice} | Spread: ${spread}`);
  }
}
```

## Requirements

- Node.js >= 18.0.0 (or any modern browser)

## License

MIT