Game Servers API
Complete reference for creating matches, getting server data, and managing match lifecycle
Overview
The Game Servers API lets you create ephemeral matches, get live server data, and cancel running matches. All endpoints are organization-scoped.
SweatHost uses an ephemeral server model — a single call creates the server, allocates a pod, and starts the game. The server auto-destroys when the match ends.
Scope
All endpoints are organization-scoped. You only see and manage servers owned by your organization.
createMatch()
Create an ephemeral match. This single call creates a server, allocates a pod from the fleet, and applies game configuration via RCON.
HTTP API
| Method | Path | Description |
|---|---|---|
POST | /api/v1/matches | Create match |
Headers: Authorization: Bearer <your-api-key>, Content-Type: application/json
Request body
| Field | Type | Required | Description |
|---|---|---|---|
region | string | Yes | Region code (e.g. us-west-1). |
gameType | string | Yes | e.g. cs2. |
callbackUrl | string | No | URL to POST match lifecycle events to. |
callbackAuthToken | string | No | Token sent as Authorization header in webhook callbacks. |
externalMatchId | string | No | Your correlation ID, returned in all callbacks. |
gameSettings | Cs2GameSettings | Yes | Game-specific settings. |
Game settings (Cs2GameSettings)
| Field | Type | Required | Description |
|---|---|---|---|
matchType | string | Yes | competitive, casual, deathmatch, wingman, retakes, custom. |
map | string | Yes | Starting map (e.g. de_dust2). |
maps | string[] | No | Additional map pool. |
seriesFormat | string | No | bo1, bo3, bo5 — competitive/wingman only. |
teams | TeamsConfig | No | Team config — competitive/wingman only. |
players | string[] | No | Steam ID 64s — deathmatch only. |
serverPassword | string | No | Server password for players to connect. |
dmSubMode | string | No | ffa or team — deathmatch only. |
dmRoundMinutes | number | No | Round duration in minutes (min: 1) — deathmatch only. |
freezeTime | number | No | Freeze time in seconds (min: 0). |
maxRounds | number | No | Max rounds (min: 1). |
customCvars | string | No | Raw CVar lines. |
Validation
players and teams cannot be set at the same time. players is only valid for deathmatch. teams is only valid for competitive or wingman.
TeamsConfig shape:
{
team1: { name: string; players: string[] }, // Steam ID 64s
team2: { name: string; players: string[] },
}Example (cURL)
curl -X POST "https://api.sweathost.com/api/v1/matches" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"region": "us-west-1",
"gameType": "cs2",
"callbackUrl": "https://example.com/webhooks/match",
"callbackAuthToken": "Bearer my-secret-token",
"externalMatchId": "my-tournament-match-42",
"gameSettings": {
"matchType": "competitive",
"map": "de_dust2",
"seriesFormat": "bo1",
"teams": {
"team1": { "name": "Alpha", "players": ["76561198000000001", "76561198000000002"] },
"team2": { "name": "Beta", "players": ["76561198000000003", "76561198000000004"] }
}
}
}'SDK
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
dto | CreateMatchRequest | Yes | Match creation payload. |
options | RequestOptions | No | Optional request config. |
Return type: Promise<MatchServer>
Example (competitive with teams)
const match = await client.matches.create({
region: 'us-west-1',
gameType: 'cs2',
callbackUrl: 'https://example.com/webhooks/match',
callbackAuthToken: 'Bearer my-secret-token',
externalMatchId: 'my-tournament-match-42',
gameSettings: {
matchType: 'competitive',
map: 'de_dust2',
maps: ['de_dust2', 'de_mirage', 'de_inferno'],
seriesFormat: 'bo3',
teams: {
team1: { name: 'Alpha', players: ['76561198000000001', '76561198000000002'] },
team2: { name: 'Beta', players: ['76561198000000003', '76561198000000004'] },
},
},
});
console.log(`Server: ${match.serverId}`);
console.log(`Connect: ${match.ip}:${match.port}`);Example (deathmatch with player list)
const match = await client.matches.create({
region: 'us-west-1',
gameType: 'cs2',
callbackUrl: 'https://example.com/webhooks/match',
callbackAuthToken: 'Bearer my-secret-token',
externalMatchId: 'dm-lobby-99',
gameSettings: {
matchType: 'deathmatch',
map: 'de_dust2',
dmSubMode: 'ffa',
dmRoundMinutes: 10,
players: ['76561198000000001', '76561198000000002', '76561198000000003'],
},
});Response structure
MatchServer:
| Field | Type | Description |
|---|---|---|
serverId | string | Unique server ID. |
gameId | string | Session UUID. |
region | string | Region code. |
status | string | allocating → running. |
ip | string | null | Public IP (available once running). |
port | number | null | Game port (available once running). |
callbackUrl | string | null | Your callback URL. |
externalMatchId | string | null | Your correlation ID. |
gameType | string | e.g. cs2. |
createdAt | string | ISO 8601. |
rconPassword | string | null | RCON password. |
Match features
When players or teams is provided:
| Feature | Behavior |
|---|---|
| Whitelist | Only listed players can connect. Unauthorized players are kicked immediately. |
| Auto-start | Game stays in warmup until every listed player has joined. Competitive/wingman: MatchZy force-readies all players. Deathmatch: warmup ends, round restarts, stats begin. |
| Auto-shutdown | Server is destroyed immediately after the match ends. |
Callback events
When callbackUrl is set, the API sends a single POST to your URL when the match ends or is canceled. Only one match_over callback is sent per match. If callbackAuthToken was provided, it is sent as the Authorization header so your endpoint can verify authenticity.
The callback includes full per-player stats. For competitive Bo3/Bo5, each map has its own player stats. You can also fetch this data at any time via getMatchByExternalId().
match_over (competitive/wingman):
{
"eventType": "match_over",
"gameId": "cs2",
"externalMatchId": "my-tournament-match-42",
"serverId": "uuid",
"sessionId": "uuid",
"timestamp": "2026-03-12T11:00:00.000Z",
"result": {
"gameMode": "competitive",
"format": "bo3",
"winner": "team1",
"team1": { "name": "Alpha", "seriesScore": 2 },
"team2": { "name": "Beta", "seriesScore": 1 },
"maps": [
{
"mapName": "de_dust2",
"mapNumber": 1,
"team1Score": 13,
"team2Score": 7,
"winner": "team1",
"duration": 1800,
"players": [
{
"steamId": "76561198000000001",
"name": "Player1",
"team": "team1",
"kills": 25, "deaths": 15, "assists": 5,
"headshots": 12, "hsPercent": 48.0,
"kdRatio": 1.67, "adr": 85.3,
"damageDealt": 1706, "utilityDamage": 120,
"flashAssists": 3, "firstKills": 4, "firstDeaths": 2,
"entryKills": 3, "tradeKills": 2,
"bombPlants": 1, "bombDefuses": 0,
"clutchWins": 1, "roundsPlayed": 20, "mvps": 5,
"kastPercent": 72.0, "impactRating": 1.45
}
]
}
]
}
}match_over (deathmatch):
{
"eventType": "match_over",
"gameId": "cs2",
"externalMatchId": "dm-lobby-99",
"serverId": "uuid",
"sessionId": "uuid",
"timestamp": "2026-03-12T11:00:00.000Z",
"result": {
"gameMode": "deathmatch",
"map": "de_dust2",
"duration": 600,
"winnerSteamId": "76561198000000001",
"players": [
{
"steamId": "76561198000000001",
"name": "Player1",
"kills": 45, "deaths": 20, "assists": 3,
"headshots": 22, "hsPercent": 48.9,
"kdRatio": 2.25, "damageDealt": 5400, "kpm": 4.5
}
]
}
}match_canceled:
{
"eventType": "match_canceled",
"gameId": "cs2",
"externalMatchId": "my-tournament-match-42",
"serverId": "uuid",
"sessionId": "uuid",
"timestamp": "2026-03-12T11:05:00.000Z",
"reason": "canceled_by_user"
}See the API reference for a full breakdown of all callback fields and player stats.
Callback delivery
Callbacks are fire-and-forget with 1 retry on failure (10s timeout per attempt). Your endpoint should return 2xx to acknowledge receipt. You can also fetch the same result via getMatchByExternalId().
getMatchByExternalId()
Get the match result using your externalMatchId. Returns the same enriched structure as the match_over webhook.
HTTP API
| Method | Path | Description |
|---|---|---|
GET | /api/v1/matches/:externalMatchId | Get match by external ID |
SDK
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
externalMatchId | string | Yes | Your correlation ID from match creation. |
options | RequestOptions | No | Optional request config. |
Return type: Promise<{ externalMatchId, serverId, status, region, createdAt, result }>
The result field is null while the match is in progress and contains the full match result once finished (same structure as the match_over callback).
Example
const match = await client.matches.getByExternalId('my-tournament-match-42');
if (match.result && match.result.gameMode === 'competitive') {
console.log(`Winner: ${match.result.winner}`);
console.log(`Series: ${match.result.team1.seriesScore}-${match.result.team2.seriesScore}`);
for (const map of match.result.maps) {
console.log(` ${map.mapName}: ${map.team1Score}-${map.team2Score}`);
for (const p of map.players) {
console.log(` ${p.name} (${p.team}): ${p.kills}/${p.deaths}/${p.assists} ADR:${p.adr}`);
}
}
}getServer()
Get a server with live match data.
HTTP API
| Method | Path | Description |
|---|---|---|
GET | /api/v1/servers/:id | Get server with live data |
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Server ID. |
SDK
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Server ID. |
options | RequestOptions | No | Optional request config. |
Return type: Promise<MatchServerDetail>
Example
const server = await client.servers.get('server-id');
console.log(`Status: ${server.status}`);
console.log(`Connect: ${server.ip}:${server.port}`);cancelMatch()
Cancel a running match and destroy the server. Fires a match_canceled callback if callbackUrl was set.
HTTP API
| Method | Path | Description |
|---|---|---|
POST | /api/v1/servers/:id/cancel | Cancel match |
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Server ID. |
SDK
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Server ID. |
options | RequestOptions | No | Optional request config. |
Return type: Promise<{ ok: true }>
Example
await client.servers.cancel('server-id');Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS | Invalid request body or query. |
| 401 | UNAUTHORIZED | Invalid or missing API key. |
| 403 | FORBIDDEN | No access to this server. |
| 404 | NOT_FOUND | Server not found. |