polynode 0.2.1

Rust SDK for the PolyNode API — real-time Polymarket data
Documentation
# 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