Events
The SDK exposes two families of events through client.on(...): lifecycle (connection state) and data (sport events and odds).
Lifecycle events
Section titled “Lifecycle events”| Event | Payload |
|---|---|
connected | undefined |
disconnected | { willReconnect: boolean, code: number, reason: string } |
reconnecting | { attempt: number, delayMs: number } |
error | { message: string, fatal: boolean } |
connected
Section titled “connected”Fires when the WebSocket has opened and the SDK has received the gateway’s initial state. After this fires, client.snapshot() is populated.
disconnected
Section titled “disconnected”Fires when the WebSocket closes for any reason.
willReconnect:trueif the SDK will attempt to reconnect (transient failure within retry policy).code: WebSocket close code. Auth failures use4001,4002,4003— see Close codes.reason: server-provided reason string, possibly empty.
reconnecting
Section titled “reconnecting”Fires once per scheduled reconnect attempt — before the attempt happens.
attempt: 1-based counter, reset to 1 after a successful reconnection.delayMs: actual delay before this attempt (after backoff + jitter).
fatal: true: the SDK has stopped and will not reconnect. Possible causes: invalid apiKey (close 4001/4002), protocol incompatibility, exhausted reconnect attempts (maxAttemptsreached). The next user action must bedisconnect()followed by a freshcreateClient(...).fatal: false: informational — typically a transient WebSocket-level error already being retried.
client.on('error', ({ message, fatal }) => { if (fatal) console.error('giving up:', message) else console.warn('transient:', message)})Data events
Section titled “Data events”| Event | Payload |
|---|---|
sportEvent:added | { sportEvent: SportEvent, receivedAt: number } |
sportEvent:updated | { sportEvent: SportEvent, receivedAt: number } |
sportEvent:removed | { bookmaker: Bookmaker, sportEventId: SportEventId, receivedAt: number } |
odds:changed | { bookmaker, sportEventId, marketId, selectionId, quote, receivedAt } |
receivedAt is Date.now() at the moment the SDK received the message — see Time semantics.
sportEvent:added
Section titled “sportEvent:added”Fires once when a sport event is first observed (per bookmaker). Also fires for each existing event during initial sync — see Snapshot vs events for the pattern to ignore initial-sync emissions.
client.on('sportEvent:added', ({ sportEvent }) => { console.log(`new: ${sportEvent.bookmaker} ${sportEvent.name}`)})sportEvent:updated
Section titled “sportEvent:updated”Fires when any field of a sport event changes — metadata, market list, or any odds value. The internal store is immutable, so a price tick produces a new instance reference. Treat the payload as a full replacement.
client.on('sportEvent:updated', ({ sportEvent }) => { // re-render the row keyed by sportEvent.id})sportEvent:removed
Section titled “sportEvent:removed”Fires when a sport event is no longer reported by its source (match ended, withdrawn, etc.). The entity itself is gone — the payload carries bookmaker and sportEventId so you can clean up references.
client.on('sportEvent:removed', ({ sportEventId }) => { cleanupRow(sportEventId)})odds:changed
Section titled “odds:changed”Fires per selection whose quote (or order book) changed. Always fires alongside a sportEvent:updated for the parent event — pick one based on what your code needs.
client.on('odds:changed', ({ bookmaker, sportEventId, marketId, selectionId, quote, // Quote — new top-of-book receivedAt}) => { // line-move detection, alerts, analytics})For CLOB sources, the new full order book is on the parent Selection.orderBook — re-read it via client.getSportEvent(sportEventId) if you need it.
Subscribe / unsubscribe
Section titled “Subscribe / unsubscribe”const onUpdated = ({ sportEvent }) => { /* … */ }
client.on('sportEvent:updated', onUpdated)
// later — must use the same reference:client.off('sportEvent:updated', onUpdated)Type-safe handlers
Section titled “Type-safe handlers”The ClientEventMap type drives type inference automatically — your handler parameter is correctly typed for the event you subscribed to:
client.on('odds:changed', payload => { payload.quote.price // typed as number payload.bookmaker // typed as Bookmaker})