Matches
Keep in mind that for legacy reasons Match
entity has both _id
and id
property . While reading rest of this page, take notice of the different spelling, if request param will be described as /api/match/:id
, you must use id
property, if /api/match/:_id
, then _id
.
Listing matches
Matches can be listed on /api/match
endpoint:
[
{
"_id": "O3twsvpFriCqHYbn",
"id": "ec1362cf-cde5-4667-b46c-1b532fd3e4f0",
"current": false,
"left": {
"id": "UyfhxQ3AtoCoGIEe",
"wins": 0
},
"right": {
"id": "8nz9GXabr3tUUf0W",
"wins": 0
},
"matchType": "bo3", // Possible values: bo1, bo2, bo3, bo5, bo7, bo9
"vetos": [
{
"teamId": "UyfhxQ3AtoCoGIEe",
"mapName": "de_mirage",
"side": "NO",
"score": { // Optional. This contains information about given map score
"UyfhxQ3AtoCoGIEe": 13,
"8nz9GXabr3tUUf0W": 16
},
"type": "pick", // Possible values: pick, ban, decider
"mapEnd": true
},
{
"teamId": "",
"mapName": "",
"side": "NO",
"type": "pick",
"mapEnd": false
},
...
],
"startTime": 0,
"game": "cs2"
}
]
Additionally, each veto entry can have rounds
property. It gets automatically filled by LHM after every round, and possess information about per-round statistics for every player. It looks like this:
...
"vetos": [
{
"teamId": "UyfhxQ3AtoCoGIEe",
"mapName": "de_mirage",
"side": "NO",
"score": {
"UyfhxQ3AtoCoGIEe": 0,
"8nz9GXabr3tUUf0W": 1
},
"type": "pick",
"mapEnd": false,
"rounds": [
{
"round": 1,
"win_type": "elimination", // Possible values: elimination, defuse, time, bomb,
"winner": "CT",
"players": { // Record with SteamID64 as keys, and per-round stats object for given player as value
"768XXXX": {
"kills": 0,
"killshs": 0,
"damage": 0,
"assists": 0,
"deaths": 0,
}
}
}
]
}
],
...
Last payload
In Counter-Strike, right when the final round finishes and LHM marks map with "mapEnd":true
property, last GSI payload is also attached to the veto with game
property. This is not raw GSI that comes from the Counter-Strike data provider, but a result of parsing with csgogsi
package. To actually read this property while listing all matches, you must add ?full
query to the request path. This field is automatically added when fetching current Match, or by its id
.
Fetching current match
Each match has current
bool property, which tells HUDs which meta-data (team names / logos) to pull. Only one match can be active at the same time, and can be easily fetched with:
{
"_id": "O3twsvpFriCqHYbn",
"id": "ec1362cf-cde5-4667-b46c-1b532fd3e4f0",
"current": false,
"left": {
"id": "UyfhxQ3AtoCoGIEe",
"wins": 0
},
"right": {
"id": "8nz9GXabr3tUUf0W",
"wins": 0
},
"matchType": "bo3", // Possible values: bo1, bo2, bo3, bo5, bo7, bo9
"vetos": [
{
"teamId": "UyfhxQ3AtoCoGIEe",
"mapName": "de_mirage",
"side": "NO",
"score": { // Optional. This contains information about series score
"UyfhxQ3AtoCoGIEe": 0,
"8nz9GXabr3tUUf0W": 1
},
"type": "pick", // Possible values: pick, ban, decider
"mapEnd": false
},
{
"teamId": "",
"mapName": "",
"side": "NO",
"type": "pick",
"mapEnd": false
},
...
],
"startTime": 0,
"game": "cs2"
}
If no match is set as active, this endpoint returns 404.
Fetching single match
It is possible to fetch single match by doing:
GET /api/match/:id
Toggling active match
Match can have its current
state toggled by doing:
POST /api/match/current/:id
Match Creation
To create Match Entity, you must send a POST to /api/match
with proper payload. This payload differs based on a game. For all games beside Apex Legends, it must look like this:
{
"id": "", // Must be empty
"current": false,
"left": { "id": null, "wins": 0 },
"right": { "id": null, "wins": 0 },
"matchType": "bo1", // or any other BO. Supported BOs are: bo1, bo2, bo3, bo5, bo7, bo9
"vetos": [Fully Filled Veto, must have 9 elements],
"startTime": 0
}
If the match is for Apex Legends, use the schema below:
{
"id": "",
"name": "",
"current": false,
"teams": [Fully Filled Veto, must have 9 elements],
"matchType": "multiteam",
"vetos": [],
"startTime": 0,
"game": "apexlegends"
}
Each Match must have fully filled Veto - an array of 9 Veto objects (even if BO is not specified BO1!), which structure depends on the game.
For Counter-Strike, Veto's structure looks like this:
{
"teamId": "",
"mapName": "",
"side": "NO",
"type": "pick",
"mapEnd": false,
"reverseSide": false /
}
Field | Description |
---|---|
teamId | Required, can empty - ID of a team |
mapName | Required - Name of the map (ex. "de_mirage" ) |
side | Required - "NO" , "CT" or "T" - whether an opponent of team with teamId has picked a starting side |
type | Required - "pick" , "ban" or "decider" |
mapEnd | Required - Indicate whether map has finished. Setting this to true will prevent LHM from trying to update statistics. |
reverseSide | Whether game assigned Teams to have different orientation than left / right setup in the base Match fields. Optional field, can be undefined |
While for the rest of games:
{
"mapEnd": false,
"reverseSide": false
}
Field | Description |
---|---|
mapEnd | Required - Indicate whether map has finished. Setting this to true will prevent LHM from trying to update statistics. |
reverseSide | Whether game assigned Teams to have different orientation than left / right setup in the base Match fields. Optional field, can be undefined |
Updating a Match
Updating a Match works in form of full payload replacement, so any fields missing from the request body will be missing, and Match will be corrupted as a result. To make sure you do not miss any fields, it's recommended to firstly fetch a Match, to get full payload, with the game
property, then transforming the response, and send it back with a request:
PATCH /api/match/:id
Switching sides
You can switch sides of the teams in the currently active Match programatically by doing:
POST /api/match/reverse
Keep in mind that there are limitations and behaviours that might apply when triggering the switch.