# polynode
Rust SDK for the [PolyNode](https://polynode.dev) 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
```toml
[dependencies]
polynode = "0.2"
tokio = { version = "1", features = ["rt", "macros"] }
```
## Quick Start
```rust
use polynode::PolyNodeClient;
#[tokio::main]
async fn main() -> polynode::Result<()> {
let client = PolyNodeClient::new("pn_live_...")?;
// Fetch top markets
let markets = client.markets(Some(10)).await?;
println!("{} markets, {} total", markets.count, markets.total);
// Search
let results = client.search("bitcoin", Some(5), None).await?;
for r in &results.results {
println!("{}", r.question.as_deref().unwrap_or("?"));
}
Ok(())
}
```
## REST API
```rust
// System
client.healthz().await?;
client.status().await?;
client.create_key(Some("my-bot")).await?;
// Markets
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?;
// Pricing
client.candles("token_id", Some(CandleResolution::OneHour), Some(100)).await?;
client.stats("token_id").await?;
// Settlements
client.recent_settlements(Some(20)).await?;
client.token_settlements("token_id", Some(10)).await?;
client.wallet_settlements("0xabc...", Some(10)).await?;
// Wallets
client.wallet("0xabc...").await?;
// RPC (rpc.polynode.dev)
client.rpc_call("eth_blockNumber", serde_json::json!([])).await?;
```
## WebSocket Streaming
```rust
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
```rust
SubscriptionType::Settlements // pending + confirmed settlements
SubscriptionType::Trades // all trade activity
SubscriptionType::Prices // price-moving events
SubscriptionType::Blocks // new Polygon blocks
SubscriptionType::Wallets // all wallet activity
SubscriptionType::Markets // all market activity
SubscriptionType::LargeTrades // $1K+ trades
SubscriptionType::Oracle // UMA resolution events
SubscriptionType::Chainlink // real-time price feeds
```
### Subscription Filters
```rust
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
```rust
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);
}
}
_ => {}
}
}
// Query local state
let best_bid = book.best_bid("token_id");
let best_ask = book.best_ask("token_id");
let spread = book.spread("token_id");
```
## Configuration
```rust
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
```rust
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
- [Documentation](https://docs.polynode.dev)
- [API Reference](https://docs.polynode.dev/api-reference)
- [Get an API Key](https://polynode.dev)
- [TypeScript SDK](https://www.npmjs.com/package/polynode-sdk)
## License
MIT