Unofficial Not official Wardogs docs, not affiliated with the devs, and may change. Dev hub →
WARDOGS.TECH Unofficial · Community reference Updated 2026-09-21 · v0.39

Wardogs Server Reference

A community reference for running a Wardogs dedicated server: the RCON HTTP API and the ServerSettings.ini config, in one place. Unofficial.

RCON API/v1 · 29 live, 8 removed
AuthBearer token
TransportPlain HTTP · no TLS
ConfigServerSettings.ini

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, and in what build they run. GET /v1/capabilities lists the routes a given one actually serves, so check there rather than assume.

Changed 2026-09-14 (build ++Wardogs+Live-CL-501228): eight write endpoints were removed. Reserved slots, rotation editing, the score period and the sponsor banner are now edits to the config document instead. They are still listed below, marked removed, because plenty of servers are on older builds.

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, over plain HTTP:

http://<host>:<port>/v1/…

There is no TLS on the RCON listener. An earlier version of this page said a network-bound listener required a certificate; that is wrong, and we have corrected it — the official console hard-codes http://, and a live server confirms it: HTTP answers, HTTPS refuses the connection outright. The default port is 7776 (settable in config or with -RCONPort=).

So the password crosses the wire in the clear. Treat the port as something to keep off the internet: bind it to loopback and reach it through a VPN or an SSH tunnel, or put a reverse proxy that does terminate TLS in front of it. Anyone who can read the traffic has full control of the server.

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 served over HTTPS cannot call a plain-HTTP server at all — mixed content is blocked — which is why the official console is itself served over HTTP, and why anything you build should make the call from a server rather than the page.

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.

MethodPathGroupAccessDescription & 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

/v1/players gives you each player's in-game name and steamId. It does not give avatars or Steam profile names; resolve those yourself against the Steam Web API if you want them.

Call ISteamUser/GetPlayerSummaries with your own Steam Web API key, passing the steamId values from /v1/players. Batch them and cache the results, since profile 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.

Editing it over the API

Since the 2026-09-14 build this file is the write API for reserved slots, the rotation, the score period and the sponsor banner. Three things to know before you write to it:

1. PUT /v1/config replaces the whole document. Sections you leave out are removed, not left alone — a validate of a one-section fragment reports every other section as going away. Always GET /v1/config, edit that exact text, and send it back.

2. The leading punctuation on array keys is Unreal's config operators, not decoration. A live document looks like this:

[/Script/WDGame.WDServerMapRotationSettings]
!RotationEntries=ClearArray          // empty the array the game already has
.RotationEntries=(Map="Kavkazi")     // then append this entry

!Key=ClearArray is an instruction, not a member of the array. Count it as one and every rotation index you compute is off by one.

3. Every value is revalidated on every apply, including ones you did not touch. One stale value — a sponsor URL whose host has since dropped off the server's ImageURLWhitelist, say — fails the whole write with 422 and nothing is applied, blocking edits to unrelated keys until it is fixed. The response's errors[] names the section and key, so show it rather than a status code.

Send the revision you read as If-Match: "<revision>" so two admins editing at once get a conflict instead of one quietly overwriting the other, and dry-run with POST /v1/config/validate, which runs the same validation and writes nothing.

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; 0.0.0.0 = every interface
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

That is the whole auth model: the password — or the password behind PasswordHash — is the bearer token, and it authorizes everything. There is no per-key permission and no second factor.

The listener serves plain HTTP either way, so binding it to 0.0.0.0 puts a full-access password on the wire in clear text. Leave it on 127.0.0.1 and reach it through a tunnel, a VPN, or a TLS-terminating proxy.

Every honored key

KeyDefaultAppliesWhat it does
Session [/Script/WDGame.WDGameSession]
ServerName—immediatelyName in the server browser.
ServerPassword(empty)next restartJoin password. Empty = open server.
ServerMinPlayerCash0next restartMinimum cash to join. 0 = no limit.
ServerMaxPlayerCash0next restartMaximum cash to join. 0 = no limit.
ServerMinPlayerLevel0next restartMinimum level to join. 0 = no limit.
ServerMaxPlayerLevel0next restartMaximum level to join. 0 = no limit.
ServerImageURL—pendingSponsor banner. 1024×256 PNG/JPEG on the allow-list.
MaxReservedSlots20immediatelyHow 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]
MaxPlayers128immediatelyTotal player slots. Clamped by a developer-set min/max.
Pre-match [MatchState.PreMatch.WaitingForPlayers.PlayerCount]
MinimumRequiredPlayers60next matchPlayers required before pre-match becomes a live match.
KOTH scoring [MatchState.Playing.KOTH]
ScorePeriod24next matchSeconds between score ticks (18–30). A faster tick pays less each time.
Team balancing [/Script/WDGame.WDGameStateSession]
bLockOverpopulatedTeamsConfigtruenext matchStop players joining a team that already leads by the threshold.
OverpopulatedTeamThresholdConfig2next matchHow many players ahead a team must be before it locks.
Map rotation [/Script/WDGame.WDServerMapRotationSettings]
bEnabledtrueimmediatelyAdvance through the rotation after each match.
RotationModeOrderedimmediatelyOrdered walks top to bottom; Random picks each next entry.
+RotationEntries—immediatelyOne 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.

Paste into Claude / ChatGPT

10 Notes

  • Check capabilities per server. Not every server enables every route. GET /v1/capabilities is 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 faction is a name; the stable key across a server is the colorHex on each factionScores row.
  • 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.