.proto files, compile them for your language, and see working decoder code for the frames the gateway sends. Read it before your first connection to the stream; come back to it whenever a field decodes to a value that looks wrong by orders of magnitude.
Getting the Proto Files
Download all proto files (zip) Or download individual files and place them in aproto/kairos/v1/ directory:
The synthetic schema belongs under
proto/kairos/synthetic/v1/, not
proto/kairos/v1/. Synthetic data frames also carry a version byte after their
type tag. See the Synthetic Book Stream tutorial.
Your local directory structure should look like:
Compiling Proto Files
Python
Go
C++
TypeScript / JavaScript
Rust
Add toCargo.toml:
build.rs:
OrderbookSnapshot carries its own scales
OrderbookSnapshot has two fields that a naive decoder will miss:
Every prediction-market provider sends
0 for both, so existing decoders are
unaffected.
Gotcha: perpetual snapshots set the scales per snapshot. A consumer that
hard-codes 10,000 will read perpetual prices wrong by orders of magnitude.
Always divide by the snapshot’s own scale:
OrderbookDelta has no scale fields — it is only emitted by providers that
publish on the default scale. Perpetual books publish whole baselines, never
deltas, which is what makes a per-snapshot scale safe: two snapshots at
different scales are never merged.
Both carry an ownership epoch
The epoch is bumped when ownership of a contract transfers between streamer
instances.
0 means unfenced (legacy publishers).
Gotcha: drop any frame from a lower epoch. Two streamer instances have
independent sequence spaces, so a decoder must discard any frame whose
epoch is below the highest it has seen for that contract — otherwise a
brief double-publish during a handoff collides the two sequence spaces and
freezes the book.Reading Messages in Code
Every binary WebSocket message has a 1-byte type tag prefix.Always dispatch on the type tag first. Never assume the payload is a specific message type. New tags may be added in future versions — clients that decode blindly will break.
Gotcha: a sequence gap means a full resync, with no tolerance. The example below stops applying deltas the momentExample in Python:delta.seqruns ahead ofexpected_seq(orsnapshot_seqstops matching) and waits for a fresh snapshot from aFetchRequest. Skipping that check silently corrupts the local book by mixing levels from two baselines. See Sequencing and recovery.
Handling ErrorResponse (tag 0x17)
The server reports in-band, recoverable errors (malformed subscribe, unknown or unauthorized topic, rate limit, subscription limit, failed snapshot recovery, unknown tag, text frame received) as an ErrorResponse protobuf:
The two
fetch_* forms embed the market they refer to, so match action by
prefix rather than equality. The full catalogue of messages is in
Market Data → In-band ErrorResponse.
The connection stays open after an ErrorResponse — only the offending message is dropped. Decode and surface it for diagnostics:
4001 JWT expiry/revocation, 4002 anonymous session lifetime, 4003 anonymous lease lost, 1006 slow consumer / idle timeout), upgrade-time 401/429/503 rejections, and recommended reconnect behavior, see Market Data → Errors & Disconnection.

