Skip to main content

Documentation Index

Fetch the complete documentation index at: https://polynode.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Short-form markets are Polymarket’s Chainlink-based crypto prediction markets that rotate on fixed intervals. Bitcoin, Ethereum, Solana, XRP, Dogecoin, Hyperliquid, and BNB each have active 5-minute, 15-minute, and 1-hour “Up or Down” markets running continuously. The SDK handles everything: discovering the current window’s markets, subscribing for real-time events, and automatically rotating to the next window when the current one expires. You get enriched market data including the price-to-beat (Chainlink opening price), live odds, liquidity, and volume with zero additional latency.

5-Minute

New market every 300 seconds. 7 coins.

15-Minute

New market every 900 seconds. 7 coins.

1-Hour

New market every 3600 seconds. 7 coins.

Quick Start

import { PolyNodeWS } from 'polynode-sdk';

const ws = new PolyNodeWS('pn_live_...', 'wss://ws.polynode.dev/ws');

const stream = ws.shortForm('15m', { coins: ['btc', 'eth', 'sol'] });

stream.on('rotation', (r) => {
  console.log(`New window: ${r.timeRemaining}s remaining`);
  for (const m of r.markets) {
    console.log(`${m.coin}: beat $${m.priceToBeat} | ${(m.upOdds * 100).toFixed(0)}% up`);
  }
});

stream.on('settlement', (event) => {
  console.log(`${event.outcome} $${event.taker_size} on ${event.market_title}`);
});

Live Output

Here’s actual output from a live 15-minute stream with BTC, ETH, and SOL:
Rotation Event
{
  "interval": "15m",
  "timeRemaining": 51,
  "windowStart": 1774072800,
  "windowEnd": 1774073700,
  "marketCount": 3
}
Each market in the rotation includes enrichment data at zero cost:
BTC Market
{
  "coin": "btc",
  "slug": "btc-updown-15m-1774072800",
  "title": "Bitcoin Up or Down - March 21, 2:00AM-2:15AM ET",
  "conditionId": "0x037ad8cf0b1d7dc7febd2a46c400398838163dc3...",
  "clobTokenIds": ["11496172...", "66255671..."],
  "upOdds": 0.845,
  "downOdds": 0.155,
  "priceToBeat": 70694.18,
  "liquidity": 9833.25,
  "volume24h": 51679.05
}
ETH Market
{
  "coin": "eth",
  "slug": "eth-updown-15m-1774072800",
  "title": "Ethereum Up or Down - March 21, 2:00AM-2:15AM ET",
  "upOdds": 0.365,
  "downOdds": 0.635,
  "priceToBeat": 2152.93,
  "liquidity": 2289.0,
  "volume24h": 14602.61
}
SOL Market
{
  "coin": "sol",
  "slug": "sol-updown-15m-1774072800",
  "title": "Solana Up or Down - March 21, 2:00AM-2:15AM ET",
  "upOdds": 0.955,
  "downOdds": 0.045,
  "priceToBeat": 89.97,
  "liquidity": 3004.32,
  "volume24h": 4953.08
}
Settlement events flow in real-time as trades happen. Here’s a real settlement captured from the live stream:
Settlement Event
{
  "event_type": "settlement",
  "status": "pending",
  "event_slug": "btc-updown-15m-1774073700",
  "event_title": "Bitcoin Up or Down - March 21, 2:15AM-2:30AM ET",
  "market_slug": "btc-updown-15m-1774073700",
  "market_title": "Bitcoin Up or Down - March 21, 2:15AM-2:30AM ET",
  "outcome": "Down",
  "taker_side": "SELL",
  "taker_size": 7.58,
  "taker_price": 0.33,
  "taker_wallet": "0xe49b2c1ca08c4aef70c061ef9cfcabbcea638973",
  "taker_base_fee": 1000,
  "tick_size": 0.01,
  "neg_risk": false,
  "condition_id": "0x037ad8cf0b1d7dc7febd2a46c400398838163dc3...",
  "detected_at": 1774074055797,
  "tx_hash": "0x726b5ba5d7c48d277f7923a9482a3f7f1fcfac36...",
  "outcomes": ["Up", "Down"],
  "trades": [
    {
      "maker": "0xd44e29936409019f93993de8bd603ef6cb1bb15e",
      "taker": "0xe49b2c1ca08c4aef70c061ef9cfcabbcea638973",
      "outcome": "Down",
      "side": "BUY",
      "price": 0.37,
      "size": 5,
      "maker_amount": "1850000",
      "taker_amount": "5000000"
    }
  ]
}
In a 25-second test, the 15-minute stream received 157 settlement events across 3 coins. The 5-minute stream received 323 events across 2 coins in 20 seconds. These markets are very active.

