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.
| Field | Type | Meaning |
|---|---|---|
amount | integer ≠ 0 | Signed delta. Positive credits, negative debits. |
reason | string (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).
| Field | Type | Meaning |
|---|---|---|
amount | integer ≠ 0 | Signed delta applied to each targeted player. |
reason | string (1–500) | Required — recorded on the ledger entry. |
target | all | online | Who 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.
| Code | Status | When |
|---|---|---|
insufficient_scope | 403 | The key lacks economy:write (single) or economy:write_all (bulk). |
not_found | 404 | No 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. |
conflict | 409 | A debit exceeds the player's balance (the game-server message is in error.message). |
validation_error | 400 | amount is 0/missing, reason is missing, an unknown target, or a game-server-side rejection (its message is in error.details.mod_message). |
rate_limited | 429 | Bulk 5-second cooldown (see above). |
server_unavailable | 503 | The game server is offline or unreachable. |
gateway_timeout | 504 | The server did not respond in time. |