The stream gateway exposes:
Streaming requires the websocket entitlement, included with Sharp and Max and some active grants/legacy plans. REST rate limits and monthly request quota do not meter WebSocket frames. Streaming availability is separate from REST endpoint availability.

Connect

Prefer Authorization: Bearer <workspace-api-token> during the HTTP upgrade. Browser clients that cannot set headers can use ?token=...; the Authorization header takes precedence. Protect the URL as a credential. Reads require api.read scope. Authentication and plan failures occur before upgrade as HTTP 401/403; token-store failures can return 500. There is one active connection per token and organization. A new connection supersedes the previous one. Share that connection inside your own service if several consumers need the same feed.

Subscribe and unsubscribe

Send one JSON frame per channel:
Confirmation echoes the request ID and channel:
Use unsubscribe with the same channel; the server replies unsubscribe.ok. Duplicate subscriptions are idempotent. Failed subscriptions use subscribe.error and reason, including invalid_channel, too_many_subscriptions, or rate_limited. IDs can contain dots. Use the returned canonical ID in its entirety. A valid channel name is not evidence that data currently exists for that channel. Bookmaker visibility applies to pushed odds/prop data too.

Events and recovery

data is the channel-specific event payload; it is not the REST response envelope. Event IDs are monotonic per connection, not durable replay cursors. The server does not send an initial REST snapshot when confirming a subscription. Use REST to initialize your state and apply subsequent events. A gap frame includes channel, optional missed_count, from_id, to_id, and ts. Counts/IDs are best-effort and can be omitted. A gap signals dropped events or a restarted upstream stream. Refetch the affected resource through REST and continue; there is no customer replay/resume API. On reconnect, resubscribe and refresh state.

Heartbeat and limits

Every 20 seconds the server sends {"type":"ping"}. Reply with {"type":"pong"} within 10 seconds. These are JSON application frames. The current implementation allows 100 subscriptions per connection and limits incoming frames with a 250-frame burst bucket refilling at 20 frames/second. Inbound messages are limited to 4 KiB. Slow consumers can overflow the bounded send queue and receive gap notifications. Open connections revalidate token/access approximately every minute. Some entitlements are captured at connection time, so reconnect after plan changes. Use jittered backoff for transient disconnects; avoid a reconnect contest between two services that repeatedly supersede each other.