docker run -it --rm --name sbg-tech-test-api -p 8888-8890:8888-8890 sbgtechtest/api
10K+
The API is combination of two services designed to provide a developer with enough realistic data to build a small sportsbook website.
The services are exposed as follows:
The API provides sportsbook data in the form of Events, Markets and Outcomes and hitting the base path will return a JSON object describing the available routes:
{
"routes": {
"football": {
"live": "/football/live"
},
"sportsbook": {
"event": "/sportsbook/event/:eventId",
"market": "/sportsbook/market/:marketId",
"outcome": "/sportsbook/outcome/:outcomeId"
}
}
}
The /football/live endpoint also accepts a query parameter primaryMarkets=true to also return the primary markets for each of the events. E.g. http://localhost:8888/football/live?primaryMarkets=true
API endpoints will typically return the entity requested in an object, keyed by the type of the entity. I.e. for an event response, the schema will look something like the below:
{
"event": {
"eventId": 12345
}
}
More complete examples of the API responses are shown at the end of this document.
The Websocket API allows developers to subscribe to realtime updates for markets and outcomes as well as retrieve event, market or outcome data.
Note that for requests for single entities, the WebSocket API returns the entities directly, i.e. the data is not nested inside
event,marketoroutcomeproperties
A connection is created as follows:
const w = new Websocket("ws://localhost:8889");
To receive updates from the Websocket, set up a listener in the standard way:
w.addEventListener("message", e => console.log(e.data)); // logs all data to console
Subscriptions and requests for data are handled by sending a stringified object over the Websocket.
There are a few different ways to get updates for events, markets and outcomes. Some examples of how to subscribe are shown below.
// Subscribe to all updates for an event, by default previous subscriptions are discarded
w.send(JSON.stringify({type: "subscribe", keys: ["e.21249934"]}));
// Subscribe to all updates for an event but keep any existing subscriptions
w.send(JSON.stringify({type: "subscribe", keys: ["e.21249934"], clearSubscription: false}));
// Subscribe to a specific market's updates (which includes any related outcomes
w.send(JSON.stringify({type: "subscribe", keys: ["m.93650821"]}));
// Subscribe to a specific outcome's updates - this is the most specific subscription
w.send(JSON.stringify({type: "subscribe", keys: ["o.367533685"]}));
// Subscribe to all market updates (irrespective of event)
w.send(JSON.stringify({type: "subscribe", keys: ["m.*"]}));
// Subscribe to all outcome updates (irrespective of event or market)
w.send(JSON.stringify({type: "subscribe", keys: ["o.*"]}));
When subscribing to e. keys (i.e. e.21249934), you will receive updates for any markets or outcomes that belong to the event.
When subscribing to m. keys (i.e. m.93650821), you will receive updates for that market and any outcomes which belong to it.
When subscribe to o. keys (i.e. o.367533685), you will receive updates for that outcome specifically.
It is possible to subscribe to all market updates (m.*) and all outcome updates(o.*), but there are a large number of these items in the catalogue and the updates may not be relevant to the data you are displaying on screen at the time.
Note the default behaviour is for all previous subscriptions to be cleared before subscribing to the supplied keys
// Unsubscribe from all keys previously subscribed to
w.send(JSON.stringify({ type: "unsubscribe" }));
// Unsubscribe from keys previously subscribed to
w.send(JSON.stringify({ type: "unsubscribe", keys: ["e.21249934"] }));
// Fetch event data
w.send(JSON.stringify({ type: "getEvent", id: 21249934 }));
// Fetch market data
w.send(JSON.stringify({ type: "getMarket", id: 93650821 }));
// Fetch outcome data
w.send(JSON.stringify({ type: "getOutcome", id: 367533685 }));
// Fetch live events
w.send(JSON.stringify({ type: "getLiveEvents" }));
// Fetch live events (and include primary market ID in event data)
w.send(JSON.stringify({ type: "getLiveEvents", primaryMarkets: true }));
The data returned by these requests does not contain related entities (as would be returned by the API). I.e. the event payload just contains the event data and does not include markets or outcomes.
docker run -it --rm --name sbg-tech-test-api -p 8888-8890:8888-8890 sbgtechtest/api:2.0.0
version: '3'
services:
api:
image:
sbgtechtest/api:latest
ports:
- "8888-8890:8888-8890"
A metrics server is included to help debug your work. Stats are recorded for key events and exposed on http://localhost:8890/metrics
{
"io.skybet.push": {
"unsubscribe": {
"mean": 0.0102846799407602,
"unit": "seconds",
"m15": 0.00101378934293258,
"count": 1,
"m1": 0.00421521269601561,
"m5": 0.00253193638199838,
"type": "meter"
},
"subscribedKeys": {
"count": 1,
"type": "counter"
},
"connectedClients": {
"type": "counter",
"count": 1
},
"subscribe": {
"m5": 0.00253193638199838,
"type": "meter",
"m1": 0.00421521269601561,
"unit": "seconds",
"count": 1,
"m15": 0.00101378934293258,
"mean": 0.0102846799407602
},
"incomingMessages": {
"m5": 0.00253193638199838,
"type": "meter",
"m1": 0.00421521269601561,
"unit": "seconds",
"m15": 0.00101378934293258,
"count": 1,
"mean": 0.0102846799407602
},
"outgoingMessages": {
"type": "meter",
"m5": 0.0630758994492022,
"m1": 0.227419715022405,
"m15": 0.0225123756752244,
"unit": "seconds",
"count": 21,
"mean": 0.215978278755965
},
"connectionMeter": {
"mean": 0.0102846799407602,
"m15": 0.00100817279588172,
"unit": "seconds",
"count": 1,
"m1": 0.00387818289744378,
"type": "meter",
"m5": 0.00249008715458779
}
},
"io.skybet.route": {
"match": {
"mean": 0.0514308049949598,
"unit": "seconds",
"count": 5,
"m15": 0.185000174790719,
"m1": 0.0601387636194611,
"m5": 0.158123992754695,
"type": "meter"
},
"noMatch": {
"m15": 0,
"unit": "seconds",
"count": 0,
"mean": 0,
"type": "meter",
"m5": 0,
"m1": 0
}
},
"io.skybet": {
"response": {
"type": "timer",
"duration": {
"type": "histogram",
"median": 0,
"p95": 3,
"std_dev": 1.30384048104053,
"count": 5,
"p99": 3,
"sum": 4,
"max": 3,
"p75": 2,
"min": 0,
"variance": 1.7,
"p999": 3,
"mean": 0.8
},
"rate": {
"m1": 0.0601387636194611,
"type": "meter",
"m5": 0.158123992754695,
"mean": 0.0514302759748609,
"count": 5,
"unit": "seconds",
"m15": 0.185000174790719
}
}
}
}
{
"event": {
"eventId": 21249939,
"name": "Shanghai Shenhua 0 v 0 Shandong Luneng Taishan",
"displayOrder": -1000,
"sort": "MTCH",
"linkedEventId": 21228740,
"classId": 5,
"className": "Football",
"typeId": 10003971,
"typeName": "Football Live",
"linkedEventTypeId": 10005942,
"linkedEventTypeName": "Chinese Super League",
"startTime": "2017-09-19T11:35:23.000Z",
"scores": { "home": 0, "away": 0 },
"competitors": [
{ "name": "Shanghai Shenhua", "position": "home" },
{ "name": "Shandong Luneng Taishan", "position": "away" }
],
"status": {
"active": true,
"started": true,
"live": true,
"resulted": false,
"finished": false,
"cashoutable": true,
"displayable": true,
"suspended": false,
"requestabet": false
},
"boostCount": 0,
"superBoostCount": 0,
"markets": [93649849, 93649179, 93649150, 93649398, 93649188]
}
}
{
"market": {
"marketId": 93649179,
"eventId": 21249939,
"name": "Both Teams To Score",
"displayOrder": -32499,
"type": "standard",
"status": {
"active": true,
"resulted": false,
"cashoutable": true,
"displayable": true,
"suspended": false,
"noExtraTime": false,
"live": true
},
"liabilities": { "livePriceLimit": 2500 },
"spAvail": false,
"outcomes": [367528211, 367528215]
}
}
{
"outcome": {
"outcomeId": 367528215,
"marketId": 93649179,
"eventId": 21249939,
"name": "No",
"displayOrder": 20,
"result": { "place": 0, "result": "-", "favourite": false },
"linkedOutcomeId": 366480090,
"price": { "den": 7, "num": 1, "decimal": 1.1428571428571428 },
"status": {
"active": true,
"resulted": false,
"cashoutable": true,
"displayable": true,
"suspended": false,
"result": "-"
}
}
}
Content type
Image
Digest
Size
55.4 MB
Last updated
over 7 years ago
docker pull sbgtechtest/api