WarDogsServer Commands
API-01

API for developers

Last updated September 17, 2026

Your website, your own bot or a script can read your WARDOGS servers and act on them. It works the same whether your community is connected through Warcon, directly or through the WarDogs agent. Every action goes through the same checks as the dashboard and appears in your log.

1.0

Getting a key

In the dashboard open Setup → API & webhooks, name the key and pick its scopes:

  • read: servers, live data, matches, leaderboards, player stats, bans, history
  • moderate: broadcast, whisper, kick, kill, move, ban, unban, whitelist
  • control: end or restart the match, change the map, next map, lighting
  • config: read and change the server config

The key is shown once. Keep it on your server, never in a web page or a Discord message. 120 requests a minute per key; above that you get HTTP 429 with Retry-After.

2.0

Requests

Base URL https://wardogsbot.com/api/v1, key in the Authorization header. Every answer has ok; errors look like { "ok": false, "error": { "code", "message" } }.

curl https://wardogsbot.com/api/v1/servers \
  -H "Authorization: Bearer wdk_your_key"
curl -X POST https://wardogsbot.com/api/v1/servers/SERVER_ID/actions/kick \
  -H "Authorization: Bearer wdk_your_key" -H "Content-Type: application/json" \
  -d '{"steamId":"76561198000000000","reason":"Team killing"}'
// Node.js 18+
const res = await fetch("https://wardogsbot.com/api/v1/actions/ban", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.WARDOGS_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ steamId: "76561198000000000", reason: "Cheating", minutes: 10080 }),
});
console.log(await res.json()); // { ok: true, message: "...", servers: [...] }

Add "silent": true to an action to skip the in-game announcement. The full description is machine-readable at /api/v1/openapi.json (OpenAPI 3.1).

3.0

Endpoints

MethodPathScopeWhat
GET/meanyThe key, its scopes and the community
GET/serversreadLinked servers with online state, players and map
GET/servers/{serverId}/livereadLive status (scores, map, mode, rotation) and every player with kills, deaths and ping
GET/servers/{serverId}/history?hours=24readPlayer counts over time, uptime, outages, unique players, time per map (up to 720 h)
GET/matches?server=&limit=20readRecent matches with score, winner and MVP
GET/matches/{matchId}readOne match with every player
GET/leaderboard?range=7d&sort=kills&limit=50readLeaderboard (range 7d, 30d or all)
GET/players/{steamId}readA player's kills, deaths, matches and seeding time here
GET/bansreadCommunity ban lists and per-server bans
POST/servers/{serverId}/actions/{action}moderate / controlRun an action on one server
POST/actions/{action}moderate / controlBan, unban and whitelist on every server at once
GET/servers/{serverId}/configconfigThe server config as sections and keys (passwords hidden)
PATCH/servers/{serverId}/configconfigChange config values, checked by the server first

Actions

broadcastmoderatemessage
whispermoderatesteamId, message
kickmoderatesteamId, reason?
killmoderatesteamId
changeTeammoderatesteamId, faction
banmoderatesteamId, reason?, minutes? (temporary)
unbanmoderatesteamId
reservedAddmoderatesteamId, minutes? (whitelist)
reservedRemovemoderatesteamId
endMatch / restartMatchcontrol
changeMap / setNextMapcontrolmap, experiences?, lighting?, zoneAlternator?
setLightingcontrollighting
4.0

Webhooks

Add an https URL under Setup → API & webhooks and pick events. We POST JSON to it:

  • action: any staff action (dashboard, Discord, automations or the API), with who did it
  • match.ended: the match summary and the top ten players
  • server.offline / server.online: a server stopped or started answering
{
  "id": "5f0c…",
  "event": "match.ended",
  "guildId": "1123372445974401185",
  "at": "2026-09-17T20:14:03.000Z",
  "data": { "match": { "id": 73, "map": "Ozeti", "winner": "Valkyra", … }, "topPlayers": [ … ] }
}

Every request carries X-WarDogs-Signature: t=<unix>,v1=<hex>, an HMAC-SHA256 of <t>.<raw body> with the webhook secret. Check it, and refuse requests older than five minutes:

import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Answer with any 2xx within five seconds. Deliveries are not retried; after 50 failures in a row the webhook is paused until a test from the dashboard succeeds.