Integration reference · v1

scoreClientSocket

The public edge of the live-score platform. Third-party integrators connect here — never directly to the internal provider — for scorecard/iframe lookups over REST and live push updates over a SignalR socket.

Agent key required 5 req/s per IP REST + WebSocket Soccer Tennis Cricket Golf

Authentication

Every request — REST or socket — needs a valid, unexpired agent key. Ask the platform owner for one; each key can optionally be locked to specific caller IPs.

How to send it

Call typeTransportExample
REST APIHTTP header X-AppX-App: <your-key>
REST API (alt.)Query string?key=<your-key>
Socket connectionQuery string on the hub URL — required, headers don't reach itwss://host/clientScore?key=<your-key>

The socket needs the query string because a browser's native WebSocket upgrade can't carry custom headers — only the initial SignalR "negotiate" call could use one, and the upgrade after it would then fail auth. ?key= works for both legs.

Failure responses

StatusMessageCause
401Agent key required.No key present, header or query string
401Invalid agent key.Key doesn't match any configured agent
401Agent '<name>' key has expired on <date>.Past the key's expiry date
403IP '<ip>' is not whitelisted for agent '<name>'.Key has an IP allowlist and yours isn't on it

Rejection body shape

{ "success": false, "data": null, "message": "...", "status": 401 }

Testing in Swagger? Click Authorize and paste your key once — it's attached to every "Try it out" call automatically.

REST API

All routes are prefixed with /api. Every route below shares the auth rules above, a 5 req/s per-IP rate limit, and open CORS unless the deployment restricts it.

Scorecard & iframe

GET/api/Scorecardalias /api/bfrateScoreborad

Cached scorecard widget URL for an event.

Query params

ParamTypeRequiredNotes
eventIdstringyes
linkintno · default 0scorecard variant/link id
pidintno · default 0provider id
colorstringnoappended to the URL as &color=
fontstringnoappended to the URL as &font=

Response

{
  "EventID": 12345,
  "scoreUrl": "https://.../scoreboard?id=12345&color=000000",
  "streamingUrl": "https://..."
}

Operational

Monitoring endpoints — connection counts, daily stats, instance lifecycle. Not needed for a typical score integration.

GET /api/ConnectionCount GET /api/ConnectionStats GET /api/InstanceStats GET /api/ip (diagnostic)

Real-time socket

A SignalR hub at /clientScore pushes score updates the moment they change — no polling needed on your side.

Connect

const connection = new signalR.HubConnectionBuilder()
  .withUrl(`wss://<host>/clientScore?key=${AGENT_KEY}`)
  .withAutomaticReconnect()
  .build();

connection.on('Score', (fullScore) => { /* §Score payloads */ });
connection.on('ShortScore', (shortScore) => { /* §Score payloads */ });

await connection.start();
connection.invoke('getscore', '30123456');
connection.invoke('getShortScore', '30123456');

Client → server methods

MethodArgsEffect
getscore"123,456"Subscribe to full-score updates. Sends the cached Score immediately if present, then every future update.
disconnectscoreevent id(s)Unsubscribe from full-score updates.
getShortScoreevent id(s)Same as getscore, for the ShortScore stream.
disconnectShortScoreevent id(s)Unsubscribe from short-score updates.
getupdateScoreevent id(s)Heartbeat — keeps the event active server-side. See below.
PingnoneReplies with Pong. Liveness check.

Server → client events

EventPayloadWhen
Scorefull score objectOn getscore (cache hit), then every live update
ShortScoreshort score objectOn getShortScore (cache hit), then every live update
PongnoneReply to your Ping

Heartbeat & reconnection

Call getupdateScore on an interval well under 90 seconds for every event you're watching. The server only keeps polling events with recent client interest — an event goes idle 90s after its last getscore/getupdateScore/getShortScore call. score-webapp uses a 15s interval.

Use .withAutomaticReconnect(). Subscriptions are per-connection — on reconnect, re-issue getscore/getShortScore for every event you still care about. There's no explicit "connected" event; a resolved connection.start() is your signal.

Score payloads

scoredata (the Score event) and shortscoredata (ShortScore) are relayed byte-for-byte from the upstream provider.

Keys are abbreviated, not the "nice" names. The live socket push serializes raw C# member names — na, sc, hts, eid, etid, gsq, isrv — never the expanded name / score / halfTimeScore aliases you might expect from a Betfair-flavored API. The tables below are your field glossary.

eventTypeId (etid / eti) → sport

ValueSport
1Soccer
2Tennis
3Golf
4Cricket

Score event — base fields