Intervals

IntervalCodeWindowSlug Pattern
5 minutes'5m' / FiveMin300sbtc-updown-5m-{timestamp}
15 minutes'15m' / FifteenMin900sbtc-updown-15m-{timestamp}
1 hour'1h' / Hourly3600sbitcoin-up-or-down-march-21-2026-2am-et

Slug Calculator

Pick a coin and interval to see the current market slug. Updates live with a countdown to the next window.
The slug pattern is deterministic: {coin}-updown-{interval}-{windowTimestamp}. Compute it yourself:
const now = Math.floor(Date.now() / 1000);
const window5m = Math.floor(now / 300) * 300;
const window15m = Math.floor(now / 900) * 900;

console.log(`btc-updown-5m-${window5m}`);   // current BTC 5m slug
console.log(`eth-updown-15m-${window15m}`);  // current ETH 15m slug
You don’t need to compute slugs manually. The SDK’s shortForm() handles discovery automatically and gives you the slug, conditionId, and clobTokenIds on every rotation event.

Supported Coins

All 7 Chainlink-tracked coins are supported:
CoinIDSymbol
Bitcoinbtc / Coin::BtcBTC
Ethereumeth / Coin::EthETH
Solanasol / Coin::SolSOL
XRPxrp / Coin::XrpXRP
Dogecoindoge / Coin::DogeDOGE
Hyperliquidhype / Coin::HypeHYPE
BNBbnb / Coin::BnbBNB
If no coins are specified, all 7 are subscribed.

Market Enrichments

Every ShortFormMarket includes these fields, all populated during discovery with zero hot-path cost:
coin
string
Coin identifier ('btc', 'eth', 'sol', etc.).
slug
string
Market URL slug (e.g., 'btc-updown-15m-1774072800').
title
string
Human-readable market title (e.g., “Bitcoin Up or Down - March 21, 2:00AM-2:15AM ET”).
conditionId
string
The Polymarket condition ID. Use this to subscribe via the main WebSocket with condition_ids filters.
clobTokenIds
string[]
The two CLOB token IDs (Up and Down outcomes). Pass these directly to OrderbookEngine.subscribe() to get real-time orderbook data for this market. See Orderbook + Short-Form below.
outcomes
string[]
Outcome labels, always ["Up", "Down"].
outcomePrices
number[]
Raw outcome prices from the CLOB, matching the outcomes array order.
windowStart
number
Unix timestamp (seconds) when this market window opened.
windowEnd
number
Unix timestamp (seconds) when this market window closes.
priceToBeat
number | null
The Chainlink opening price for this window. For “Up” to win, the closing price must exceed this value. Fetched once per rotation via the Polymarket crypto-price API.
upOdds
number
Probability (0-1) that “Up” wins, derived from the market’s outcome prices. For example, 0.845 means the market prices an 84.5% chance of Up.
downOdds
number
Probability (0-1) that “Down” wins. Always 1 - upOdds.
liquidity
number
Market liquidity in USD, from the Gamma API response. No extra call.
volume24h
number
24-hour trading volume in USD across all windows for this coin’s series. No extra call.
timeRemaining
number
Seconds remaining in the current window. Computed client-side (zero cost). Available on the rotation event and as a live getter on the stream.
None of these enrichments touch the event hot path. priceToBeat is one HTTP call per coin per rotation (e.g., 7 calls every 15 minutes). Everything else is parsed from data already fetched during discovery or computed locally.

