WebSocket streaming
Connect to:
wss://lowcapsxyz.com/v1/stream
Authenticate the WebSocket handshake with either Authorization: Bearer <your-api-key> or a valid same-origin session cookie. Then send exactly one JSON subscribe frame.
Subscribe
{
"filter": {
"chain_ids": [8453],
"pool_ids": [
"0x1111111111111111111111111111111111111111111111111111111111111111"
],
"token_ids": [
"0x2222222222222222222222222222222222222222222222222222222222222222"
]
},
"resume_cursor": null
}
Filter arrays must be strictly sorted and unique. Empty pool_ids and token_ids arrays select every routed message for the chosen chains. A null cursor starts live-only delivery.
Message envelope
Durable messages share this envelope:
{
"stream_sequence": 10842,
"routing": {
"chain_id": 8453,
"pool_ids": [],
"token_ids": []
},
"type": "PRICE_UPSERT",
"payload": {}
}
stream_sequence is monotonic, not necessarily contiguous. Use it for ordering and recovery. Message types are:
| Type | Meaning |
|---|---|
PRICE_UPSERT | Absolute current price state; safe to apply repeatedly. |
PRICE_RETRACT | Previously published evidence changed or was removed; recompute from the supplied post-change state. |
SWAP_OBSERVED | A decoded swap with exact amounts and event position. |
FEED_HEALTH | A chain feed-health update. |
RESET_REQUIRED | Replay cannot safely continue; rebuild state and reconnect. |
RESET_REQUIRED is a control message and has no stream_sequence.
Resume and replay
For snapshot-plus-delta consumption:
-
Read every page of
GET /v1/poolsand retain the minimumsnapshot_sequencereturned across the pages. -
Create a cursor after that boundary:
curl --fail-with-body -X POST \ -H 'Authorization: Bearer <your-api-key>' \ 'https://lowcapsxyz.com/v1/session?chain_id=8453&snapshot_sequence=<snapshot-sequence>' -
Reconnect and send the returned
resume_cursorin the subscribe frame. -
Apply replayed records, then continue with live records. Ignore overlap at or below the last applied sequence.
The current session cursor is chain-wide. A narrower pool or token filter with that cursor causes RESET_REQUIRED with FILTER_MISMATCH. For resumable delivery, subscribe chain-wide and filter locally.
Heartbeats and slow consumers
The server sends a WebSocket ping every 30 seconds and expects a pong before the next heartbeat. It also responds to client pings.
If a slow consumer falls behind, the connection closes with code 1013 and identifies the last delivered sequence. Create a new session cursor after that sequence and reconnect. If replay is no longer available, discard local state and take a fresh snapshot.
RESET_REQUIRED
{
"type": "RESET_REQUIRED",
"payload": {
"reason": "REPLAY_UNAVAILABLE",
"server_time_unix_ms": 1784217600000
}
}
Possible reasons are INVALID_CURSOR, EXPIRED_CURSOR, FILTER_MISMATCH, REPLAY_UNAVAILABLE, and SCHEMA_MISMATCH.
On receipt:
- stop applying stream messages;
- discard state whose consistency depends on the rejected cursor;
- fetch a fresh pool snapshot;
- create a new cursor at that snapshot boundary;
- reconnect chain-wide.