Real-time(Socket.IO) Integration
Getting started
Real-time push updates are available via Socket.IO. Subscribe to live events, live odds, and sport-wide feeds without polling. This page provides complete integration examples for all major frameworks.
/ws-token endpoint. This token is only available to MEGA plan subscribers. See the Token Authentication section below.https://live.matchstat.comRapid HOST:
tennis-api-atp-wta-itf.p.rapidapi.com tennis-live-api.p.rapidapi.comNote: Use the RapidAPI host corresponding to the product for which you purchased the Mega plan.
Why Token ? --> RapidAPI doesn't natively support WebSocket authentication, so we use this token-based system to verify MEGA plan access.
Tennis Live API WebSocket â Events Reference
This page is the single source of truth for every event exchanged over the Tennis Live API WebSocket connection. It is language-agnostic: once you have an authenticated socket connection open (see the Quick Start / language-specific integration guides), use this table to know what to emit, what to listen for, and what shape to expect back â without needing a separate code sample per language for every event.
Connect using the Quick Start snippet for your language, then simply emit/on the event names above. Every language-specific integration guide (React/Next.js, C#/.NET, etc.) points back to this page instead of re-documenting payload shapes, so this table is the only place that needs updating when the event contract changes.
Connection Lifecycle Events
These fire automatically as part of the underlying socket connection and don't need to be joined or left explicitly.
| Event | Direction | Payload | Description |
|---|---|---|---|
connect | Server â Client | â | Fired once the socket has connected and the token was accepted. The connection ID is the client-side property socket.id; the server sends no payload. |
disconnect | Server â Client | reason: string | Fired when the socket disconnects. reason is the standard Socket.IO reason, passed through unchanged (e.g. transport close, ping timeout, io server disconnect, io client disconnect). |
connect_error | Server â Client | { message: string } | Fired when the handshake is rejected. The error carries only message, one of:
|
ping-server / pong-server | Client â Server / Server â Client | â | Optional application-level heartbeat: emit ping-server, the server answers pong-server. |
Single-Event Subscription (Live Score & Odds)
Used when a client wants live updates for one specific match/event.
| Event | Direction | Payload | Description |
|---|---|---|---|
join-event | Client â Server | eventId: number | Subscribes the socket to updates for one live event (the live id from /events/live). Fire-and-forget: the server sends no acknowledgement or confirmation event. Join only events whose status is InPlay â that check is done by your client; it is not part of the payload. |
leave-event | Client â Server | eventId: number | Unsubscribes from that event. Fire-and-forget (no acknowledgement). Call it on cleanup. |
event-update | Server â Client | The full live event row (same fields as one item of GET /events/live) | Sent when the event changes while InPlay (point, game, set, status). The server is shown by indicator ("1,0" = player 1 serving); set scores are in score (comma-separated sets). |
odds-update | Server â Client | { results: { "Full Time Result": { od1, od1Bookmaker, od2, od2Bookmaker, odx, odxBookmaker, line, updatedAt } } } | Sent when new odds arrive for the event: the best match-winner price per outcome across bookmakers (same shape as GET /event/odds/best/{eventId}). Odds are decimal strings; updatedAt is Unix seconds. The payload does not include the event ID: see the note below. |
// event-update (real payload shape)
{
"id": "4071379",
"name": "Asahi Harazaki vs Jonah Braswell",
"participant1": "Asahi Harazaki",
"participant2": "Jonah Braswell",
"league": "M15 Fayetteville",
"score": "6-4,0-0",
"status": "InPlay",
"points": "40-40",
"indicator": "1,0",
"player1": { "name": "Asahi Harazaki" },
"player2": { "name": "Jonah Braswell" },
"tournament": { "name": "M15 Fayetteville" },
"tourType": "atp",
"startTimestamp": 1790776800,
"matchId": "92049-94972-22090-4"
}
// odds-update (real payload shape)
{
"results": {
"Full Time Result": {
"od1": "1.72", "od1Bookmaker": "Pinnacle",
"od2": "2.25", "od2Bookmaker": "Bet365",
"odx": null, "odxBookmaker": null,
"line": null,
"updatedAt": 1790777402
}
}
}Field meanings are the same as in REST: see Live Events (event fields) and Best Live Odds(odds fields). The event's matchId equals the liveMatchId of the same match in Upcoming Matches rows, and GET /matches/{matchId}/live returns its live eventId.
Rejoin after every reconnect. Subscriptions (rooms) belong to one connection. When the connection drops and Socket.IO reconnects, the server has forgotten them: emit join-event / join-live-events-all again on every connect. A disconnect started by the server (io server disconnect) is not retried by Socket.IO itself: call socket.connect().
Attributing odds. event-update carries the event id, so it can be routed to the right match. odds-update does not: on a connection that follows several events, an odds payload cannot be matched to its event. Follow one event per connection for odds, or poll GET /event/odds/best/{eventId} for each match.
The integration guides below implement both (one shared connection, rejoin on connect, per-event subscriber counts, no retry on plan or token errors).
All-Matches Subscription
Used when a client wants a single feed covering every in-play match for a sport, rather than subscribing per match.
| Event | Direction | Payload | Description |
|---|---|---|---|
join-live-events-all | Client â Server | The plain string "tennis", e.g. socket.emit("join-live-events-all", "tennis"). Not an object: {"sportSlug":"tennis"} is ignored with no error. | Subscribes the socket to the feed of every live tennis match (ATP, WTA, Challenger and ITF are all inside it; tour is in each item's tourType). Fire-and-forget: there is no acknowledgement; the first live-events-all-update snapshot arrives about 2 seconds after joining and serves as the initial state. |
leave-live-events-all | Client â Server | sportSlug: string | Unsubscribes from the combined feed. Always call this on cleanup/disposal. |
live-events-all-update | Server â Client | { count: number, results: LiveEvent[] } | A full snapshot of all live events (each item = one /events/live row), sent on every live refresh. Not a diff: replace your list with results. |