Events

rotation

Emitted once per window when new markets are discovered and subscribed.
stream.on('rotation', (r) => {
  console.log(r.interval);       // '15m'
  console.log(r.timeRemaining);  // 847
  console.log(r.markets.length); // 7

  for (const m of r.markets) {
    console.log(m.coin, m.priceToBeat, m.upOdds);
  }
});

settlement

The primary event. Fired when a trade is detected on any subscribed short-form market. Includes the full settlement payload with market metadata, wallet addresses, trade size, and outcome.
stream.on('settlement', (event) => {
  console.log(event.market_slug);  // 'btc-updown-15m-1774072800'
  console.log(event.outcome);      // 'Up' or 'Down'
  console.log(event.taker_size);   // 12.5
  console.log(event.status);       // 'pending' or 'confirmed'
});

error

Non-fatal errors (e.g., a coin’s market not found). The stream continues operating.
stream.on('error', (err) => {
  console.error(err.message);
});

Time Remaining

In TypeScript, stream.timeRemaining is a live getter that always returns the current seconds remaining:
// Check anytime — no network call, pure local math
setInterval(() => {
  console.log(`${stream.timeRemaining}s until next rotation`);
}, 1000);
In Rust, time_remaining is provided on each RotationInfo. Compute it manually between rotations:
let remaining = rotation.window_end - (SystemTime::now()
    .duration_since(UNIX_EPOCH).unwrap().as_secs() as i64);

Options

const stream = ws.shortForm('15m', {
  coins: ['btc', 'eth'],         // default: all 7
  apiBaseUrl: 'https://api.polynode.dev', // default
  rotationBuffer: 3,             // seconds after window end before discovering next
});

How It Works

1

Discovery

On start and at each rotation, the SDK fetches market data from the Gamma API proxy. For 5m and 15m markets, it constructs deterministic slugs like btc-updown-15m-{timestamp}. For hourly markets, it queries by series. All 7 coins are fetched in parallel.
2

Enrichment

In parallel with discovery, the SDK fetches the Chainlink opening price (price-to-beat) for each coin. Odds, liquidity, and volume are parsed from the existing Gamma response. No extra network calls for these.
3

Subscribe

The SDK subscribes to settlements with slug filters for all discovered markets on the existing WebSocket connection. Events start flowing immediately.
4

Rotate

A timer fires at windowEnd + 3 seconds. The SDK unsubscribes, re-discovers the next window’s markets, and resubscribes. A rotation event is emitted with the new market data.

Cleanup

stream.stop();        // cancel timer, unsubscribe
ws.disconnect();      // close WebSocket

Full Example: Price Tracker

A complete example that tracks all 7 coins on 5-minute windows and logs the price-to-beat vs current odds:
import { PolyNodeWS } from 'polynode-sdk';

const ws = new PolyNodeWS('pn_live_...', 'wss://ws.polynode.dev/ws');
const stream = ws.shortForm('5m');

stream.on('rotation', (r) => {
  console.log(`\n--- New 5m window | ${r.timeRemaining}s remaining ---`);
  for (const m of r.markets) {
    const dir = m.upOdds > 0.5 ? 'UP' : 'DOWN';
    const pct = Math.max(m.upOdds, m.downOdds) * 100;
    console.log(`  ${m.coin.toUpperCase().padEnd(5)} $${m.priceToBeat?.toFixed(2) ?? '?'}${dir} ${pct.toFixed(0)}% | $${m.liquidity.toFixed(0)} liq`);
  }
});

stream.on('settlement', (e) => {
  console.log(`  Trade: ${e.outcome} $${e.taker_size?.toFixed(2)} on ${e.event_slug}`);
});

// Countdown
setInterval(() => {
  process.stdout.write(`\r  ${stream.timeRemaining}s remaining   `);
}, 1000);

Live Output (all 7 coins, 5m)

