Radion Rust SDK
Official, async-first, fully-typed Rust SDK for Radion. One client, one API key.
use StreamExt;
use ;
use Radion;
async
Features
- Unified client — one
Radion, one API key; product surfaces attach as fields. - Auto-reconnect — exponential backoff with jitter after unexpected drops.
- Subscription restore — subscriptions are replayed automatically on reconnect.
- Heartbeats — periodic pings with stale-connection detection.
- Typed end-to-end — every frame, channel, filter, and payload is statically
typed; events stream as a typed
Payloadenum you canmatchexhaustively. - Async-first — built on
tokio; events are aStream.
Requirements
Rust 1.85 or later.
Install
Cargo features:
| Feature | Default | Description |
|---|---|---|
realtime |
✅ | The WebSocket product surface. |
rustls |
✅ | rustls TLS backend (no system OpenSSL). |
native-tls |
Use the platform native TLS backend instead. | |
tracing |
Emit tracing spans/events. |
To drop the realtime transport (e.g. for a future REST-only build):
Usage
Configuration
Build a client with [Radion::builder]:
| Method | Description |
|---|---|
.api_key(key) |
Radion API key (required), sent as X-API-Key. |
.base_url(url) |
Override the REST base URL. Defaults to https://api.radion.app. |
.ws_url(url) |
Override the realtime endpoint. Defaults to wss://api.radion.app/ws. |
let radion = builder.api_key.build?;
# Ok::
Realtime client
Reached as radion.realtime, or constructed standalone with
RealtimeClient::new(RealtimeOptions::new(api_key)).
| Method | Description |
|---|---|
connect() |
Open the connection; resolves once established. |
subscribe(sub) |
Subscribe and return a Stream of that subscription's events. |
unsubscribe(id) |
Drop a subscription by id. |
events() |
Firehose Stream across all subscriptions. |
lifecycle() |
Stream of connection lifecycle events. |
close(code, reason) |
Gracefully close; stops reconnecting. |
connected() |
Whether the socket is currently open. |
Subscriptions & filters
Subscription::new(id, channel) takes a client-defined id (echoed back on every
event) and a channel. Use mempool.-prefixed channels for speculative pending
transactions: "mempool.trading".parse::<SubscribableChannel>()?.
Attach server-side filters with .with_filters(...). Some channels require a
filter — wallets needs wallets, markets needs market_ids or token_ids.
Requirements are validated before any frame is sent.
use ;
let sub = new.with_filters;
Channels
Channel enumerates every channel. Nine topic channels each carry a typed
payload — Trading, Fees, Oracle, Resolution, Lifecycle, Positions,
Combos, Transfers, Accounts — plus two cross-cutting filter channels,
Wallets and Markets, that re-emit the matching topic payload. CHANNELS is
the full array. Each channel's event data is the typed Payload enum — match
on it for compile-time exhaustiveness. Unknown channels or event types are
preserved as Payload::Other(serde_json::Value).
Filter high-volume order flow by size with min_usd on Trading (there is no
separate large-trades channel). Every channel also has a mempool.-prefixed
companion for speculative pending transactions.
Lifecycle events
use StreamExt;
use LifecycleEvent;
# async
Reconnect & subscription restore
By default the client reconnects with exponential backoff (500ms initial, ×2,
30s max, 0.2 jitter) and replays every active subscription on reconnect. Tune via
RealtimeOptions::reconnect(...) or disable with .disable_reconnect().
Heartbeats
A ping is sent every 15s; if no inbound traffic arrives within 10s the connection
is treated as stale, torn down, and reconnected. Tune via
RealtimeOptions::heartbeat(...) or disable with .disable_heartbeat().
Error handling
RadionError covers connection-lifecycle misuse (Connection), server-reported
error frames (Server), and transport failures (Transport). Server and
transport errors during a live connection are surfaced on the lifecycle()
stream as LifecycleEvent::Error.
License
MIT — see LICENSE.