polynode
Rust SDK for the PolyNode real-time Polymarket API.
Stream settlements, trades, positions, deposits, oracle events, orderbook updates, and more through a single WebSocket connection. All events enriched with full market metadata.
Install
[dependencies]
polynode = "0.2"
tokio = { version = "1", features = ["rt", "macros"] }
Quick Start
use polynode::PolyNodeClient;
#[tokio::main]
async fn main() -> polynode::Result<()> {
let client = PolyNodeClient::new("pn_live_...")?;
let markets = client.markets(Some(10)).await?;
println!("{} markets, {} total", markets.count, markets.total);
let results = client.search("bitcoin", Some(5), None).await?;
for r in &results.results {
println!("{}", r.question.as_deref().unwrap_or("?"));
}
Ok(())
}
REST API
client.healthz().await?;
client.status().await?;
client.create_key(Some("my-bot")).await?;
client.markets(Some(10)).await?;
client.market("token_id").await?;
client.market_by_slug("bitcoin-100k").await?;
client.market_by_condition("0xabc...").await?;
client.list_markets(&ListMarketsParams {
count: Some(20),
sort: Some("volume".into()),
..Default::default()
}).await?;
client.search("ethereum", Some(5), None).await?;
client.candles("token_id", Some(CandleResolution::OneHour), Some(100)).await?;
client.stats("token_id").await?;
client.recent_settlements(Some(20)).await?;
client.token_settlements("token_id", Some(10)).await?;
client.wallet_settlements("0xabc...", Some(10)).await?;
client.wallet("0xabc...").await?;
client.rpc_call("eth_blockNumber", serde_json::json!([])).await?;
WebSocket Streaming
use polynode::ws::{Subscription, SubscriptionType, StreamOptions};
use polynode::WsMessage;
let mut stream = client.stream(StreamOptions {
compress: true,
auto_reconnect: true,
..Default::default()
}).await?;
stream.subscribe(
Subscription::new(SubscriptionType::Settlements)
.min_size(100.0)
.status("pending")
.snapshot_count(20)
).await?;
while let Some(msg) = stream.next().await {
match msg? {
WsMessage::Event(event) => {
match event {
polynode::PolyNodeEvent::Settlement(s) => {
println!("{} ${:.2} on {}",
s.taker_side, s.taker_size,
s.market_title.as_deref().unwrap_or("unknown"));
}
polynode::PolyNodeEvent::StatusUpdate(u) => {
println!("Confirmed in {}ms", u.latency_ms);
}
_ => {}
}
}
WsMessage::Snapshot(events) => {
println!("Snapshot: {} events", events.len());
}
_ => {}
}
}
Subscription Types
SubscriptionType::Settlements SubscriptionType::Trades SubscriptionType::Prices SubscriptionType::Blocks SubscriptionType::Wallets SubscriptionType::Markets SubscriptionType::LargeTrades SubscriptionType::Oracle SubscriptionType::Chainlink
Subscription Filters
Subscription::new(SubscriptionType::Settlements)
.wallets(vec!["0xabc...".into()])
.tokens(vec!["21742633...".into()])
.slugs(vec!["bitcoin-100k".into()])
.condition_ids(vec!["0xabc...".into()])
.side("BUY")
.status("pending")
.min_size(100.0)
.max_size(10000.0)
.event_types(vec!["settlement".into()])
.snapshot_count(50)
.feeds(vec!["BTC/USD".into()])
Orderbook Streaming
use polynode::{ObStreamOptions, ObMessage, OrderbookUpdate, LocalOrderbook};
let mut stream = client.orderbook_stream(ObStreamOptions::default()).await?;
stream.subscribe(vec!["token_id_1".into(), "token_id_2".into()]).await?;
let mut book = LocalOrderbook::new();
while let Some(msg) = stream.next().await {
match msg? {
ObMessage::Update(OrderbookUpdate::Snapshot(snap)) => {
book.apply_snapshot(&snap);
println!("{}: {} bids, {} asks", snap.asset_id, snap.bids.len(), snap.asks.len());
}
ObMessage::Update(OrderbookUpdate::Update(delta)) => {
book.apply_update(&delta);
}
ObMessage::Update(OrderbookUpdate::PriceChange(change)) => {
for asset in &change.assets {
println!("{} {}: {}", change.market, asset.outcome, asset.price);
}
}
_ => {}
}
}
let best_bid = book.best_bid("token_id");
let best_ask = book.best_ask("token_id");
let spread = book.spread("token_id");
Configuration
let client = PolyNodeClient::builder("pn_live_...")
.base_url("https://api.polynode.dev")
.ws_url("wss://ws.polynode.dev/ws")
.ob_url("wss://ob.polynode.dev/ws")
.rpc_url("https://rpc.polynode.dev")
.timeout(Duration::from_secs(10))
.build()?;
Error Handling
use polynode::Error;
match client.market("invalid-id").await {
Ok(detail) => println!("{:?}", detail),
Err(Error::NotFound(msg)) => println!("Not found: {}", msg),
Err(Error::Auth(msg)) => println!("Auth failed: {}", msg),
Err(Error::RateLimited(msg)) => println!("Rate limited: {}", msg),
Err(e) => println!("Other error: {}", e),
}
Links
License
MIT