SweatHost
SDK Reference

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

MethodPathDescription
POST/api/v1/matchesCreate match

Headers: Authorization: Bearer <your-api-key>, Content-Type: application/json

Request body

FieldTypeRequiredDescription
regionstringYesRegion code (e.g. us-west-1).
gameTypestringYese.g. cs2.
callbackUrlstringNoURL to POST match lifecycle events to.
callbackAuthTokenstringNoToken sent as Authorization header in webhook callbacks.
externalMatchIdstringNoYour correlation ID, returned in all callbacks.
gameSettingsCs2GameSettingsYesGame-specific settings.

Game settings (Cs2GameSettings)

FieldTypeRequiredDescription
matchTypestringYescompetitive, casual, deathmatch, wingman, retakes, custom.
mapstringYesStarting map (e.g. de_dust2).
mapsstring[]NoAdditional map pool.
seriesFormatstringNobo1, bo3, bo5 — competitive/wingman only.
teamsTeamsConfigNoTeam config — competitive/wingman only.
playersstring[]NoSteam ID 64s — deathmatch only.
serverPasswordstringNoServer password for players to connect.
dmSubModestringNoffa or team — deathmatch only.
dmRoundMinutesnumberNoRound duration in minutes (min: 1) — deathmatch only.
freezeTimenumberNoFreeze time in seconds (min: 0).
maxRoundsnumberNoMax rounds (min: 1).
customCvarsstringNoRaw 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

ParameterTypeRequiredDescription
dtoCreateMatchRequestYesMatch creation payload.
optionsRequestOptionsNoOptional 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:

FieldTypeDescription
serverIdstringUnique server ID.
gameIdstringSession UUID.
regionstringRegion code.
statusstringallocatingrunning.
ipstring | nullPublic IP (available once running).
portnumber | nullGame port (available once running).
callbackUrlstring | nullYour callback URL.
externalMatchIdstring | nullYour correlation ID.
gameTypestringe.g. cs2.
createdAtstringISO 8601.
rconPasswordstring | nullRCON password.

Match features

When players or teams is provided:

FeatureBehavior
WhitelistOnly listed players can connect. Unauthorized players are kicked immediately.
Auto-startGame stays in warmup until every listed player has joined. Competitive/wingman: MatchZy force-readies all players. Deathmatch: warmup ends, round restarts, stats begin.
Auto-shutdownServer 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

MethodPathDescription
GET/api/v1/matches/:externalMatchIdGet match by external ID

SDK

Parameters

ParameterTypeRequiredDescription
externalMatchIdstringYesYour correlation ID from match creation.
optionsRequestOptionsNoOptional 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

MethodPathDescription
GET/api/v1/servers/:idGet server with live data

Path parameters

ParameterTypeRequiredDescription
idstringYesServer ID.

SDK

Parameters

ParameterTypeRequiredDescription
idstringYesServer ID.
optionsRequestOptionsNoOptional 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

MethodPathDescription
POST/api/v1/servers/:id/cancelCancel match

Path parameters

ParameterTypeRequiredDescription
idstringYesServer ID.

SDK

Parameters

ParameterTypeRequiredDescription
idstringYesServer ID.
optionsRequestOptionsNoOptional request config.

Return type: Promise<{ ok: true }>

Example

await client.servers.cancel('server-id');

Errors

HTTPCodeDescription
400INVALID_PARAMSInvalid request body or query.
401UNAUTHORIZEDInvalid or missing API key.
403FORBIDDENNo access to this server.
404NOT_FOUNDServer not found.

On this page