Connection and subscription.
The proposed protocol uses a long-lived secure WebSocket. Clients authenticate once, create a scoped subscription, establish state from a snapshot, and process ordered deltas.
Connection
The production hostname is not yet active. The intended connection target is shown only to make the draft concrete.
wss://stream.oddsloom.com/v1UTF-8 JSON text frames for the initial beta.
Control messages are bidirectional; state and deltas flow server to client.
WebSocket compression policy remains under evaluation.
Sandbox and production credentials will be isolated.
Authentication
The proposed handshake sends a scoped API key in the first application frame. This avoids putting credentials in URLs and keeps authentication explicit.
{
"type": "session.authenticate",
"request_id": "req_01J5Y7JVB6",
"data": { "api_key": "ol_test_••••••••" }
}Until the service exists, key format, scopes, rotation, and authentication timeouts remain design decisions rather than guarantees.
Session ready
A successful handshake returns session capabilities before subscriptions are accepted.
{
"type": "session.ready",
"schema_version": "0.3",
"message_id": "msg_01J5Y7K2DX",
"sequence": 0,
"emitted_at": "2026-08-07T05:19:59.981Z",
"data": {
"session_id": "ses_01J5Y7K1Y7",
"environment": "sandbox",
"heartbeat_interval_ms": 15000,
"resume_supported": true
}
}session_idstringIdentifier for this connection lifetime.environmentenumsandbox or production.heartbeat_interval_msintegerExpected maximum interval between liveness messages.resume_supportedbooleanWhether this session class supports replay from a committed position.Create a subscription
Filters describe the state the consumer wants maintained. The server validates the combination and returns the effective scope; it does not silently broaden a request.
{
"type": "subscription.create",
"request_id": "req_01J5Y7KZXN",
"data": {
"sports": ["basketball"],
"leagues": ["nba"],
"books": ["book_a", "book_b"],
"market_types": ["moneyline", "spread", "total"],
"event_phase": ["pregame", "live"]
}
}sportsstring[]Canonical sport keys.leaguesstring[]?Optional league restriction.booksstring[]Canonical book IDs to include.market_typesstring[]?Optional canonical market families.event_phaseenum[]?pregame, live, or both.Subscription ready
The accepted message establishes the stream position immediately before the initial snapshot.
{
"type": "subscription.ready",
"schema_version": "0.3",
"message_id": "msg_01J5Y7M0A2",
"sequence": 18490,
"emitted_at": "2026-08-07T05:20:00.041Z",
"data": {
"subscription_id": "sub_01J5Y7KZXN",
"effective_filters": {
"sports": ["basketball"],
"leagues": ["nba"],
"books": ["book_a", "book_b"]
}
}
}Lifecycle
Subscription modification and multiple concurrent subscriptions are still open design questions. The first beta may intentionally support one subscription per connection to keep sequence ownership unambiguous.