WardenCoredocs
APIEndpoints

Coins

Add or remove coins for one player, or in bulk across your whole server.

Adjust coin balances: a single player (POST /v1/players/{ref}/coins) or everyone (POST /v1/economy/coins). Every adjustment is recorded in the economy ledger with the reason you supply — read it back with GET /v1/economy/transactions.

Signed amount

amount is a signed delta: a positive value credits, a negative value debits. 0 is rejected (400). The panel routes the sign to the right game-server operation and always sends the magnitude — you never call a separate "add" vs "remove" endpoint. The response echoes the signed amount you sent.

Coin writes are NOT idempotent — send an Idempotency-Key

Unlike ban/mute, a coin adjustment is a delta: applying it twice doubles it. A network retry could double-apply. Send an Idempotency-Key so a retry after a blip replays the first result instead of adding again.

POST /v1/players/{ref}/coins

Adjust one player's balance. {ref} is a Steam64 or a prefixed Discord id (discord:123456789012345678); a discord: ref resolves to the currently-linked player.

Scope: economy:write.

FieldTypeMeaning
amountinteger ≠ 0Signed delta. Positive credits, negative debits.
reasonstring (1–500)Required — recorded on the ledger entry.
POST /v1/players/76561198000000000/coins
Content-Type: application/json

{ "amount": 500, "reason": "event reward" }

Returns the new balance and the subject identity (Discord travels with Steam — discord_id is null when the player isn't linked):

{ "amount": 500, "balance": 1500, "player": { "steam_id": "76561198000000000", "discord_id": "123456789012345678" } }

Crediting an unknown Steam id creates the player

A positive adjust to a well-formed Steam64 that has never joined creates that player's record and credits it (200) — matching the game server's native behaviour. A negative adjust to an unknown player returns 404 not_found. Debiting more than the balance returns 409 conflict.

POST /v1/economy/coins

Adjust many players at once.

Scope: economy:write_all (a separate, more powerful scope than the single-player one — a key that tops up individuals cannot drain the whole economy).

FieldTypeMeaning
amountinteger ≠ 0Signed delta applied to each targeted player.
reasonstring (1–500)Required — recorded on the ledger entry.
targetall | onlineWho to adjust. Default all.
  • all (default) — every player on record, online and offline (including long-departed players). This is a big hammer; it is the default only because it matches the game server's existing "give to all" behaviour.
  • online — only the players currently online.

`target: online` needs a recent game server

The online-only target is served by a dedicated game-server route. If the connected server predates it, the call returns 404 not_found with a message telling you to update — it is never silently applied to everyone. Update the game server, or use target: all.

POST /v1/economy/coins
Content-Type: application/json

{ "amount": 100, "reason": "server anniversary", "target": "online" }
{ "amount": 100, "affected_count": 7, "target": "online" }

Bulk is rate-limited

Bulk adjustments share a 5-second cooldown on the game server. A second bulk call inside the window returns 429 rate_limited with a Retry-After header.

Errors

Standard error envelope.

CodeStatusWhen
insufficient_scope403The key lacks economy:write (single) or economy:write_all (bulk).
not_found404No player matches the {ref} (unlinked Discord id); a debit targets an unknown player; or target: online on a game server too old to support it.
conflict409A debit exceeds the player's balance (the game-server message is in error.message).
validation_error400amount is 0/missing, reason is missing, an unknown target, or a game-server-side rejection (its message is in error.details.mod_message).
rate_limited429Bulk 5-second cooldown (see above).
server_unavailable503The game server is offline or unreachable.
gateway_timeout504The server did not respond in time.

On this page