--- New 5m window | 193s remaining ---
  BTC   $70697.94 → DOWN 53% | $23248 liq
  ETH   $2153.39 → DOWN 51% | $30702 liq
  BNB   $642.23 → DOWN 55% | $9798 liq
  HYPE  $39.34 → DOWN 50% | $419 liq
  XRP   $1.45 → DOWN 51% | $10924 liq
  DOGE  $0.09 → DOWN 59% | $9800 liq
  SOL   $89.97 → UP 51% | $10977 liq
  Trade: Down $30.00 on btc-updown-5m-1774074300
  Trade: Down $30.00 on btc-updown-5m-1774074300
  Trade: Down $15.00 on btc-updown-5m-1774074300

--- 397 trades in 15s | 179s remaining ---

Live Output (Rust, all 3 intervals)

=== Testing 5m ===
ROTATION: 5m | 249s remaining | 2 markets
  btc | btc-updown-5m-1774074300 | beat $70697.94 | 48% up | $23248 liq
  eth | eth-updown-5m-1774074300 | beat $2153.39 | 50% up | $30702 liq
  Events in 10s: 388

=== Testing 15m ===
ROTATION: 15m | 239s remaining | 2 markets
  btc | btc-updown-15m-1774073700 | beat $70714.31 | 68% up | $9883 liq
  eth | eth-updown-15m-1774073700 | beat $2152.36 | 88% up | $3028 liq
  Events in 10s: 73

=== Testing 1h ===
ROTATION: 1h | 2029s remaining | 2 markets
  btc | bitcoin-up-or-down-march-21-2026-2am-et | beat $70697.94 | 70% up | $10652 liq
  eth | ethereum-up-or-down-march-21-2026-2am-et | beat $2153.39 | 52% up | $7162 liq
  Events in 10s: 20

Connect the Orderbook to Crypto Markets

Want depth data for crypto markets? Every ShortFormMarket in the rotation event includes clobTokenIds — the token IDs for both Up and Down outcomes. Pass them straight to OrderbookEngine and you get live orderbook depth, bid/ask spreads, and price moves alongside your settlement stream. One setup, three real-time feeds.
Here’s the full pattern: short-form discovers markets, hands the token IDs to the orderbook engine, and both streams run in parallel.
import { PolyNodeWS, OrderbookEngine } from 'polynode-sdk';

const KEY = 'pn_live_...';
const ws = new PolyNodeWS(KEY, 'wss://ws.polynode.dev/ws');
const engine = new OrderbookEngine({ apiKey: KEY, compress: true });

// 1. Start the short-form stream
const stream = ws.shortForm('5m', { coins: ['btc', 'eth'] });

// 2. On each rotation, subscribe the orderbook to the new markets
stream.on('rotation', async (r) => {
  const tokenIds = r.markets.flatMap(m => m.clobTokenIds);
  await engine.subscribe(tokenIds);

  for (const m of r.markets) {
    console.log(`${m.coin}: beat $${m.priceToBeat} | ${(m.upOdds * 100).toFixed(0)}% up`);
  }
});

// 3. Orderbook events
engine.on('ready', () => console.log(`${engine.size} books loaded`));
engine.on('price', (p) => {
  for (const a of p.assets) {
    console.log(`Book: ${a.outcome} = ${a.price}`);
  }
});

// 4. Settlement events (trades happening on these markets)
stream.on('settlement', (e) => {
  console.log(`Trade: ${e.outcome} $${e.taker_size} on ${e.event_slug}`);
});
This gives you three real-time feeds from one setup: settlements (trade flow), orderbook (depth and price moves), and rotation enrichments (odds, liquidity, price-to-beat). Add a chainlink subscription on the same WebSocket connection for the underlying asset price too.

What you get

StreamSourceData
Settlementsstream.on('settlement')Every trade on the crypto market: size, price, side, wallet
Orderbookengine.on('price')Bid/ask depth, price changes, spread
Market infostream.on('rotation')Price-to-beat, odds, liquidity, volume, time remaining
Crypto priceChainlink subscriptionUnderlying BTC/ETH/SOL price at ~1/sec