01 Overview
Two references in one: the RCON HTTP API (everything under /v1, one bearer token) and the ServerSettings.ini config the server reads at startup.
Servers vary in what they enable. GET /v1/capabilities lists what a given one supports, so check there rather than assume.
Building with an AI assistant? Grab the copy-paste version for Claude or ChatGPT.
02 Base URL & transport
Requests go to the server's RCON host and port. The scheme depends on how the listener is bound:
// loopback listener (BindAddress=127.0.0.1) — plaintext allowed http://<host>:<port>/v1/… // network listener (BindAddress=0.0.0.0) — TLS required https://<host>:<port>/v1/…
Any server you reach remotely is bound to the network, and a network-exposed RCON listener requires TLS (and a hashed password) to start. Plain HTTP is only for a loopback listener on the box itself. The default RCON port is 7776 (settable in config or with -RCONPort=).
Bodies and responses are JSON (Content-Type: application/json). The two config-document endpoints are the exception: they send and receive text/plain.
A browser page can call a TLS server directly. It can't call a plaintext loopback listener from an HTTPS page (mixed content is blocked), so for local/plaintext setups call from a server.
03 Authentication
Send the RCON password as a bearer token on every request:
Authorization: Bearer <rcon-password>
There's no separate login step. To check a connection, call GET /v1/status; if it succeeds, the token is good.
One token, full access
The same token authorizes every endpoint, read and write. That includes kick, ban, config replacement, and ending a match. There's no read-only key, so treat it as a full-access secret and keep it server-side.
04 Conventions
Errors
Failures return a non-2xx status with a JSON body:
{ "error": { "code": string, "message": string } }
The config write endpoints return 412 when your revision is out of date (see Response shapes).
Feature detection
GET /v1/capabilities tells you which routes a server supports:
{ "routes": string[], // e.g. "PATCH /v1/players/{id}"
"config": { "writable": boolean } }
The admin panel uses exactly this: it shows "change team" only when PATCH /v1/players/{id} is in routes, and the config editor only when config.writable is true.
05 Endpoints
The full /v1 surface. Path parameters are in violet, and request bodies are noted where an endpoint takes one. Filter by access or search by path, method, or description.
↗ Open the interactive API console
A Scalar console backed by the OpenAPI spec (openapi.json) — browse, and generate a client in any language.
| Method | Path | Group | Access | Description & body |
|---|
06 Response shapes
The fields you can count on in each response. Servers may include more, but these are the ones the panel reads and relies on.
GET /v1/status
{
serverName: string,
map: string, // map id, e.g. "Kavkazi"
experiences: string[],
lighting: string,
alternator: string,
scoreTick: { current, min, max },
scoreCap: number,
matchSeconds: number,
players: { current, max },
factionScores: [ { name, colorHex, … } ], // one row per faction
rotation: { nowIndex, nextIndex } // integer, or null
}
GET /v1/players
{ players: [ { name, steamId, faction, kills, deaths, cash, pingMs } ] }
faction is a server-defined name; match it to a faction row by colorHex from factionScores. Steam names and avatars aren't here, see Player names.
GET /v1/rotation
{
enabled: boolean,
mode: string, // "ordered" | "random"
entries: [ {
map, experiences[], lighting,
zoneAlternator,
status, // "now" | "next" | …
denied: boolean
} ]
}
GET /v1/bans
{ bans: [ {
steamId,
bannedAtUtc,
bannedBy,
reason
} ] }
GET /v1/reserved-slots
{ reservedSlots: string[] }
// array of steamId strings
GET /v1/audit?limit=N
{ entries: [ {
timestampUtc, peer,
sessionId, event,
detail
} ] }
// limit 1–500, default 50
GET /v1/config
{
revision: string,
writable: boolean,
text: string, // the config document
sections: [ … ],
warnings: [ … ]
}
PUT /v1/config & POST /v1/config/validate — result
{
ok: boolean, revision: string,
error: { code, message },
outcomes: [], shadowed: [], stripped: [], errors: [], changed: [],
conflict: [], // present on HTTP 412 (revision mismatch)
warnings: [], timingsMs: object|null
}
Send the document as the raw request body with Content-Type: text/plain. Pass the current revision as an If-Match: "<revision>" header for safe concurrent edits; a stale revision returns 412. Optional query params: force=true, fullApply=true.
07 Player names
The API gives you steamId, not display names or avatars. Resolve those yourself against the Steam Web API.
Call ISteamUser/GetPlayerSummaries with your own Steam Web API key, passing the steamId values from /v1/players. Batch them and cache the results, since names change rarely.
The admin panel does the same thing through a small proxy on its own host (GET /api/steam/profiles?ids=…, key in an X-Steam-Api-Key header, up to 32 ids per call, returning { "<steamId>": { name, avatar } }). That proxy isn't part of the game server API, so most tools just call Steam directly.
08 ServerSettings.ini
The dedicated server reads a single config file at startup. Only whitelisted sections and keys are honored — anything else is stripped. Omitted keys keep their default. RCON commands for bans, reserved slots, and rotation edit this file and persist back to it.
↓ Download a starter ServerSettings.ini
A commented template with every key at its default. Edit it and drop it in your server's config location.
The RCON listener
This section decides whether, where, and how you can connect at all:
[/Script/WDRCON.WDRCONSettings] bEnabled=true // listener is OFF by default BindAddress=127.0.0.1 // loopback = plaintext ok; 0.0.0.0 = all interfaces, needs TLS Port=7776 // default; or launch with -RCONPort= Password= // plaintext; if empty, auto-generated to Saved/RCON/ADMIN-PASSWORD.txt PasswordHash="" // from `WardogsServer -GenerateRCONHash=`; wins over Password
A network-facing listener (0.0.0.0) will not start without a TLS cert and key, and uses PasswordHash. Loopback may use a plaintext Password. That is the whole auth model: the password (or the password behind the hash) is the bearer token.
Every honored key
| Key | Default | Applies | What it does |
|---|---|---|---|
| Session [/Script/WDGame.WDGameSession] | |||
| ServerName | — | immediately | Name in the server browser. |
| ServerPassword | (empty) | next restart | Join password. Empty = open server. |
| ServerMinPlayerCash | 0 | next restart | Minimum cash to join. 0 = no limit. |
| ServerMaxPlayerCash | 0 | next restart | Maximum cash to join. 0 = no limit. |
| ServerMinPlayerLevel | 0 | next restart | Minimum level to join. 0 = no limit. |
| ServerMaxPlayerLevel | 0 | next restart | Maximum level to join. 0 = no limit. |
| ServerImageURL | — | pending | Sponsor banner. 1024×256 PNG/JPEG on the allow-list. |
| MaxReservedSlots | 20 | immediately | How many reserved slots exist. |
| +DefaultReservedPlayerIds | — | — | One line per SteamID64. The RCON reserve command edits these. |
| +DefaultBannedPlayerIds | — | — | One line per SteamID64. The RCON ban / unban commands edit these. |
| Player slots [/Script/Engine.GameSession] | |||
| MaxPlayers | 128 | immediately | Total player slots. Clamped by a developer-set min/max. |
| Pre-match [MatchState.PreMatch.WaitingForPlayers.PlayerCount] | |||
| MinimumRequiredPlayers | 60 | next match | Players required before pre-match becomes a live match. |
| KOTH scoring [MatchState.Playing.KOTH] | |||
| ScorePeriod | 24 | next match | Seconds between score ticks (18–30). A faster tick pays less each time. |
| Team balancing [/Script/WDGame.WDGameStateSession] | |||
| bLockOverpopulatedTeamsConfig | true | next match | Stop players joining a team that already leads by the threshold. |
| OverpopulatedTeamThresholdConfig | 2 | next match | How many players ahead a team must be before it locks. |
| Map rotation [/Script/WDGame.WDServerMapRotationSettings] | |||
| bEnabled | true | immediately | Advance through the rotation after each match. |
| RotationMode | Ordered | immediately | Ordered walks top to bottom; Random picks each next entry. |
| +RotationEntries | — | immediately | One map entry per line (format below). |
Rotation entry format
+RotationEntries=(Map="Kavkazi",Experience="Bakurani_KOTH_01",Lighting="DayClear",ZoneAlternator="ZoneAlternator.Factory.Circle") +RotationEntries=(Map="Europe",Experiences="Madrid_KOTH_01+KOTH_InfantryOnly",Lighting="DayLateGray")
Experience (singular) is one; Experiences (plural) joins several with +. ZoneAlternator is optional — omit it for the map's authored default.
09 Prompt for AI tools
Building with Claude or ChatGPT? Copy the block below and paste it in as context. It's the whole API in plain text, so your assistant can write correct requests against it without guessing.
10 Notes
- Check capabilities per server. Not every server enables every route.
GET /v1/capabilitiesis the real list for the server you're talking to. - Poll gently. There's no published rate limit. A few seconds between calls is plenty for live status; the panel itself refreshes on a 3–5 second cadence.
- Match factions by color. A player's
factionis a name; the stable key across a server is thecolorHexon eachfactionScoresrow. - Keep the token off the client. Since the token is the full-access RCON password, requests belong on a server you control, never in a browser.