Skip to main content

Streaming API (Socket.IO)

Real-time feeds use Socket.IO over WebSockets, on a different host from the REST API. The REST endpoints under https://api.4cx.io are not WebSocket endpoints.

Server

Authentication

You authenticate the socket connection with the same REST session token returned by Log in (data.user.auth). Pass it on the handshake — either as a query parameter or as the Authorization header. No Bearer prefix — the raw token only.
If the token is missing, invalid, or the account is closed, the handshake fails with Error: not authorized.

Namespaces

The server uses Socket.IO namespaces to separate feeds. Connect to a namespace by appending it to the host. <username> must be the username of the account whose token you’re using (not the email, not the ObjectId). The server enforces this — if the namespace username doesn’t match the token owner, the handshake is rejected.
All event payloads are stringified JSON. You must JSON.parse them in your handler. The server does this so the wire format is uniform across clients regardless of how their Socket.IO library serializes objects.

/priceUpdates events

orderUpdate

Emitted when a single side of a market changes — a new resting order, a fill, a cancel, or an edit. One emission per side that changed. Outer payload (after JSON.parse): Each sideOrders entry:

gameUpdate

Emitted when a game is first published, its market opens or closes, the start time changes, or odds across the full game are republished (e.g. by a seeding job). Payload includes: id, parentGameID, league, sport, start, ended, participants, awayMoneylines, homeMoneylines, awaySpreads, homeSpreads, over, under, mainHomeSpread, mainAwaySpread, mainTotal, and messageType (marketOpen | marketClosed) when present. Full payloads are large; ask your integration contact for a sample if you need the exact field set for a given league.

/v2/user/<username> events

This namespace emits exactly one event: positionUpdate. Every state change on one of your orders, and every fill that involves you (as offerer or taker), arrives as a positionUpdate.

Payload shape

Two payload objects do the heavy lifting:
  • unmatched — state of your resting offer. Fields: orderID, odds, offered (original size), filled (cumulative amount filled into this order), remaining (offered - filled). Present whenever your resting state changed.
  • matched — the fill that just occurred. Fields: txID (cross-reference with REST matched-play endpoints), filled (size of this specific fill), odds (always from your side — if you offered −105 you’ll see −105 here even though the counterparty saw +105). Present whenever a fill involving you just happened.
The origin field is a hint emitted by the server:
  • origin: "offer"unmatched is present (your resting offer changed in some way).
  • origin: "wager" — only matched is present, no unmatched (you took someone else’s resting liquidity).

How to tell what just happened

Use the table below in your handler. All checks are on the parsed positionUpdate payload.

Example handler

REST cross-reference

For looking up a txID (matched fills) or orderID (your resting state), see Look up single order. To list all of your current open offers in one call, use List my open orders.