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.
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.
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).
Endpoints
| Method | Path | Scope | What |
|---|---|---|---|
| GET | /me | any | The key, its scopes and the community |
| GET | /servers | read | Linked servers with online state, players and map |
| GET | /servers/{serverId}/live | read | Live status (scores, map, mode, rotation) and every player with kills, deaths and ping |
| GET | /servers/{serverId}/history?hours=24 | read | Player counts over time, uptime, outages, unique players, time per map (up to 720 h) |
| GET | /matches?server=&limit=20 | read | Recent matches with score, winner and MVP |
| GET | /matches/{matchId} | read | One match with every player |
| GET | /leaderboard?range=7d&sort=kills&limit=50 | read | Leaderboard (range 7d, 30d or all) |
| GET | /players/{steamId} | read | A player's kills, deaths, matches and seeding time here |
| GET | /bans | read | Community ban lists and per-server bans |
| POST | /servers/{serverId}/actions/{action} | moderate / control | Run an action on one server |
| POST | /actions/{action} | moderate / control | Ban, unban and whitelist on every server at once |
| GET | /servers/{serverId}/config | config | The server config as sections and keys (passwords hidden) |
| PATCH | /servers/{serverId}/config | config | Change config values, checked by the server first |
Actions
| broadcast | moderate | message |
| whisper | moderate | steamId, message |
| kick | moderate | steamId, reason? |
| kill | moderate | steamId |
| changeTeam | moderate | steamId, faction |
| ban | moderate | steamId, reason?, minutes? (temporary) |
| unban | moderate | steamId |
| reservedAdd | moderate | steamId, minutes? (whitelist) |
| reservedRemove | moderate | steamId |
| endMatch / restartMatch | control | — |
| changeMap / setNextMap | control | map, experiences?, lighting?, zoneAlternator? |
| setLighting | control | lighting |
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.