WardenCoredocs
APIEndpoints

Claim codes

Mint, list, and revoke redeemable pack claim codes for your players.

A claim code is a redeemable token tied to a pack. Mint one for a specific player, hand it out, and they redeem it in-game or via Discord to receive the pack. Use these endpoints to mint, list (the code history), and revoke codes.

Redemptions land in the pack delivery history with source: "claim".

POST /v1/claim-codes

Mint a targeted claim code for a pack.

Scope: claim_codes:write.

FieldTypeMeaning
pack_idstring (positive integer)The pack to grant. Resolved to the pack by id.
steam_idstring (17 digits)The recipient — only this player can redeem the code.
max_usesinteger (≥ 1)How many times it can be redeemed. Default 1.
expiry_daysinteger (0–3650)Days until it expires. 0 = never. Default 0.
POST /v1/claim-codes
Content-Type: application/json

{ "pack_id": "5", "steam_id": "76561198000000000", "max_uses": 1, "expiry_days": 7 }
{
  "code": "scrap_50units-VRBC7A",
  "pack": { "id": 5, "name": "starter", "display_name": "Starter Pack" },
  "target": { "steam_id": "76561198000000000", "discord_id": "123456789012345678" },
  "max_uses": 1,
  "expires_at": "2026-01-10 12:00:00",
  "dm_status": "sent"
}

If the recipient is Discord-linked, the code is also DM'd to them; dm_status reports that delivery. expires_at is null when the code never expires. The pack object is the standard pack reference — catalog slug plus display title.

Minting is NOT idempotent — send an Idempotency-Key

Each call mints a new code. A network retry would mint a second one. Send an Idempotency-Key so a retry after a blip replays the first code instead.

GET /v1/claim-codes

List minted codes with their redemption state (the code history).

Scope: claim_codes:read.

QueryTypeMeaning
pack_idstring (positive integer)Only codes for this pack.
sourcewargm | discord | panelHow the code was created.
statusactive | expired | exhausted | revokedRedemption state.
targetstring (Steam64 digits)Match on the target Steam64 (partial match allowed).
cursorstringOpaque pagination cursor.
limitinteger (1–100)Page size. Default 50.
{
  "data": [
    {
      "code": "scrap_50units-VRBC7A",
      "pack": { "id": 5, "name": "starter", "display_name": "Starter Pack" },
      "target": { "steam_id": "76561198000000000", "discord_id": "123456789012345678" },
      "source": "panel",
      "status": "active",
      "max_uses": 1,
      "uses_remaining": 1,
      "created_at": "2026-01-03 12:00:00",
      "expires_at": "2026-01-10 12:00:00",
      "dm": { "channel_id": "111111111111111111", "message_id": "222222222222222222" }
    }
  ],
  "has_more": false,
  "next_cursor": null,
  "total": 1
}

target is null for a public (untargeted) code. target.discord_id is the recipient's current Discord link (Discord travels with Steam — null when they aren't linked).

DELETE /v1/claim-codes/{code}

Revoke a code — it can no longer be redeemed. 404 not_found when the code doesn't exist.

Scope: claim_codes:write.

{ "code": "scrap_50units-VRBC7A", "revoked": true }

Errors

Standard error envelope.

CodeStatusWhen
insufficient_scope403The key lacks claim_codes:read (list) or claim_codes:write (mint / revoke).
premium_required403The game server's plan does not include the pack/shop feature.
not_found404Unknown pack_id (mint) or unknown code (revoke).
validation_error400Bad pack_id/steam_id, an out-of-range max_uses/expiry_days, an out-of-enum source/status, or a game-server rejection (its message is in error.details.mod_message).
idempotency_conflict409The Idempotency-Key you sent was already used with a different request body. Reuse the key only for a retry of the identical mint.
server_unavailable503The game server is offline or unreachable.
gateway_timeout504The server did not respond in time.

On this page