JavaScript / Node.js
Track all pending settlements
const WebSocket = require("ws");
const ws = new WebSocket("wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY");
ws.on("open", () => {
ws.send(JSON.stringify({
action: "subscribe",
type: "settlements",
filters: { status: "pending" }
}));
});
ws.on("message", (data) => {
const msg = JSON.parse(data);
switch (msg.type) {
case "snapshot":
console.log(`Loaded ${msg.count} recent settlements`);
break;
case "settlement":
const d = msg.data;
console.log(
`${d.status.toUpperCase()} | ${d.taker_side} ${d.taker_size} shares @ ${d.taker_price}`,
`| "${d.market_title}" (${d.outcome})`
);
break;
case "status_update":
console.log(`Confirmed: ${msg.data.tx_hash} in ${msg.data.latency_ms}ms`);
break;
case "heartbeat":
break; // ignore
}
});
// Reconnect on close
ws.on("close", () => setTimeout(() => process.exit(1), 1000));
Whale alerts ($5K+)
const ws = new WebSocket("wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY");
ws.on("open", () => {
ws.send(JSON.stringify({
action: "subscribe",
type: "large_trades",
filters: { min_size: 5000 }
}));
});
ws.on("message", (data) => {
const msg = JSON.parse(data);
if (msg.type === "settlement") {
const d = msg.data;
console.log(`WHALE ALERT: ${d.taker_side} $${d.taker_size.toFixed(0)} @ ${d.taker_price}`);
console.log(` Market: ${d.market_title} (${d.outcome})`);
console.log(` Wallet: ${d.taker_wallet}`);
console.log(` TX: ${d.tx_hash}`);
}
});
Monitor a specific market by slug
ws.send(JSON.stringify({
action: "subscribe",
type: "markets",
filters: {
slugs: ["will-pete-hegseth-win-the-2028-us-presidential-election"],
snapshot_count: 100 // Get last 100 events
}
}));
Track a wallet
const TRACKED_WALLET = "0xabcdef1234567890abcdef1234567890abcdef12";
ws.send(JSON.stringify({
action: "subscribe",
type: "wallets",
filters: { wallets: [TRACKED_WALLET] }
}));
// To find the wallet's actual trades inside settlement events,
// iterate data.trades[] and match by maker. NEVER match by taker.
ws.on("message", (raw) => {
const msg = JSON.parse(raw);
if (msg.type !== "settlement") return;
for (const fill of msg.data.trades) {
if (fill.maker.toLowerCase() === TRACKED_WALLET.toLowerCase()) {
console.log(`Trade: ${fill.side} ${fill.size} ${fill.outcome} @ ${fill.price}`);
}
}
});
Always match by
fill.maker, never by fill.taker. The taker field is the counterparty — matching it returns the wrong wallet’s perspective with the opposite token and the complement price. See the Settlement Event reference for full details.Chainlink price feed
This unchanged subscription follows the default Chainlink stream. See Chainlink TWAP Prices to select the 30-second window, the 60-second window, or both during the August transition.const ws = new WebSocket("wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY");
ws.on("open", () => {
ws.send(JSON.stringify({
action: "subscribe",
type: "chainlink",
filters: { feeds: ["BTC/USD"] }
}));
});
ws.on("message", (data) => {
const msg = JSON.parse(data);
if (msg.type === "price_feed") {
const d = msg.data;
console.log(`BTC/USD: $${d.price.toFixed(2)} (bid: $${d.bid.toFixed(2)}, ask: $${d.ask.toFixed(2)})`);
}
});
Settlements + price feeds on same connection
const ws = new WebSocket("wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY");
ws.on("open", () => {
// Subscribe to both — they're independent streams
ws.send(JSON.stringify({ action: "subscribe", type: "settlements" }));
ws.send(JSON.stringify({ action: "subscribe", type: "chainlink" }));
});
ws.on("message", (data) => {
const msg = JSON.parse(data);
switch (msg.type) {
case "settlement":
console.log(`TRADE: ${msg.data.taker_side} ${msg.data.taker_size} @ ${msg.data.taker_price}`);
break;
case "price_feed":
console.log(`BTC: $${msg.data.price.toFixed(2)}`);
break;
}
});
Python
asyncio client with reconnection
import asyncio
import json
import websockets
API_KEY = "pn_live_YOUR_KEY"
URL = f"wss://ws.polynode.dev/ws?key={API_KEY}"
async def connect():
while True:
try:
async with websockets.connect(URL) as ws:
# Subscribe to pending settlements
await ws.send(json.dumps({
"action": "subscribe",
"type": "settlements",
"filters": {"status": "pending", "min_size": 100}
}))
async for message in ws:
msg = json.loads(message)
if msg["type"] == "snapshot":
print(f"Loaded {msg['count']} recent events")
elif msg["type"] == "settlement":
d = msg["data"]
print(f"{d['taker_side']} {d['taker_size']:.0f} @ {d['taker_price']:.2f}"
f" | {d.get('market_title', 'unknown')}")
elif msg["type"] == "status_update":
print(f"Confirmed: {msg['data']['tx_hash'][:16]}..."
f" ({msg['data']['latency_ms']}ms)")
except (websockets.ConnectionClosed, ConnectionError) as e:
print(f"Disconnected: {e}. Reconnecting in 3s...")
await asyncio.sleep(3)
asyncio.run(connect())
Multiple wallet subscriptions
const ws = new WebSocket("wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY");
const subscriptionIds = [];
ws.on("open", () => {
// Subscribe to multiple wallet groups — each creates an independent subscription
ws.send(JSON.stringify({
action: "subscribe",
type: "wallets",
filters: { wallets: ["0xWallet1...", "0xWallet2..."] }
}));
ws.send(JSON.stringify({
action: "subscribe",
type: "wallets",
filters: { wallets: ["0xWallet3...", "0xWallet4..."] }
}));
});
ws.on("message", (data) => {
const msg = JSON.parse(data);
if (msg.type === "subscribed") {
// Save subscription_id for targeted unsubscribe later
subscriptionIds.push(msg.subscription_id);
console.log(`Subscribed: ${msg.subscription_id}`);
}
if (msg.type === "settlement") {
console.log(`${msg.data.taker_side} ${msg.data.taker_size} @ ${msg.data.taker_price}`);
}
});
// Later: remove just one subscription
// ws.send(JSON.stringify({ action: "unsubscribe", subscription_id: subscriptionIds[0] }));
// Or remove all
// ws.send(JSON.stringify({ action: "unsubscribe" }));
wscat (CLI)
Quick testing from the command line:# Install
npm install -g wscat
# Connect
wscat -c "wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY"
# Once connected, paste:
{"action": "subscribe", "type": "settlements", "filters": {"status": "pending"}}
# Subscribe to Chainlink BTC/USD prices
{"action": "subscribe", "type": "chainlink"}
# Subscribe to whale trades (stacks with previous subscriptions)
{"action": "subscribe", "type": "large_trades", "filters": {"min_size": 10000}}
# Subscribe by market slug
{"action": "subscribe", "type": "markets", "filters": {"slugs": ["bitcoin-100k-2026"]}}
# Ping
{"action": "ping"}
# Unsubscribe a specific subscription (use the subscription_id from the ack)
{"action": "unsubscribe", "subscription_id": "abc123:1"}
# Unsubscribe all
{"action": "unsubscribe"}
curl (WebSocket upgrade)
# Using websocat (Rust CLI tool)
websocat "wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY"
# Then type:
{"action":"subscribe","type":"settlements"}
Common patterns
Reconnection with exponential backoff
function createConnection() {
let delay = 1000;
function connect() {
const ws = new WebSocket("wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY");
ws.onopen = () => {
delay = 1000; // Reset backoff
ws.send(JSON.stringify({
action: "subscribe",
type: "settlements"
}));
};
ws.onclose = () => {
console.log(`Reconnecting in ${delay}ms...`);
setTimeout(connect, delay);
delay = Math.min(delay * 2, 30000); // Max 30s
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type !== "heartbeat") {
handleEvent(msg);
}
};
}
connect();
}
Pending-to-confirmed tracking
const pending = new Map();
function handleEvent(msg) {
if (msg.type === "settlement" && msg.data.status === "pending") {
pending.set(msg.data.tx_hash, {
...msg.data,
received_at: Date.now()
});
console.log(`PENDING: ${msg.data.taker_side} ${msg.data.taker_size} @ ${msg.data.taker_price}`);
}
if (msg.type === "status_update") {
const original = pending.get(msg.data.tx_hash);
if (original) {
console.log(`CONFIRMED: ${msg.data.latency_ms}ms latency, block ${msg.data.block_number}`);
pending.delete(msg.data.tx_hash);
}
}
}