FieldTypeMeaning
etidintevent type id (sport)
eidintevent id
scobjectscore object — sc.hm home, sc.aw away (table below)
ststringstatus
msstringmatch status
teintSoccer match clock, seconds
ertintSoccer elapsed regular time
fteobject{ h, m, s } full time elapsed
csetintTennis current set number
hsboolTennis "has sets" flag
udarrayupdate log: {ut, uid, mt, ert, ty, uty, team, tname}

sc.hm / sc.aw — per side

FieldTypeMeaningSport
nastringnameall
scstringscore (goals / points)all
htsstringhalf-time scoreSoccer
ftcstringfull-time scoreSoccer
pes / peseqstring / arraypenalties score / sequence (omitted when empty)Soccer
games / setsstringgames in set / sets wonTennis
gsqarray<string>point-by-point game sequenceTennis
isrvbool?currently servingTennis
sbrint?service breaksTennis
nyfc / nrfc / nfcintyellow / red / total cards (omitted at 0)Soccer
nfco / nfcofh / nfcoshintcorners — total / 1st half / 2nd half (omitted at 0)Soccer
bpintbooking points (omitted at 0)Soccer
in1 / in2object{rn, wi, ov} runs/wickets/overs, innings 1 & 2Cricket

† Cricket doesn't get a Score event today. The model has cricket fields, but the live pipeline never populates or broadcasts Score for cricket — that sport's data arrives through a separate feed that only produces ShortScore. If you're integrating cricket, subscribe to ShortScore only.

ShortScore event — fields

No key aliasing here — these are the actual wire names.

FieldTypeMeaning
etiintevent type id (sport)
eidstringevent id
enstringevent name, e.g. "Team A v Team B"
te1n / te2nstringteam/player 1 & 2 names
t1s / t2sstringteam/player 1 & 2 scores
ptintperiod/time — meaning depends on sport (omitted at 0)
t1set / t2setstringsets won Tennis
t1p / t2pstringpoints/games Tennis
currBattingstringteam currently batting Cricket
currBattingTeamScorestringbatting team's current score Cricket

Per sport

Sportt1s/t2sptSets/pointscurrBatting*Source
Soccergoalsmatch clock (s)derived from Score
Tennisgames in setcurrent set #setderived from Score
Cricketnot populated this waypopulatedindependent live feed
Golfno short score produced

Soccer and tennis short scores are a summarized view of the same Score payload. Cricket short scores come from an independent feed whose messages already arrive pre-shaped this way — which is why currBatting* is only ever populated there.

Sample payloads

Soccer — Score

{
  "etid": 1, "eid": 30123456, "st": "IN_PLAY", "ms": "1st Half", "te": 1523, "ert": 1523,
  "fte": { "h": 0, "m": 25, "s": 23 },
  "sc": {
    "hm": { "na": "Team A", "sc": "1", "hts": "0", "ftc": "0", "nyfc": 2, "nfco": 3 },
    "aw": { "na": "Team B", "sc": "0", "hts": "0", "ftc": "0" }
  }
}

Soccer — ShortScore

{ "eti": 1, "eid": "30123456", "en": "Team A v Team B", "te1n": "Team A", "te2n": "Team B", "t1s": "1", "t2s": "0", "pt": 1523 }

Tennis — Score

{
  "etid": 2, "eid": 30234567, "cset": 2, "hs": true,
  "sc": {
    "hm": { "na": "Player A", "sc": "30", "games": "3", "sets": "1", "isrv": true, "gsq": ["15-0","15-15","30-15"] },
    "aw": { "na": "Player B", "sc": "15", "games": "2", "sets": "0", "isrv": false }
  }
}

Tennis — ShortScore

{ "eti": 2, "eid": "30234567", "en": "Player A v Player B", "te1n": "Player A", "te2n": "Player B", "t1s": "3", "t2s": "2", "pt": 2, "t1set": "1", "t2set": "0", "t1p": "30", "t2p": "15" }

Cricket — ShortScore (values illustrative — exact shape is whatever the feed sends)

{ "eti": 4, "eid": "30345678", "en": "Team A v Team B", "te1n": "Team A", "te2n": "Team B", "t1s": "156/4 (18.2)", "t2s": "", "currBatting": "Team A", "currBattingTeamScore": "156/4" }

No Score event for cricket — see the callout above.

Quick-start checklist

  1. Get an agent key — and if you need IP restriction, share the IPs your backend calls from.
  2. REST: send X-App: <key> (or ?key=) on every /api/* call.
  3. Socket: connect to wss://<host>/clientScore?key=<key>.
  4. Call getscore and/or getShortScore for each event you want.
  5. Re-call getupdateScore at least every ~60–90s per event to keep it active.
  6. Handle Score/ShortScore — remember cricket only ever sends ShortScore.
  7. On reconnect, re-subscribe — the server doesn't remember your subscriptions across a dropped connection.