Documentation / Guides

WebSocket stream

Stream greyhound results and race status changes over wss://: channels, the subscribe protocol, the replay window and connection limits.

Live keys can hold up to 2 connections to wss://greyhoundapi.com/v1/stream. Sandbox keys have no stream. Present your key on the upgrade in whichever way suits your client: the X-API-Key header (or Authorization: Bearer) for server-side clients, or — since browsers can't set handshake headers — as a WebSocket subprotocol:

// browser: pass a marker protocol and your key
const ws = new WebSocket('wss://greyhoundapi.com/v1/stream',
  ['gapi-stream', 'gapi_live_yourkey']);

Subscribe by channel — topic {results|status|cards} and region {GB|AU|*}:

{ "action": "subscribe",
  "channels": ["results:GB", "status:*", "cards:AU"] }

Events

result.received when a result lands in the pipeline; race.status_changed on off / results_pending / void / abandoned transitions; card.updated for runner changes on upcoming races.

{ "event": "result.received", "channel": "results:GB",
  "race_id": 1229082, "track": "Romford",
  "results_delay_s": 1060, "ts": "2026-07-08T21:03:41Z" }

Reconnecting

Heartbeat ping every 30s. On reconnect, send {"action":"replay","channel":"results:GB","since":"<iso>"} to replay the last 15 minutes; for anything older, catch up over REST with GET /v1/results/latest?since=.

Close codes

The gateway closes with 4401 (unknown, revoked or expired key), 4403 (sandbox key, or a live key suspended mid-session — you'll get a {"event":"closing","reason":…} frame first) or 4408 (you already hold the maximum 2 connections). A suspended or expired key is dropped within a minute, not just refused on the next connect.