Documentation Index
Fetch the complete documentation index at: https://hypernode-docs.polynode.dev/llms.txt
Use this file to discover all available pages before exploring further.
When a WebSocket connection drops, you typically lose every event that happened while you were disconnected. hypernode solves this with session replay: pass a session_id and since_seq cursor on reconnect, and the server replays every missed event that matches your subscription filter before resuming the live stream.
When to use this
- Production trading systems where gaps in the event stream can cause desync between your local state and the real chain state
- Fill monitors that track PnL and positions by watching
fill events
- Builder analytics tracking every fill attributed to your builder address
- Compliance and audit pipelines that need to prove they received every event in a window
- Any client that cares about reliability — brief network blips, client crashes, container restarts, load balancer reconnects
If you don’t care about gaps (sampling use cases, dashboards that refresh periodically), you don’t need session replay. It’s optional. Clients that don’t pass session_id work exactly as before.
How it works for the client
Every event on the WebSocket stream now carries a seq field. It’s a monotonically increasing integer — each event gets a unique seq one higher than the last. Track the highest seq you’ve processed, and on reconnect you’ll get exactly what you missed.
Example event with seq:
{
"seq": 4404497,
"type": "fill",
"timestamp": 1776229763378,
"consensus": "confirmed",
"asset": "BTC",
"user": "0x4b53ec7251039454d057757b6fde7e39e48b49a1",
"data": {
"coin": "BTC",
"side": "B",
"px": "74207.0",
"sz": "0.02644",
"dir": "Close Short",
"closedPnl": "1.70538",
"fee": "0.784813",
"oid": 382009563898,
"tid": 1094600066756112
},
"network": "mainnet"
}
Reconnect flow
Pass session_id and since_seq as query params when reconnecting:
wss://hyper.polynode.dev/ws?key=YOUR_KEY&session_id=<uuid>&since_seq=<last_seq>
After you send your subscribe message, the server responds with:
- A normal
subscribed ack
- A
reconnected notification listing how many events will be replayed
- The replayed events themselves (ordered by seq, already filtered)
- A
replay_complete message
- Live events resume
Subscribed ack
{
"action": "subscribed",
"id": "default",
"sub_id": 5,
"total_subs": 2,
"newest_seq": 4423387,
"session_id": "84391b47-cc77-4b01-97df-ff0944d94d9f"
}
Reconnected notification
{
"action": "reconnected",
"id": "default",
"from_seq": 4412795,
"to_seq": 4423117,
"total_events": 218,
"total_chunks": 1
}
Replay complete
{
"action": "replay_complete",
"id": "default",
"replayed": 218,
"resume_seq": 4423117
}
Retention window
hypernode keeps up to 30 seconds of recent events available for replay. If you reconnect within that window, every missed event that matches your subscription filter is delivered before live events resume. If your cursor is older than the window, you’ll receive a gap signal instead.
Gap signal
{
"action": "reconnected",
"id": "default",
"gap": true,
"oldest_available_seq": 4423117,
"newest_available_seq": 4612394,
"message": "cursor too old, gap detected — reload snapshot state"
}
When you see gap: true, your cursor was older than the oldest replayable event. Reload any snapshot state you were maintaining (positions, order book, etc.) from REST and start fresh. In practice this rarely happens — most clients reconnect within a few seconds.
Full Python client
A reconnect-safe client that tracks the last seq and resumes automatically:
import asyncio, json, uuid, websockets
API_KEY = "pn_live_..."
SESSION = str(uuid.uuid4())
async def stream(last_seq=0):
url = f"wss://hyper.polynode.dev/ws?key={API_KEY}&session_id={SESSION}"
if last_seq > 0:
url += f"&since_seq={last_seq}"
async with websockets.connect(url) as ws:
await ws.send(json.dumps({
"action": "subscribe",
"filters": {"action_types": ["fill"]}
}))
async for raw in ws:
event = json.loads(raw)
action = event.get("action")
if action == "subscribed":
print(f"Subscribed, newest_seq={event.get('newest_seq')}")
continue
if action == "reconnected":
if event.get("gap"):
print("Gap detected — reload snapshot state")
# Reload positions, orderbook, etc. from REST here
else:
print(f"Replaying {event['total_events']} missed events")
continue
if action == "replay_complete":
print(f"Replay done, live at seq {event['resume_seq']}")
continue
# Normal event
if event.get("seq"):
last_seq = event["seq"]
if event.get("type") == "fill":
d = event["data"]
print(f"{d['coin']} {d['sz']}@{d['px']} seq={event['seq']}")
return last_seq
async def main():
last = 0
while True:
try:
last = await stream(last)
except Exception as e:
print(f"Disconnected ({e}), reconnecting with cursor {last}")
await asyncio.sleep(1)
asyncio.run(main())
This client tracks the last seq it processed, and whenever the connection drops — for any reason — it reconnects with the cursor and receives exactly the events it missed.
Limits
| Limit | Value |
|---|
| Retention window | 30 seconds |
| Max events per replay | 10,000 |
| Max events per chunk | 500 |
If you need longer retention or higher replay caps, reach out and we can tune these.