WardenCoredocs
APIEndpoints

Players

Rosters, live presence, full profiles, inventory, and moderation for the players on your server.

Everything about the players on your server — the roster, who is online right now, a full profile (stats, skills, bases, vehicles, survival), inventory, and moderation state. A separate scope unlocks moderation history and IP data.

Identifying a player

Every per-player endpoint takes a {ref} path segment that accepts either identifier:

  • a Steam64 id — 76561198000000000
  • a Discord id, prefixed — discord:123456789012345678
GET /v1/players/76561198000000000
GET /v1/players/discord:123456789012345678

Steam64 is the canonical, immutable key. A Discord id is itself stable, but its link to a player is mutable, so a discord: ref resolves to the currently-linked player at request time (404 not_found if none is linked). You can also look a player up on the list endpoint with ?steam_id= or ?discord_id=.

Authorization

ScopeGrants
players:readThe list, live presence, profile, inventory, and moderation state.
players:read_sensitiveModeration history and IP data (/violations, /ips).

Both steam_id and discord_id are returned in the roster and profile responses under the base players:read scope; the live snapshot (/players/online) carries only steam_id. A key missing the required scope gets 403 insufficient_scope.

GET /v1/players

The player roster, paginated. Optional filters:

QueryMeaning
steam_idExact match on Steam64.
discord_idExact match on the linked Discord id.
onlinetrue / false — only online / offline players.
searchFree-text name search. Cannot be combined with a structured filter above (400 validation_error).
limitPage size, 10–100 (default 50).
cursorOpaque cursor from a previous response's next_cursor.

Returns a collection envelope:

{
  "data": [
    {
      "steam_id": "76561198000000000",
      "discord_id": "123456789012345678",
      "user_profile_id": 7,
      "steam_name": "Bob",
      "char_name": "Bobby",
      "online": true,
      "squad": { "id": 4, "name": "Alpha", "rank": 1 },
      "money": 500, "gold": 3, "coins": 9, "fame_points": 12.5,
      "attributes": { "strength": 2.35, "constitution": 3.1, "dexterity": 4, "intelligence": 5.25 },
      "play_time": 3600, "is_admin": false,
      "last_seen": "2024-01-01 12:00:00", "created_at": "2023-01-01 10:00:00"
    }
  ],
  "total": 1,
  "has_more": false,
  "next_cursor": null
}

total is the count of players matching the query (across all pages).

GET /v1/players/online

A live snapshot of everyone online right now — positions, ping, stance, and live currency. Filter to one player with ?steam_id= or ?discord_id=. Not paginated (the online set is bounded); served with a short max-age so a poller does not hammer the game server.

{
  "online": 1,
  "data": [
    {
      "steam_id": "76561198000000000", "name": "Bob", "ping": 30,
      "position": { "x": 1, "y": 2, "z": 3 },
      "alive": true, "conscious": true, "immortal": false, "super_jump": false,
      "is_admin": false, "money": 0, "gold": 0, "fame_points": 0,
      "stance": "stand", "item_in_hands": null
    }
  ]
}

GET /v1/players/{ref}

The full profile: everything on the roster row plus warden_stats (kills, deaths, streaks, totals, login streak, timestamps), skills, bases, vehicles, and a typed survival block. money is the player's bank balance.

Field notes

Attributes, fame_points, and skill level are fractional numbers. total_kills, total_deaths, and login_streak are null on servers running an older mod build that does not yet report them. The profile includes discord_id; it excludes IP history — that lives behind the sensitive scope at /ips — and any other Discord-account detail.

GET /v1/players/{ref}/inventory

The player's full, nested inventory — each item may carry contents (recursively) for containers. A subtree the mod stopped expanding at its depth cap is flagged contents_truncated: true.

{ "items": [ { "id": 1, "class": "Weapon", "name": "Rifle", "icon": "…", "health": 100, "max_health": 100, "weight": 3.5, "is_container": false, "is_weapon": true, "contents_truncated": false, "contents": [] } ] }

GET /v1/players/{ref}/moderation

Current ban and mute state. The player (subject) and banned_by (moderator) are identity objects that carry both steam_id and discord_iddiscord_id is null when that person is not Discord-linked. banned_by is null when the player is not banned; a legacy/system entry with no moderator Steam id surfaces its label as name (with steam_id: null).

{
  "player": { "steam_id": "76561198000000000", "discord_id": "123456789012345678" },
  "ban": { "banned": true, "reason": "cheating", "permanent": false, "expires_at": "2023-11-14T22:13:20.000Z", "banned_at": "2023-11-03T…", "banned_by": { "steam_id": "76561198000000001", "discord_id": "223…", "name": null } },
  "mute": { "muted": false, "permanent": false, "muted_at": null, "duration_minutes": null, "channels": [] }
}

To change ban/mute state, see Moderation (players:ban / players:mute).

GET /v1/players/{ref}/violations

Requires players:read_sensitive. The paginated moderation history (bans, mutes, and trap events), newest first, with the issuing moderator. Paginate with limit (1–100) and the cursor. Never cached (Cache-Control: private, no-store). issued_by is an identity object carrying the moderator's steam_id, discord_id (null when unlinked), and name.

{
  "data": [ { "id": 11, "type": "ban", "action": "applied", "source": "mod", "reason": "…", "issued_by": { "steam_id": "76561198000000001", "discord_id": "223…", "name": "Admin" }, "applied_at": "2023-11-03T…", "expires_at": "2023-11-14T…", "duration_sec": 3600, "metadata": { "channel": "Global" } } ],
  "has_more": false,
  "next_cursor": null
}

GET /v1/players/{ref}/ips

Requires players:read_sensitive. The player's IP history, newest first; current_ip is the most recent. Never cached.

{ "current_ip": "…", "history": [ { "ip": "…", "first_seen": "2023-11-03T…", "last_seen": "2023-11-14T…" } ] }

Caching

The list, live snapshot, profile, inventory, and moderation reads send an ETag and a short Cache-Control: private, max-age; send the ETag back as If-None-Match to get a 304 Not Modified (the live snapshot's ETag matches when nothing has moved within its window). The sensitive reads (/violations, /ips) are no-store.

Errors

Standard error envelope. The ones you're most likely to hit:

CodeStatusWhen
insufficient_scope403The key lacks players:read (or players:read_sensitive for /violations, /ips).
not_found404No player matches the {ref} (unlinked Discord id, or unknown profile).
validation_error400?search= combined with a structured filter, or a bad query value.
server_unavailable503The game server is offline or unreachable.
gateway_timeout504The server did not respond in time.

On this page