triggair API
Reference

API reference

Every endpoint, its auth scope, and a request/response example — 305 across 46 groups. Most games use the @triggair/sdk client rather than raw HTTP, but this is the underlying contract. Machine-readable: /openapi.json (OpenAPI 3.1). A publishable key goes in X-Triggair-Key; a player token and the developer/operator sessions go in Authorization: Bearer.

Players

Player accounts: use the SDK, or these endpoints

Email/password + Google sign-in are first-class endpoints — POST /v1/players/signup, /login, /token/refresh, /password-reset, and /oauth/google/start (all below). The SDK wraps them as tg.auth.signUp / signInWithPassword / signInWithGoogle / sendPasswordReset and handles the session + token refresh for you. See the Player accounts guide.

POST /v1/players/anonymous publishable key

Mint an anonymous player token

Exchanges a stable device id for a 24h player token. The player is created on first use. This is what the SDK's tg.login() calls; every player-scoped call sends the returned token as `Authorization: Bearer`.

request
{
  "device_id": "a-stable-device-uuid",
  "turnstile_token": "optional-if-challenge-on"
}
response · A banned account or device is refused with 403 player_banned.
{
  "player_id": "p_1a2b3c",
  "token": "eyJ…",
  "expires_in": 86400
}
GET /v1/players/oauth-origin-allowed no auth

Is an origin allowed for a game (OAuth callback guard)

Keyless. The centralized OAuth /auth/callback page calls this before delivering a Google session, to confirm the return `origin` is in the game's allowlist (pk passed as `?key`). Returns only `{ allowed }`, never the session. BE-19 security guard.

response
{
  "allowed": true
}
POST /v1/players/signup publishable key

Register a player account (email/password)

Create an account. With email confirmation on (the default), returns `{ needs_confirmation: true }` and a confirmation email is sent; set `redirect_to` (an allowlisted origin) for where its link lands. If a session is issued immediately, returns `{ needs_confirmation: false, session, player }`. The SDK wraps this as `tg.auth.signUp`.

request
{
  "email": "player@example.com",
  "password": "a-strong-password",
  "device_id": "a-stable-device-uuid"
}
response
{
  "needs_confirmation": true
}
POST /v1/players/login publishable key

Sign in with email/password

Verify credentials and return the account `session` (access + refresh token) plus a game-scoped player token (resume/adopt/link/create, or a `conflict` merge offer). Bad credentials return a generic 401. The SDK wraps this as `tg.auth.signInWithPassword`.

request
{
  "email": "player@example.com",
  "password": "a-strong-password",
  "device_id": "a-stable-device-uuid"
}
response
{
  "session": {
    "access_token": "eyJ…",
    "refresh_token": "…"
  },
  "player_id": "p_1a2b3c",
  "token": "eyJ…",
  "expires_in": 86400,
  "outcome": "linked"
}
POST /v1/players/token/refresh publishable key

Refresh the account session + player token

Exchange a `refresh_token` for a fresh account session AND a re-minted player token, so a login survives token/session expiry. The SDK calls this automatically.

request
{
  "refresh_token": "…",
  "device_id": "a-stable-device-uuid"
}
response
{
  "session": {
    "access_token": "eyJ…",
    "refresh_token": "…"
  },
  "player_id": "p_1a2b3c",
  "token": "eyJ…",
  "expires_in": 86400,
  "outcome": "resumed"
}
POST /v1/players/password-reset publishable key

Email a password-reset link

Always returns `{ ok: true }` — never reveals whether the address has an account. `redirect_to` (an allowlisted origin) is where the link lands. The SDK wraps this as `tg.auth.sendPasswordReset`.

request
{
  "email": "player@example.com"
}
response
{
  "ok": true
}
POST /v1/players/logout publishable key

Revoke the account session

Best-effort revoke of the account session (`Authorization: Bearer <access token>`). The client clears its own session regardless.

response
{
  "ok": true
}
GET /v1/players/oauth/google/start no auth

Start Google sign-in (redirect)

Keyless (opened in a popup; `key` + `origin` in the query). Validates the key + that the origin is allowlisted + Google is enabled, then 302-redirects into the Google OAuth flow, returning to the centralized callback. The SDK wraps this as `tg.auth.signInWithGoogle`.

Parameters
  • key (query) The game's publishable key.
  • origin (query) The calling game's origin (must be allowlisted).
POST /v1/players/session publishable key

Exchange an account session for a player token

Verifies an account session token (`Authorization: Bearer`, obtained via tg.auth) and returns a game-scoped player token, resolving the account↔player mapping. `outcome` is one of resumed/adopted/linked/created, or `conflict` — which also returns a `merge` block (an account player AND a distinct anonymous player with data both exist). Send the current `device_id` so a first login can link the anonymous player.

request
{
  "device_id": "a-stable-device-uuid"
}
response · On outcome=conflict, `merge.ticket` is passed to /v1/players/session/merge.
{
  "player_id": "p_1a2b3c",
  "token": "eyJ…",
  "expires_in": 86400,
  "outcome": "linked"
}
POST /v1/players/session/merge publishable key

Resolve a login merge conflict

With the merge ticket from a `conflict` session, choose `keep_account` (keep the account's data) or `use_anonymous` (replace it with the anonymous progress — a pointer swap that PARKS, never deletes, the displaced player). Returns a token for the resulting player. BE-18.

request
{
  "ticket": "…",
  "choice": "use_anonymous"
}
response
{
  "player_id": "p_9x8y7z",
  "token": "eyJ…",
  "expires_in": 86400,
  "outcome": "replaced"
}
POST /v1/players/recover publishable key

Recover a player on a new device

Consumes a recovery code (from /v1/players/me/recovery-code) to rebind the same player to a new device, returning a fresh token.

request
{
  "code": "RECOVERY-CODE",
  "device_id": "new-device-uuid"
}
response
{
  "player_id": "p_1a2b3c",
  "token": "eyJ…",
  "expires_in": 86400
}
GET /v1/players/me player token

Get the current player

response
{
  "id": "p_1a2b3c",
  "display_name": null,
  "created_at": "2026-07-01T00:00:00Z"
}
POST /v1/players/me/recovery-code player token

Mint a cross-device recovery code

Returns a single-use code the player saves/shares once; redeem it later with /v1/players/recover on another device.

response
{
  "code": "RECOVERY-CODE",
  "expires_at": "2026-08-01T00:00:00Z"
}
GET /v1/players/me/moderation player token

Get the caller's own ban/mute status

The player's active bans and restrictions (shadow actions are hidden from self-view).

response
{
  "banned": false,
  "restrictions": []
}
GET /v1/players/me/stats player token

Get the player's own stats

response
{
  "stats": [
    {
      "key": "kills",
      "value": 12
    }
  ]
}
POST /v1/players/me/stats player token

Update stats (set / increment)

Applies one or more stat operations atomically. Stats back leaderboards, achievements, and segment targeting.

request
{
  "stats": [
    {
      "key": "kills",
      "op": "increment",
      "value": 1
    }
  ]
}
response
{
  "stats": [
    {
      "key": "kills",
      "value": 13
    }
  ]
}
PATCH /v1/players/me player token

Update the player's profile (e.g. display name)

request
{
  "display_name": "AceRunner"
}
response
{
  "id": "p_1a2b3c",
  "display_name": "AceRunner",
  "handle": null,
  "avatar_seed": null
}
GET /v1/players player token

Look up a player by handle (public fields)

Parameters
  • handle (query) The unique @handle to resolve.
response
{
  "id": "p_9",
  "display_name": "Rival",
  "handle": "rival",
  "avatar_seed": null
}
GET /v1/players/:id player token

Get another player's public profile

Parameters
  • id (path) Player id.
response
{
  "id": "p_9",
  "display_name": "Rival",
  "handle": "rival",
  "avatar_seed": null
}

Saves

GET /v1/saves player token

List the player's save slots

response
{
  "saves": [
    {
      "slot": "slot1",
      "version": 3,
      "updated_at": "2026-07-01T00:00:00Z"
    }
  ]
}
GET /v1/saves/:slot player token

Read a save slot

Parameters
  • slot (path) Slot name (game-defined).
response
{
  "slot": "slot1",
  "data": {
    "level": 4,
    "coins": 120
  },
  "version": 3
}
PUT /v1/saves/:slot player token

Write a save slot

Last-write-wins by default. Send `If-Match: <version>` for optimistic concurrency — a stale version returns 409 save_conflict. Returns 201 on first write, 200 on update.

Parameters
  • slot (path) Slot name.
request
{
  "data": {
    "level": 5,
    "coins": 90
  }
}
response
{
  "slot": "slot1",
  "data": {
    "level": 5,
    "coins": 90
  },
  "version": 4
}
DELETE /v1/saves/:slot player token

Delete a save slot

Parameters
  • slot (path) Slot name.
response · 204 No Content.
null

Leaderboards

POST /v1/leaderboards/:board/scores player token

Submit a score

Submits a score to a configured board. The board keeps each player's best score for the period (higher_is_better sets direction); there is no last/sum mode. The period (all-time/daily/weekly) is set by the developer; the response reports the player's kept score for the current period.

Parameters
  • board (path) Board key.
request
{
  "score": 9000
}
response
{
  "ok": true,
  "best_score": 9000,
  "period_key": "2026-07"
}
GET /v1/leaderboards/:board/top player token

Read the top entries

Parameters
  • board (path) Board key.
  • limit (query) Max entries (default 10).
response
{
  "board": "high_scores",
  "period_key": "2026-07",
  "entries": [
    {
      "rank": 1,
      "player_id": "p_9",
      "score": 12000
    }
  ]
}
GET /v1/leaderboards/:board/around-me player token

Read entries around the player

Parameters
  • board (path) Board key.
response
{
  "board": "high_scores",
  "period_key": "2026-07",
  "me": {
    "rank": 42,
    "score": 8000
  },
  "entries": []
}
GET /v1/leaderboards/:board/friends player token

Read the friends-only board

Parameters
  • board (path) Board key.
response
{
  "board": "high_scores",
  "period_key": "2026-07",
  "me": {
    "rank": 2,
    "score": 8000
  },
  "entries": []
}

Achievements

GET /v1/achievements player token

List achievements + the caller's progress

Definitions plus this player's progress; secret achievements are hidden until unlocked.

response
{
  "achievements": [
    {
      "key": "first_win",
      "unlocked": true,
      "progress": 1,
      "target": 1
    }
  ]
}
POST /v1/achievements/:key/progress player token

Report achievement progress

The server clamps progress, unlocks exactly once, and escrows any reward into the inbox. The client reports progress but never grants the reward.

Parameters
  • key (path) Achievement key.
request
{
  "amount": 1
}
response
{
  "key": "first_win",
  "unlocked": true,
  "progress": 1
}

Daily

GET /v1/daily player token

Get daily-reward status

response
{
  "claimable": true,
  "streak": 3,
  "next_claim_at": "2026-07-11T00:00:00Z"
}
POST /v1/daily/claim player token

Claim today's reward

Server-day gated; the reward is escrowed into the inbox. Re-claiming the same day → 409 conflict.

response
{
  "claimed": true,
  "streak": 4
}

Inbox

GET /v1/inbox player token

List inbox items

Parameters
  • limit (query) Max items.
response
{
  "items": [
    {
      "id": "in_1",
      "kind": "reward",
      "claimable": true,
      "read": false
    }
  ]
}
POST /v1/inbox/:id/read player token

Mark an inbox item read

Parameters
  • id (path) Inbox item id.
response
{
  "ok": true
}
POST /v1/inbox/:id/claim player token

Claim an inbox item's reward

The single hardened grant path — exactly-once (idempotent per item). Grants currency, items, or stat rewards.

Parameters
  • id (path) Inbox item id.
response
{
  "claimed": true,
  "granted": {
    "currency": [
      {
        "code": "gold",
        "amount": 100
      }
    ]
  }
}

Social

GET /v1/friends player token

List friends

response
{
  "friends": [
    {
      "player_id": "p_9",
      "display_name": "Rival",
      "state": "accepted"
    }
  ]
}
GET /v1/friends/requests player token

List incoming friend requests

response
{
  "requests": [
    {
      "player_id": "p_7",
      "display_name": "Newcomer"
    }
  ]
}
POST /v1/friends/:id player token

Send or accept a friend request

Parameters
  • id (path) The other player's id.
response
{
  "state": "pending"
}
DELETE /v1/friends/:id player token

Remove a friend / cancel a request

Parameters
  • id (path) The other player's id.
response · 204 No Content.
null
POST /v1/friends/:id/block player token

Block a player

Parameters
  • id (path) The player to block.
response
{
  "blocked": true
}
POST /v1/share player token

Mint a share / invite link

Creates a short code carrying an opaque context blob (a level, a challenge, a referral). Resolve it with GET /v1/share/:code on the recipient's device.

request
{
  "context": {
    "level": 7
  },
  "expires_in_seconds": 604800
}
response
{
  "code": "SH4RE",
  "expires_at": "2026-07-18T00:00:00Z"
}
GET /v1/share/:code player token

Resolve a share link

Parameters
  • code (path) Share code.
response
{
  "context": {
    "level": 7
  },
  "from": "p_1a2b3c"
}

Moderation

POST /v1/moderate/check player token

Pre-check text before submit

Runs the same moderation the write paths use, so you can validate a chosen name/message without a round-trip failure. Stateless (writes nothing).

request
{
  "surface": "username",
  "text": "player name to check"
}
response
{
  "verdict": "mask",
  "masked_text": "player ****",
  "categories": [
    "profanity"
  ],
  "severity": 2
}
POST /v1/reports player token

Report a player / message / UGC

request
{
  "target_type": "player",
  "target_id": "p_9",
  "reason": "harassment",
  "note": "optional"
}
response
{
  "id": "cr_1",
  "state": "open"
}
POST /v1/appeals player token

Appeal a ban

request
{
  "ban_id": "bn_1",
  "body": "why the ban should be lifted"
}
response
{
  "id": "ap_1",
  "state": "pending"
}

Compliance

POST /v1/players/me/age player token

Set the player's age bracket

Neutral age screen. A birth year is mapped to a bracket and DISCARDED (no DOB stored). Returns the compliance view with the gated-feature map.

request
{
  "birth_year": 2013
}
response
{
  "bracket": "13_15",
  "consent_state": "pending",
  "gated": {
    "open_chat": true,
    "lootbox": true
  }
}
GET /v1/players/me/compliance player token

Get the compliance view (bracket + gated map)

response
{
  "bracket": "13_15",
  "consent_state": "pending",
  "gated": {
    "open_chat": true
  }
}
GET /v1/compliance/policy publishable key

Get the game's gate policy (pre-token)

pk-only so the client can pre-disable regulated UI before a player token exists.

response
{
  "gates": {
    "open_chat": "13_15",
    "lootbox": "adult"
  },
  "coppa_mode": false,
  "default_jurisdiction": "US"
}
POST /v1/players/me/consent/request player token

Request parental consent (emails the parent)

request
{
  "parent_email": "parent@example.com"
}
response
{
  "id": "pc_1",
  "state": "pending",
  "expires_at": "2026-07-24T00:00:00Z"
}
POST /v1/consent/:token/decide no auth

Record the parent's decision

Parameters
  • token (path) Signed consent token.
request
{
  "grant": true,
  "note": "optional"
}
response
{
  "state": "granted"
}

Crashes

POST /v1/crashes player token

Report a crash

Grouped server-side by a normalized-stack fingerprint into a handful of issues with a crash-free-users %.

request
{
  "message": "TypeError: x is undefined",
  "stack": "at play (game.js:42)",
  "platform": "web",
  "appVersion": "1.4.0"
}
response
{
  "ok": true,
  "group_id": "cg_1"
}

RNG

GET /v1/rng/:stream player token

Deterministic server-seeded random values

A verifiable per-player, per-period stream — the same request returns the same values, so loot/crit rolls can't be client-forged.

Parameters
  • stream (path) Stream name (e.g. 'loot').
  • count (query) How many values.
response
{
  "stream": "loot",
  "period_key": "2026-07",
  "values": [
    0.42,
    0.88
  ]
}

Realtime

GET /v1/realtime/rooms/:room player token

Join a realtime room (WebSocket upgrade)

A WebSocket upgrade. Because a browser WS can't send headers, the pk + player token go in the query (?key=&token=). Presence + broadcast; chat is moderated in transit. Rooms named team:<id> / match:<id> require membership. Use tg.realtime.join(room) from the SDK.

Parameters
  • room (path) Room name; team:/match: prefixes enforce membership.
  • key (query) Publishable key (query, since a WS can't set headers).
  • token (query) Player token.

Economy

GET /v1/wallet player token

Get all currency balances

response
{
  "balances": [
    {
      "currency": "gold",
      "balance": 250
    }
  ]
}
GET /v1/wallet/history player token

Get currency transaction history

Parameters
  • limit (query) Max lines.
response
{
  "lines": [
    {
      "currency": "gold",
      "delta": -100,
      "reason": "store_buy",
      "created_at": "2026-07-01T00:00:00Z"
    }
  ]
}
GET /v1/wallet/:currency player token

Get one currency's balance

Parameters
  • currency (path) Currency code.
response
{
  "currency": "gold",
  "balance": 250
}
GET /v1/stores player token

List stores

response
{
  "stores": [
    {
      "key": "main_store",
      "name": "Shop"
    }
  ]
}
GET /v1/stores/:key player token

Get a store's listings

Parameters
  • key (path) Store key.
response
{
  "key": "main_store",
  "listings": [
    {
      "id": "l_1",
      "item_id": "sword",
      "price": [
        {
          "currency": "gold",
          "amount": 100
        }
      ]
    }
  ]
}
POST /v1/stores/:key/buy player token

Buy a store listing

Server-authoritative price + balance check; idempotent (pass idem). Fails with insufficient_funds / out_of_stock / store_limit_reached.

Parameters
  • key (path) Store key.
request
{
  "listing_id": "l_1",
  "idempotency_key": "uuid"
}
response
{
  "kind": "applied",
  "txn_id": "tx_1",
  "lines": [
    {
      "target": "gold",
      "delta": -100,
      "balance_after": 150
    },
    {
      "target": "sword",
      "delta": 1,
      "balance_after": 1
    }
  ]
}
GET /v1/inventory player token

List the player's inventory

response
{
  "items": [
    {
      "item_id": "sword",
      "qty": 1,
      "equipped": true
    }
  ]
}
POST /v1/inventory/:item/consume player token

Consume an item

Parameters
  • item (path) Item id.
request
{
  "qty": 1,
  "idempotency_key": "uuid"
}
response
{
  "ok": true,
  "remaining": 0
}
POST /v1/inventory/:item/equip player token

Equip an item

Parameters
  • item (path) Item id.
response
{
  "ok": true,
  "equipped": true
}
POST /v1/inventory/:item/unequip player token

Unequip an item

Parameters
  • item (path) Item id.
response
{
  "ok": true,
  "equipped": false
}
GET /v1/loot/:key/odds player token

Get a loot box's disclosed odds

Parameters
  • key (path) Loot box key.
response
{
  "key": "bronze_box",
  "odds": [
    {
      "item": "common",
      "weight": 0.9
    },
    {
      "item": "rare",
      "weight": 0.1
    }
  ]
}
POST /v1/loot/:key/open player token

Open a loot box

Server-rolled (verifiable RNG), idempotent. loot_not_enabled if the box isn't configured; age-gated where required.

Parameters
  • key (path) Loot box key.
request
{
  "idem": "uuid"
}
response
{
  "rolled": [
    {
      "item": "rare",
      "qty": 1
    }
  ]
}
GET /v1/energy player token

List energy meters

response
{
  "meters": [
    {
      "meter": "stamina",
      "current": 4,
      "max": 5,
      "refill_at": "2026-07-10T01:00:00Z"
    }
  ]
}
GET /v1/energy/:meter player token

Get one energy meter

Parameters
  • meter (path) Meter name.
response
{
  "meter": "stamina",
  "current": 4,
  "max": 5
}
POST /v1/energy/:meter/spend player token

Spend energy

out_of_energy if the balance is insufficient. Idempotent.

Parameters
  • meter (path) Meter name.
request
{
  "amount": 1,
  "idem": "uuid"
}
response
{
  "meter": "stamina",
  "current": 3
}
POST /v1/energy/:meter/refill player token

Refill energy (e.g. with a currency)

Parameters
  • meter (path) Meter name.
request
{
  "idem": "uuid"
}
response
{
  "meter": "stamina",
  "current": 5
}
POST /v1/codes/redeem player token

Redeem a promo code

Grants the campaign reward into the inbox. code_invalid / code_expired / code_already_redeemed / code_campaign_exhausted on failure.

request
{
  "code": "LAUNCH2026"
}
response
{
  "ok": true,
  "granted": {
    "stats": [
      {
        "key": "gold",
        "amount": 100
      }
    ]
  }
}
POST /v1/gifts player token

Send a gift to another player

Delivers an item/currency gift into the recipient's inbox (subject to gifting limits).

request
{
  "to": "p_9",
  "item": "sword",
  "qty": 1,
  "idem": "uuid"
}
response
{
  "ok": true
}

Teams

POST /v1/teams player token

Create a team

request
{
  "name": "Alpha Squad",
  "tag": "ALPHA",
  "privacy": "open"
}
response
{
  "team": {
    "id": "tm_1",
    "name": "Alpha Squad",
    "tag": "ALPHA"
  }
}
GET /v1/teams player token

List / search teams

Parameters
  • q (query) Search query.
response
{
  "teams": [
    {
      "id": "tm_1",
      "name": "Alpha Squad",
      "member_count": 4
    }
  ]
}
GET /v1/teams/mine player token

Get the caller's team

response
{
  "teams": [
    {
      "id": "tm_1",
      "role": "owner"
    }
  ]
}
GET /v1/teams/leaderboards/:board player token

Team leaderboard

Parameters
  • board (path) Board key.
response
{
  "board": "high_scores",
  "agg": "sum",
  "standings": [
    {
      "team_id": "tm_1",
      "score": 5000
    }
  ]
}
GET /v1/teams/:id player token

Get a team + members

Parameters
  • id (path) Team id.
response
{
  "id": "tm_1",
  "name": "Alpha Squad",
  "members": [
    {
      "player_id": "p_1",
      "role": "owner"
    }
  ]
}
POST /v1/teams/:id/join player token

Join a team (open teams)

Parameters
  • id (path) Team id.
response
{
  "joined": true
}
POST /v1/teams/:id/leave player token

Leave a team

Parameters
  • id (path) Team id.
response
{
  "left": true
}
POST /v1/teams/:id/members/:pid/kick player token

Kick a member (admin/owner)

Parameters
  • id (path) Team id.
  • pid (path) Member player id.
response
{
  "kicked": true
}
POST /v1/teams/:id/members/:pid/role player token

Change a member's role

Parameters
  • id (path) Team id.
  • pid (path) Member player id.
request
{
  "role": "admin"
}
response
{
  "ok": true
}
POST /v1/teams/:id/transfer player token

Transfer ownership

Parameters
  • id (path) Team id.
request
{
  "to": "p_2"
}
response
{
  "ok": true
}
POST /v1/teams/:id/disband player token

Disband a team (owner)

Parameters
  • id (path) Team id.
response
{
  "ok": true
}
GET /v1/teams/mine/invites player token

List the caller's team invites

response
{
  "invites": [
    {
      "id": "ti_1",
      "team_id": "tm_1"
    }
  ]
}
POST /v1/teams/:id/invites player token

Invite a player

Parameters
  • id (path) Team id.
request
{
  "invitee_id": "p_7"
}
response
{
  "invite_id": "ti_1"
}
POST /v1/teams/invites/:iid/accept player token

Accept an invite

Parameters
  • iid (path) Invite id.
response
{
  "ok": true
}
POST /v1/teams/invites/:iid/reject player token

Reject an invite

Parameters
  • iid (path) Invite id.
response
{
  "ok": true
}
POST /v1/teams/:id/requests player token

Request to join (closed teams)

Parameters
  • id (path) Team id.
response
{
  "id": "tr_1",
  "state": "pending"
}
GET /v1/teams/:id/requests player token

List join requests (admin)

Parameters
  • id (path) Team id.
response
{
  "requests": [
    {
      "id": "tr_1",
      "player_id": "p_7"
    }
  ]
}
POST /v1/teams/:id/requests/:rid/approve player token

Approve a join request

Parameters
  • id (path) Team id.
  • rid (path) Request id.
response
{
  "ok": true
}
POST /v1/teams/:id/requests/:rid/reject player token

Reject a join request

Parameters
  • id (path) Team id.
  • rid (path) Request id.
response
{
  "ok": true
}
POST /v1/teams/:id/members/:pid/ban player token

Ban a member from the team

Parameters
  • id (path) Team id.
  • pid (path) Player id.
response
{
  "ok": true
}
POST /v1/teams/:id/members/:pid/unban player token

Unban a player

Parameters
  • id (path) Team id.
  • pid (path) Player id.
response
{
  "ok": true
}
GET /v1/teams/:id/bans player token

List team bans

Parameters
  • id (path) Team id.
response
{
  "bans": [
    {
      "player_id": "p_9"
    }
  ]
}

Competition

GET /v1/tournaments player token

List tournaments

response
{
  "tournaments": [
    {
      "id": "to_1",
      "title": "Weekend Cup",
      "state": "live"
    }
  ]
}
GET /v1/tournaments/mine player token

Tournaments the player has joined

response
{
  "tournaments": []
}
GET /v1/tournaments/:id player token

Get a tournament

Parameters
  • id (path) Tournament id.
response
{
  "id": "to_1",
  "title": "Weekend Cup",
  "starts_at": "2026-07-12T00:00:00Z"
}
GET /v1/tournaments/:id/standings player token

Get tournament standings

Parameters
  • id (path) Tournament id.
response
{
  "entries": [
    {
      "rank": 1,
      "player_id": "p_9",
      "score": 12000
    }
  ]
}
POST /v1/tournaments/:id/join player token

Join a tournament

tournament_not_open if entry is closed; may require an entry fee.

Parameters
  • id (path) Tournament id.
response
{
  "ok": true
}
GET /v1/tournaments/:id/me player token

The player's tournament entry

Parameters
  • id (path) Tournament id.
response
{
  "rank": 42,
  "score": 8000
}
POST /v1/leagues/:key/join player token

Join a league

Parameters
  • key (path) League key.
response
{
  "division": "bronze",
  "tier": 3
}
GET /v1/leagues/:key/me player token

The player's league standing

Parameters
  • key (path) League key.
response
{
  "division": "bronze",
  "tier": 3,
  "rank": 5
}
GET /v1/leagues/:key/divisions/:tier/top player token

Top of a league division

Parameters
  • key (path) League key.
  • tier (path) Division tier.
response
{
  "entries": [
    {
      "rank": 1,
      "player_id": "p_9"
    }
  ]
}
POST /v1/boards/:board/submit player token

Submit to a keyed board (team / UGC / custom entity)

Parameters
  • board (path) Keyed board key.
request
{
  "entity_id": "tm_1",
  "score": 5000
}
response
{
  "ok": true,
  "best_score": 5000
}
GET /v1/boards/:board/top player token

Top entries of a keyed board

Parameters
  • board (path) Keyed board key.
response
{
  "entries": [
    {
      "rank": 1,
      "entity_id": "tm_1",
      "score": 5000
    }
  ]
}
GET /v1/boards/:board/entries/:entity_id player token

One entity's keyed-board entry

Parameters
  • board (path) Keyed board key.
  • entity_id (path) Entity id (team/UGC/…).
response
{
  "entity_id": "tm_1",
  "score": 5000,
  "rank": 1
}

Progression

GET /v1/quests player token

List quests + the caller's progress

response
{
  "quests": [
    {
      "key": "daily_login",
      "progress": 1,
      "target": 1,
      "claimable": true
    }
  ]
}
POST /v1/quests/:key/claim player token

Claim a completed quest's reward

quest_not_complete if objectives aren't met; the reward is escrowed into the inbox.

Parameters
  • key (path) Quest key.
response
{
  "claimed": true
}
GET /v1/battle-pass/:season player token

Get battle-pass tiers + the caller's progress

Parameters
  • season (path) Season key.
response
{
  "season": "s1",
  "tier": 4,
  "xp": 1200,
  "premium": false
}
POST /v1/battle-pass/:season/claim player token

Claim a battle-pass tier reward

tier_not_earned if not reached; premium_required for a premium lane without the pass.

Parameters
  • season (path) Season key.
request
{
  "tier": 4,
  "lane": "free"
}
response
{
  "claimed": true
}
GET /v1/progression player token

Get XP / level curve progress

response
{
  "level": 7,
  "xp": 3400,
  "next_level_xp": 4000
}

Storage

GET /v1/storage/:collection player token

List keys in the player's collection

Parameters
  • collection (path) Collection key.
response
{
  "keys": [
    {
      "key": "settings",
      "version": 2
    },
    {
      "key": "deck",
      "version": 5
    }
  ]
}
GET /v1/storage/:collection/:key player token

Read a collection entry

Parameters
  • collection (path) Collection key.
  • key (path) Entry key.
response
{
  "value": {
    "sfx": true
  },
  "version": 2
}
PUT /v1/storage/:collection/:key player token

Write a collection entry

Optional If-Match for OCC (storage_conflict on a stale version).

Parameters
  • collection (path) Collection key.
  • key (path) Entry key.
request
{
  "data": {
    "sfx": false
  }
}
response
{
  "version": 3
}
DELETE /v1/storage/:collection/:key player token

Delete a collection entry

Parameters
  • collection (path) Collection key.
  • key (path) Entry key.
response · 204 No Content.
null
POST /v1/storage/:collection/:key/mutate player token

Atomic server-side mutation of an entry

Apply structured ops (e.g. list append, counter add) server-side to avoid read-modify-write races.

Parameters
  • collection (path) Collection key.
  • key (path) Entry key.
request
{
  "op": "append",
  "field": "deck",
  "value": "card_9"
}
response
{
  "value": {
    "deck": [
      "card_9"
    ]
  },
  "version": 5
}
GET /v1/storage/shared/:collection/:key player token

Read a shared (game-wide) entry

Parameters
  • collection (path) Collection key.
  • key (path) Entry key.
response
{
  "value": {
    "text": "Welcome!"
  },
  "version": 1
}
PUT /v1/storage/shared/:collection/:key player token

Write a shared entry (per the collection's write policy)

Parameters
  • collection (path) Collection key.
  • key (path) Entry key.
request
{
  "data": {
    "text": "Welcome!"
  }
}
response
{
  "key": "motd",
  "version": 1
}
GET /v1/storage/team/:teamId/:collection player token

List a team collection's keys (members only)

Parameters
  • teamId (path) Team id.
  • collection (path) Collection key.
response
{
  "keys": [
    "roster"
  ]
}
GET /v1/storage/team/:teamId/:collection/:key player token

Read a team entry

Parameters
  • teamId (path) Team id.
  • collection (path) Collection key.
  • key (path) Entry key.
response
{
  "key": "roster",
  "data": {}
}
PUT /v1/storage/team/:teamId/:collection/:key player token

Write a team entry (members only)

Parameters
  • teamId (path) Team id.
  • collection (path) Collection key.
  • key (path) Entry key.
request
{
  "data": {}
}
response
{
  "key": "roster",
  "version": 1
}
DELETE /v1/storage/team/:teamId/:collection/:key player token

Delete a team entry

Parameters
  • teamId (path) Team id.
  • collection (path) Collection key.
  • key (path) Entry key.
response · 204 No Content.
null

UGC

GET /v1/ugc player token

Browse published content

Parameters
  • sort (query) e.g. top, new.
response
{
  "items": [
    {
      "id": "ug_1",
      "title": "My Level",
      "plays": 42,
      "rating": 4.5
    }
  ]
}
GET /v1/ugc/mine player token

List the caller's content

response
{
  "items": [
    {
      "id": "ug_1",
      "title": "My Level",
      "status": "published"
    }
  ]
}
POST /v1/ugc player token

Create a draft

Title/content are moderated. Publish it with POST /v1/ugc/:id/submit.

request
{
  "title": "My Level",
  "data": {
    "grid": []
  }
}
response
{
  "id": "ug_1",
  "status": "draft"
}
GET /v1/ugc/:id player token

Get a content item

Parameters
  • id (path) Content id.
response
{
  "id": "ug_1",
  "title": "My Level",
  "data": {},
  "author": "p_1"
}
PATCH /v1/ugc/:id player token

Update a draft

Parameters
  • id (path) Content id.
request
{
  "title": "My Level v2"
}
response
{
  "id": "ug_1"
}
DELETE /v1/ugc/:id player token

Delete content

Parameters
  • id (path) Content id.
response · 204 No Content.
null
POST /v1/ugc/:id/submit player token

Publish a draft

Parameters
  • id (path) Content id.
response
{
  "id": "ug_1",
  "status": "published"
}
POST /v1/ugc/:id/play player token

Record a play

Parameters
  • id (path) Content id.
response
{
  "ok": true
}
GET /v1/ugc/:id/lineage player token

Get remix lineage (attribution)

Parameters
  • id (path) Content id.
response
{
  "ancestors": [
    {
      "id": "ug_0",
      "author": "p_0"
    }
  ]
}
POST /v1/ugc/:id/remix player token

Remix content (forks with attribution)

Parameters
  • id (path) Source content id.
request
{
  "title": "My Remix"
}
response
{
  "id": "ug_2",
  "remixed_from": "ug_1"
}
POST /v1/ugc/:id/rate player token

Rate content

Parameters
  • id (path) Content id.
request
{
  "rating": 5
}
response
{
  "ok": true,
  "rating": 4.6
}
POST /v1/ugc/:id/like player token

Like content

Parameters
  • id (path) Content id.
response
{
  "ok": true,
  "likes": 13
}
DELETE /v1/ugc/:id/like player token

Unlike content

Parameters
  • id (path) Content id.
response
{
  "ok": true,
  "likes": 12
}

Async

POST /v1/async player token

Create a turn-based match

No live connection needed — turns are submitted over HTTP with server-enforced turn order + optimistic concurrency.

request
{
  "type": "chess",
  "opponents": [
    "p_9"
  ]
}
response
{
  "match": {
    "id": "am_1",
    "state": {},
    "turn": "p_1a2b3c"
  }
}
GET /v1/async/mine player token

List the player's active matches

response
{
  "matches": [
    {
      "id": "am_1",
      "type": "chess",
      "turn": "p_9"
    }
  ]
}
GET /v1/async/:id player token

Get a match (participants only)

Parameters
  • id (path) Match id.
response
{
  "match": {
    "id": "am_1",
    "state": {},
    "turn_number": 4
  }
}
POST /v1/async/:id/turn player token

Submit a turn

Rejected with not_your_turn out of order, or async_conflict on a stale version (send the version you read).

Parameters
  • id (path) Match id.
request
{
  "state": {
    "board": []
  },
  "version": 4,
  "end": false
}
response
{
  "match": {
    "id": "am_1",
    "turn_number": 5
  }
}
POST /v1/async/:id/forfeit player token

Forfeit a match

Parameters
  • id (path) Match id.
response
{
  "match": {
    "id": "am_1",
    "status": "complete",
    "winner": "p_9"
  }
}

LiveOps

GET /v1/config publishable key

Get the game's published config blob

The developer's key→value tuning blob (server-controlled, no client deploy to change).

response
{
  "config": {
    "spawn_rate": 1.5,
    "event_banner": "summer"
  },
  "version": 12
}
GET /v1/flags player token

Get feature flags resolved for the player

Each flag resolves per the player's segments, with a break-glass kill switch honoured.

response
{
  "flags": {
    "new_hud": true,
    "checkout_v2": "variant_b"
  }
}
GET /v1/flags/:key player token

Get one resolved flag value

Parameters
  • key (path) Flag key.
response
{
  "key": "new_hud",
  "value": true
}
GET /v1/liveops/events/live player token

Get currently-live events

response
{
  "events": [
    {
      "key": "summer_fest",
      "ends_at": "2026-08-01T00:00:00Z"
    }
  ]
}
GET /v1/players/me/segments player token

Get the player's segment memberships

response
{
  "segments": [
    "whales",
    "new_players"
  ]
}

Experiments

POST /v1/experiments/:key/assign player token

Assign the player to a variant (sticky) + log exposure

Deterministic, sticky server-side bucketing — the same player always gets the same variant. Returns { variant: null, in_experiment: false } when the experiment is unknown, not running, or the player isn't targeted (treat as control).

Parameters
  • key (path) Experiment key.
response
{
  "key": "checkout_cta",
  "variant": "green",
  "in_experiment": true
}
POST /v1/experiments/:key/track player token

Record the player's conversion

Marks the enrolled player's first conversion. `metric` names the goal reached; it counts when it matches the experiment's measured metric (omit to match the primary one).

Parameters
  • key (path) Experiment key.
request
{
  "metric": "purchase"
}
response
{
  "ok": true,
  "counted": true
}

Push

GET /v1/push/vapid-key publishable key

Get the VAPID public key (applicationServerKey)

The key the browser needs to subscribe to Web Push. Pass its bytes as applicationServerKey to pushManager.subscribe (the SDK's tg.push.subscribe() does this).

response
{
  "key": "BEl…<base64url P-256 public key>"
}
POST /v1/push/subscribe player token

Register this device's push subscription

Body mirrors the browser's PushSubscription JSON. Refused for minors / age-unknown players — the behavioral_push compliance gate runs before the row is stored (403 age_restricted / parental_consent_required).

request
{
  "endpoint": "https://fcm.googleapis.com/fcm/send/abc…",
  "keys": {
    "p256dh": "BN…",
    "auth": "k9…"
  }
}
response
{
  "ok": true
}
POST /v1/push/unsubscribe player token

Remove this device's push subscription

request
{
  "endpoint": "https://fcm.googleapis.com/fcm/send/abc…"
}
response
{
  "ok": true
}

Analytics

POST /v1/events player token

Ingest analytics events

Usually called via the SDK's durable outbox (tg.track), which coalesces + retries. Counts only — no per-player PII.

request
{
  "events": [
    {
      "name": "level_complete",
      "count": 1
    }
  ]
}
response
{
  "accepted": 1
}

Dev · Games

POST /v1/dev/games developer session

Create a game

request
{
  "name": "Neon Drift"
}
response
{
  "id": "g_1",
  "name": "Neon Drift",
  "tier": "shared",
  "env": "prod"
}
GET /v1/dev/games developer session

List your games

response
{
  "games": [
    {
      "id": "g_1",
      "name": "Neon Drift",
      "status": "active"
    }
  ]
}
GET /v1/dev/games/:id developer session

Get a game

Parameters
  • id (path) Game id.
response
{
  "id": "g_1",
  "name": "Neon Drift",
  "allowed_origins": [
    "https://mygame.com"
  ]
}
PATCH /v1/dev/games/:id developer session

Update a game (name, CORS allowlist, pause)

Set allowed_origins (CORS) — an empty list is open to any origin. status paused takes the game offline.

Parameters
  • id (path) Game id.
request
{
  "allowed_origins": [
    "https://mygame.com"
  ],
  "status": "active"
}
response
{
  "id": "g_1",
  "allowed_origins": [
    "https://mygame.com"
  ]
}
DELETE /v1/dev/games/:id developer session

Delete a game (and its keys/data)

Parameters
  • id (path) Game id.
response · 204 No Content.
null
GET /v1/dev/me developer session

Get the developer account

response
{
  "id": "d_1",
  "email": "dev@studio.com"
}

Dev · Billing

GET /v1/dev/billing developer session

Get the current plan, subscription, and plan catalog

response
{
  "plan": "indie",
  "subscription": {
    "plan": "indie",
    "interval": "month",
    "status": "active",
    "cancel_at_period_end": false,
    "current_period_end": "2026-08-01T00:00:00Z"
  },
  "plans": [
    {
      "id": "dev",
      "name": "Dev",
      "priceMonthlyUsd": 5,
      "mauCap": 250
    }
  ]
}
POST /v1/dev/billing/checkout developer session

Start a checkout for a plan

Returns a provider checkout URL to send the buyer to. The payment provider is abstracted (a mock provider ships by default; swap it for a merchant-of-record without touching these routes).

request
{
  "plan": "indie",
  "interval": "month"
}
response
{
  "url": "https://app.triggair.com/billing/checkout?session=mock_cs_abc&plan=indie&interval=month",
  "provider": "mock"
}
POST /v1/dev/billing/subscribe developer session

Finalize a checkout into an active subscription

Applies the provider's outcome as the developer's active subscription. A real provider would instead drive this from a verified webhook.

request
{
  "plan": "indie",
  "interval": "month"
}
response
{
  "subscription": {
    "plan": "indie",
    "interval": "month",
    "status": "active"
  }
}
POST /v1/dev/billing/cancel developer session

Cancel the active subscription at period end

response
{
  "subscription": {
    "plan": "indie",
    "status": "active",
    "cancel_at_period_end": true
  }
}
POST /v1/billing/webhook/:provider no auth

Payment-provider webhook (subscription lifecycle)

Public endpoint a payment provider POSTs subscription events to; the provider module verifies the signature and normalizes the event. A no-op for the built-in mock provider.

Parameters
  • provider (path) Provider name, e.g. stripe.
response
{
  "ok": true
}

Dev · Keys

POST /v1/dev/games/:id/keys developer session

Issue an API key

The full secret is returned ONCE. tg_pk_ (publishable) is safe in clients; tg_sk_ (secret) is server-only.

Parameters
  • id (path) Game id.
request
{
  "kind": "publishable"
}
response
{
  "id": "key_1",
  "prefix": "tg_pk_ab12",
  "key": "tg_pk_ab12…full-shown-once",
  "note": "Store this now — it won't be shown again."
}
GET /v1/dev/games/:id/keys developer session

List key metadata (never the secret)

Parameters
  • id (path) Game id.
response
{
  "keys": [
    {
      "id": "key_1",
      "kind": "publishable",
      "prefix": "tg_pk_ab12",
      "last_used_at": "2026-07-01T00:00:00Z",
      "revoked_at": null
    }
  ]
}
POST /v1/dev/games/:id/keys/:keyId/rotate developer session

Rotate a key (revoke + mint a replacement)

Parameters
  • id (path) Game id.
  • keyId (path) Key id.
response
{
  "id": "key_2",
  "key": "tg_pk_cd34…full-shown-once"
}
DELETE /v1/dev/games/:id/keys/:keyId developer session

Revoke a key

Parameters
  • id (path) Game id.
  • keyId (path) Key id.
response · 204 No Content.
null

Dev · Access tokens

POST /v1/dev/tokens developer session

Mint a personal access token

Returns a `tg_pat_` token ONCE. It authenticates this developer for the whole management API (/v1/dev/*) and the MCP server, with full parity to a dashboard session — an agent or CI can create and configure games with it, no browser needed. Treat it like a password; only its hash is stored.

request
{
  "name": "ci-bot"
}
response · Store the token now — it won't be shown again.
{
  "id": "pat_1",
  "name": "ci-bot",
  "prefix": "tg_pat_ab12cd",
  "token": "tg_pat_ab12…full-shown-once",
  "created_at": "2026-07-15T00:00:00Z"
}
GET /v1/dev/tokens developer session

List access token metadata (never the token)

response
{
  "tokens": [
    {
      "id": "pat_1",
      "name": "ci-bot",
      "prefix": "tg_pat_ab12cd",
      "created_at": "2026-07-15T00:00:00Z",
      "last_used_at": "2026-07-15T01:00:00Z",
      "revoked_at": null
    }
  ]
}
DELETE /v1/dev/tokens/:id developer session

Revoke an access token

Parameters
  • id (path) Token id.
response · 204 No Content.
null

Dev · Leaderboards

GET /v1/dev/games/:id/leaderboards developer session

List leaderboard definitions

Parameters
  • id (path) Game id.
response
{
  "boards": [
    {
      "board": "high_scores",
      "aggregation": "best",
      "period": "all_time"
    }
  ]
}
PUT /v1/dev/games/:id/leaderboards/:board developer session

Create / update a leaderboard

Parameters
  • id (path) Game id.
  • board (path) Board key.
request
{
  "aggregation": "best",
  "period": "weekly",
  "higher_is_better": true
}
response
{
  "board": "high_scores"
}
DELETE /v1/dev/games/:id/leaderboards/:board developer session

Delete a leaderboard (scores cascade)

Parameters
  • id (path) Game id.
  • board (path) Board key.
response · 204 No Content.
null
POST /v1/dev/games/:id/leaderboards/:board/reset developer session

Reset a board's scores (keep the definition)

Wipe every score from the board while keeping its config. Use it to clean up after a verify/test run so exploratory submissions don't linger on a live board. Also exposed as the triggair_reset_leaderboard MCP tool.

Parameters
  • id (path) Game id.
  • board (path) Board key.
response
{
  "board": "high_scores",
  "cleared": 42
}
POST /v1/dev/games/:id/boards developer session

Create a keyed board (team/UGC/custom entity)

Parameters
  • id (path) Game id.
request
{
  "board_key": "team_wars",
  "entity_type": "team",
  "aggregation": "sum",
  "period": "weekly"
}
response
{
  "board_key": "team_wars"
}
GET /v1/dev/games/:id/boards developer session

List keyed boards

Parameters
  • id (path) Game id.
response
{
  "boards": [
    {
      "board_key": "team_wars",
      "entity_type": "team"
    }
  ]
}
DELETE /v1/dev/games/:id/boards/:board developer session

Delete a keyed board

Parameters
  • id (path) Game id.
  • board (path) Keyed board key.
response · 204 No Content.
null

Dev · Economy

GET /v1/dev/games/:id/economy/currencies developer session

List currencies

Parameters
  • id (path) Game id.
response
{
  "currencies": [
    {
      "code": "gold",
      "name": "Gold"
    }
  ]
}
POST /v1/dev/games/:id/economy/items developer session

Create / upsert an item

Parameters
  • id (path) Game id.
request
{
  "key": "sword",
  "name": "Sword",
  "stackable": false
}
response
{
  "key": "sword"
}
GET /v1/dev/games/:id/economy/items developer session

List items

Parameters
  • id (path) Game id.
response
{
  "items": [
    {
      "key": "sword"
    }
  ]
}
POST /v1/dev/games/:id/economy/stores developer session

Create / upsert a store

Parameters
  • id (path) Game id.
request
{
  "key": "main_store",
  "name": "Main Store",
  "listings": [
    {
      "item_id": "sword",
      "price": [
        {
          "currency": "gold",
          "amount": 100
        }
      ]
    }
  ]
}
response
{
  "key": "main_store"
}
GET /v1/dev/games/:id/economy/stores developer session

List stores

Parameters
  • id (path) Game id.
response
{
  "stores": [
    {
      "key": "main_store"
    }
  ]
}
POST /v1/dev/games/:id/economy/loot developer session

Create / upsert a loot box (with odds)

Parameters
  • id (path) Game id.
request
{
  "key": "bronze_box",
  "drops": [
    {
      "item": "common",
      "weight": 0.9
    },
    {
      "item": "rare",
      "weight": 0.1
    }
  ]
}
response
{
  "key": "bronze_box"
}
GET /v1/dev/games/:id/economy/loot developer session

List loot boxes

Parameters
  • id (path) Game id.
response
{
  "loot": [
    {
      "key": "bronze_box"
    }
  ]
}
POST /v1/dev/games/:id/economy/energy developer session

Create / upsert an energy meter

Parameters
  • id (path) Game id.
request
{
  "meter": "stamina",
  "max": 5,
  "refill_seconds": 600
}
response
{
  "meter": "stamina"
}
GET /v1/dev/games/:id/economy/energy developer session

List energy meters

Parameters
  • id (path) Game id.
response
{
  "meters": [
    {
      "meter": "stamina",
      "max": 5
    }
  ]
}
POST /v1/dev/games/:id/economy/grant developer session

Grant currency/items to a player (support tool)

Escrows the grant into the player's inbox (the one hardened grant path). Idempotent.

Parameters
  • id (path) Game id.
request
{
  "player_id": "p_9",
  "idempotency_key": "uuid",
  "bundle": {
    "currency": [
      {
        "code": "gold",
        "amount": 500
      }
    ]
  }
}
response
{
  "ok": true
}
GET /v1/dev/games/:id/economy/ledger developer session

Read the currency ledger

Parameters
  • id (path) Game id.
response
{
  "lines": [
    {
      "player_id": "p_9",
      "currency": "gold",
      "delta": 500
    }
  ]
}
GET /v1/dev/games/:id/economy/players/:pid/wallet developer session

Inspect a player's wallet

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "balances": [
    {
      "currency": "gold",
      "amount": 500
    }
  ]
}
GET /v1/dev/games/:id/economy/players/:pid/inventory developer session

Inspect a player's inventory

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "items": [
    {
      "item": "sword",
      "qty": 1
    }
  ]
}
POST /v1/dev/games/:id/economy/currencies developer session

Create / upsert a currency

Parameters
  • id (path) Game id.
request
{
  "code": "gold",
  "name": "Gold",
  "max": 999999
}
response
{
  "code": "gold"
}

Dev · Progression

GET /v1/dev/games/:id/achievements developer session

List achievement definitions

Parameters
  • id (path) Game id.
response
{
  "achievements": [
    {
      "key": "first_win",
      "target": 1
    }
  ]
}
DELETE /v1/dev/games/:id/achievements/:key developer session

Delete an achievement

Parameters
  • id (path) Game id.
  • key (path) Achievement key.
response · 204 No Content.
null
GET /v1/dev/games/:id/daily developer session

Get the daily-reward config

Parameters
  • id (path) Game id.
response
{
  "cycle_length": 7,
  "enabled": true
}
PUT /v1/dev/games/:id/daily developer session

Set the daily-reward config

Parameters
  • id (path) Game id.
request
{
  "cycle_length": 7,
  "rewards": [
    {
      "day": 1,
      "stats": [
        {
          "key": "gold",
          "amount": 50
        }
      ]
    }
  ]
}
response
{
  "enabled": true
}
DELETE /v1/dev/games/:id/daily developer session

Disable daily rewards

Parameters
  • id (path) Game id.
response · 204 No Content.
null
POST /v1/dev/games/:id/quests developer session

Create / upsert a quest

Parameters
  • id (path) Game id.
request
{
  "key": "win_3",
  "period": "weekly",
  "objectives": [
    {
      "stat": "wins",
      "target": 3
    }
  ]
}
response
{
  "key": "win_3"
}
GET /v1/dev/games/:id/quests developer session

List quests

Parameters
  • id (path) Game id.
response
{
  "quests": [
    {
      "key": "win_3"
    }
  ]
}
POST /v1/dev/games/:id/battle-pass developer session

Create / upsert a battle-pass season

Parameters
  • id (path) Game id.
request
{
  "season": "s1",
  "starts_at": "2026-07-01T00:00:00Z",
  "tiers": []
}
response
{
  "season": "s1"
}
GET /v1/dev/games/:id/battle-pass developer session

List battle-pass seasons

Parameters
  • id (path) Game id.
response
{
  "seasons": [
    {
      "season": "s1"
    }
  ]
}
POST /v1/dev/games/:id/progression developer session

Set the XP / level curve

Parameters
  • id (path) Game id.
request
{
  "xp_key": "xp",
  "base": 100,
  "growth": 1.5,
  "max_level": 50
}
response
{
  "max_level": 50
}
GET /v1/dev/games/:id/progression developer session

Get the level curve

Parameters
  • id (path) Game id.
response
{
  "base": 100,
  "growth": 1.5,
  "max_level": 50
}
PUT /v1/dev/games/:id/achievements/:key developer session

Create / update an achievement

Parameters
  • id (path) Game id.
  • key (path) Achievement key.
request
{
  "name": "First Win",
  "target": 1,
  "reward": {
    "stats": [
      {
        "key": "gold",
        "amount": 50
      }
    ]
  },
  "secret": false
}
response
{
  "key": "first_win"
}
POST /v1/dev/games/:id/battle-pass/:season/premium developer session

Configure a season's premium track

Parameters
  • id (path) Game id.
  • season (path) Season key.
request
{
  "price": {
    "gold": 1000
  }
}
response
{
  "ok": true
}

Dev · Competition

POST /v1/dev/games/:id/tournaments developer session

Schedule a tournament

Parameters
  • id (path) Game id.
request
{
  "key": "weekend_cup",
  "board": "high_scores",
  "starts_at": "2026-07-12T00:00:00Z",
  "ends_at": "2026-07-14T00:00:00Z",
  "reward_table": []
}
response
{
  "id": "to_1"
}
GET /v1/dev/games/:id/tournaments developer session

List tournaments

Parameters
  • id (path) Game id.
response
{
  "tournaments": [
    {
      "id": "to_1",
      "state": "live"
    }
  ]
}
POST /v1/dev/games/:id/tournaments/:tid/finalize developer session

Force-finalize a tournament (pays prizes)

Parameters
  • id (path) Game id.
  • tid (path) Tournament id.
response
{
  "finalized": true
}
POST /v1/dev/games/:id/leagues developer session

Create / upsert a league (tiered divisions)

Parameters
  • id (path) Game id.
request
{
  "key": "ranked",
  "divisions": [
    "bronze",
    "silver",
    "gold"
  ]
}
response
{
  "key": "ranked"
}
GET /v1/dev/games/:id/leagues developer session

List leagues

Parameters
  • id (path) Game id.
response
{
  "leagues": [
    {
      "key": "ranked"
    }
  ]
}
POST /v1/dev/games/:id/leagues/:key/advance developer session

Advance a league season (promotion/relegation)

Parameters
  • id (path) Game id.
  • key (path) League key.
response
{
  "advanced": true,
  "season": 2
}

Dev · LiveOps

GET /v1/dev/games/:id/config developer session

Get the config blob

Parameters
  • id (path) Game id.
response
{
  "config": {},
  "version": 12
}
PUT /v1/dev/games/:id/config developer session

Replace the config blob

Whole-blob replace (≤64 KB); bumps config_version. Served to clients at GET /v1/config.

Parameters
  • id (path) Game id.
request
{
  "config": {
    "spawn_rate": 1.5
  }
}
response
{
  "version": 13
}
GET /v1/dev/games/:id/events developer session

Read remote-event counters

Parameters
  • id (path) Game id.
response
{
  "events": [
    {
      "name": "level_complete",
      "count": 1240
    }
  ]
}
POST /v1/dev/games/:id/liveops/flags developer session

Create / upsert a feature flag

Parameters
  • id (path) Game id.
request
{
  "key": "new_hud",
  "type": "boolean",
  "default_value": true,
  "safe_value": false
}
response
{
  "key": "new_hud",
  "state": "on"
}
GET /v1/dev/games/:id/liveops/flags developer session

List feature flags

Parameters
  • id (path) Game id.
response
{
  "flags": [
    {
      "key": "new_hud",
      "state": "on"
    }
  ]
}
POST /v1/dev/games/:id/liveops/flags/:key/kill developer session

Break-glass: kill / restore a flag

Parameters
  • id (path) Game id.
  • key (path) Flag key.
request
{
  "on": true
}
response
{
  "key": "new_hud",
  "state": "killed"
}
POST /v1/dev/games/:id/liveops/segments developer session

Create / upsert a targeting segment

Parameters
  • id (path) Game id.
request
{
  "key": "whales",
  "definition": {
    "all": [
      {
        "stat": "coins",
        "op": ">=",
        "value": 1000
      }
    ]
  }
}
response
{
  "id": "sg_1",
  "key": "whales"
}
GET /v1/dev/games/:id/liveops/segments developer session

List segments

Parameters
  • id (path) Game id.
response
{
  "segments": [
    {
      "id": "sg_1",
      "key": "whales",
      "approx_size": 1200
    }
  ]
}
GET /v1/dev/games/:id/liveops/segments/:sid developer session

Get a segment's rule definition

Parameters
  • id (path) Game id.
  • sid (path) Segment id.
response
{
  "definition": {
    "all": [
      {
        "stat": "coins",
        "op": ">=",
        "value": 1000
      }
    ]
  }
}
POST /v1/dev/games/:id/liveops/segments/:sid/materialize developer session

Materialize a segment's membership

Parameters
  • id (path) Game id.
  • sid (path) Segment id.
response
{
  "size": 1200
}
POST /v1/dev/games/:id/liveops/code-campaigns developer session

Create a promo-code campaign

Parameters
  • id (path) Game id.
request
{
  "key": "launch",
  "reward": {
    "stats": [
      {
        "key": "gold",
        "amount": 100
      }
    ]
  },
  "max_redemptions": 1000
}
response
{
  "key": "launch"
}
GET /v1/dev/games/:id/liveops/code-campaigns developer session

List code campaigns

Parameters
  • id (path) Game id.
response
{
  "campaigns": [
    {
      "key": "launch",
      "redeemed": 42
    }
  ]
}
GET /v1/dev/games/:id/liveops/code-campaigns/:cid/redemptions developer session

List a campaign's redemptions

Parameters
  • id (path) Game id.
  • cid (path) Campaign id.
response
{
  "redemptions": [
    {
      "player_id": "p_9",
      "at": "2026-07-01T00:00:00Z"
    }
  ]
}
POST /v1/dev/games/:id/liveops/events developer session

Create / upsert a live event

Parameters
  • id (path) Game id.
request
{
  "key": "summer_fest",
  "starts_at": "2026-07-01T00:00:00Z",
  "ends_at": "2026-08-01T00:00:00Z"
}
response
{
  "key": "summer_fest"
}
GET /v1/dev/games/:id/liveops/events developer session

List live events

Parameters
  • id (path) Game id.
response
{
  "events": [
    {
      "key": "summer_fest"
    }
  ]
}
POST /v1/dev/games/:id/liveops/code-campaigns/:cid/generate developer session

Generate promo codes for a campaign

Parameters
  • id (path) Game id.
  • cid (path) Campaign id.
request
{
  "count": 100
}
response
{
  "codes": [
    "ABCD-1234"
  ]
}
POST /v1/dev/games/:id/liveops/segments/preview developer session

Preview a segment's size (dry-run)

Parameters
  • id (path) Game id.
request
{
  "definition": {
    "all": [
      {
        "stat": "coins",
        "op": ">=",
        "value": 1000
      }
    ]
  }
}
response
{
  "count": 1200
}

Dev · Experiments

POST /v1/dev/games/:id/experiments developer session

Create / upsert an A/B experiment

Variants carry relative weights (not percentages). status: only `running` assigns players. Optional target_segment_id enrols only that segment; metric_key names the conversion event measured.

Parameters
  • id (path) Game id.
request
{
  "key": "checkout_cta",
  "variants": [
    {
      "name": "blue",
      "weight": 1
    },
    {
      "name": "green",
      "weight": 1
    }
  ],
  "metric_key": "purchase",
  "status": "running"
}
response
{
  "experiment": {
    "key": "checkout_cta",
    "status": "running"
  }
}
GET /v1/dev/games/:id/experiments developer session

List experiments

Parameters
  • id (path) Game id.
response
{
  "experiments": [
    {
      "key": "checkout_cta",
      "status": "running",
      "metric_key": "purchase"
    }
  ]
}
GET /v1/dev/games/:id/experiments/:key developer session

Get one experiment (for editing)

Parameters
  • id (path) Game id.
  • key (path) Experiment key.
response
{
  "experiment": {
    "key": "checkout_cta",
    "variants": [
      {
        "name": "blue",
        "weight": 1
      },
      {
        "name": "green",
        "weight": 1
      }
    ]
  }
}
POST /v1/dev/games/:id/experiments/:key/status developer session

Start / pause / end an experiment

Parameters
  • id (path) Game id.
  • key (path) Experiment key.
request
{
  "status": "running"
}
response
{
  "experiment": {
    "key": "checkout_cta",
    "status": "running"
  }
}
GET /v1/dev/games/:id/experiments/:key/results developer session

Per-variant exposures, conversions & rate

Parameters
  • id (path) Game id.
  • key (path) Experiment key.
response
{
  "key": "checkout_cta",
  "results": [
    {
      "variant": "blue",
      "exposures": 980,
      "conversions": 74,
      "rate": 0.0755
    },
    {
      "variant": "green",
      "exposures": 1010,
      "conversions": 96,
      "rate": 0.095
    }
  ]
}

Dev · Push

POST /v1/dev/games/:id/push/send developer session

Send a Web Push notification to a cohort

Fans out to the target (all / a segment / one player), encrypting per subscription (RFC 8291) and signing VAPID (RFC 8292). Dead endpoints (404/410) are pruned. Requires VAPID configured on the deployment.

Parameters
  • id (path) Game id.
request
{
  "title": "Your daily reward is ready",
  "body": "Claim it before the streak resets.",
  "url": "https://yourgame.example/play",
  "target": {
    "type": "all"
  }
}
response
{
  "sent": 812,
  "failed": 3,
  "removed": 14,
  "targeted": 829
}
GET /v1/dev/games/:id/push/subscribers developer session

Count push subscribers

Parameters
  • id (path) Game id.
response
{
  "count": 829
}

Dev · Realtime

GET /v1/dev/games/:id/realtime developer session

Get realtime config

Parameters
  • id (path) Game id.
response
{
  "history_limit": 50
}
POST /v1/dev/games/:id/realtime developer session

Set realtime config (chat history retention)

history_limit = how many recent chat messages a room replays to a joiner (0–200; 0 opts out of history for high-frequency state rooms). Applied to new connections via the DO.

Parameters
  • id (path) Game id.
request
{
  "history_limit": 100
}
response
{
  "history_limit": 100
}

Dev · Moderation

POST /v1/dev/games/:id/moderation developer session

Set the moderation policy

Parameters
  • id (path) Game id.
request
{
  "custom_terms": [
    "voldemort"
  ],
  "allowlist": [
    "scunthorpe"
  ]
}
response
{
  "ok": true
}
GET /v1/dev/games/:id/moderation developer session

Get the moderation policy

Parameters
  • id (path) Game id.
response
{
  "customTerms": [
    "voldemort"
  ],
  "allowlist": [
    "scunthorpe"
  ]
}
POST /v1/dev/games/:id/moderation/check developer session

Dry-run moderate a string

Parameters
  • id (path) Game id.
request
{
  "surface": "chat",
  "text": "test a string"
}
response
{
  "verdict": "allow"
}
GET /v1/dev/games/:id/moderation/reports developer session

List content reports (review queue)

Parameters
  • id (path) Game id.
  • state (query) Filter by state.
response
{
  "reports": [
    {
      "id": "cr_1",
      "state": "open",
      "target_type": "player"
    }
  ]
}
GET /v1/dev/games/:id/moderation/reports/:rp developer session

Get a report

Parameters
  • id (path) Game id.
  • rp (path) Report id.
response
{
  "id": "cr_1",
  "state": "open"
}
POST /v1/dev/games/:id/moderation/reports/:rp/assign developer session

Assign / resolve a report

Parameters
  • id (path) Game id.
  • rp (path) Report id.
request
{
  "resolution": "warn"
}
response
{
  "state": "actioned"
}
GET /v1/dev/games/:id/moderation/audit developer session

Read the moderation audit feed

Parameters
  • id (path) Game id.
response
{
  "actions": [
    {
      "action": "ban",
      "actor": "p_1",
      "target_id": "p_9"
    }
  ]
}
GET /v1/dev/games/:id/moderation/players/:pid developer session

Get a player's moderation view

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "player_id": "p_9",
  "reports_against": [],
  "actions": []
}
POST /v1/dev/games/:id/moderation/players/:pid/ban developer session

Ban a player

Parameters
  • id (path) Game id.
  • pid (path) Player id.
request
{
  "kind": "permanent",
  "scope": "account",
  "reason": "cheating"
}
response
{
  "ok": true,
  "banned": true
}
POST /v1/dev/games/:id/moderation/players/:pid/unban developer session

Unban a player

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "ok": true,
  "lifted": true
}
POST /v1/dev/games/:id/moderation/players/:pid/unmute developer session

Unmute a player

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "ok": true,
  "lifted": true
}
GET /v1/dev/games/:id/moderation/appeals developer session

List ban appeals; decide grants/denies

Parameters
  • id (path) Game id.
response
{
  "appeals": [
    {
      "id": "ap_1",
      "state": "pending"
    }
  ]
}
POST /v1/dev/games/:id/moderation/players/:pid/mute developer session

Mute / restrict a player

Parameters
  • id (path) Game id.
  • pid (path) Player id.
request
{
  "effect": "mute",
  "expires_at": "2026-07-15T00:00:00Z"
}
response
{
  "ok": true
}
POST /v1/dev/games/:id/moderation/reports/:rp/resolve developer session

Resolve a report (warn / dismiss / duplicate)

Parameters
  • id (path) Game id.
  • rp (path) Report id.
request
{
  "resolution": "warn"
}
response
{
  "state": "actioned"
}
POST /v1/dev/games/:id/moderation/appeals/:ap/decide developer session

Decide a ban appeal (grant lifts the ban)

Parameters
  • id (path) Game id.
  • ap (path) Appeal id.
request
{
  "grant": true,
  "note": "first offense"
}
response
{
  "appeal": {
    "id": "ap_1",
    "state": "granted"
  }
}

Dev · Compliance

POST /v1/dev/games/:id/compliance developer session

Set the age-gate / COPPA policy

Parameters
  • id (path) Game id.
request
{
  "coppa_mode": false,
  "default_jurisdiction": "US",
  "gates": {
    "open_chat": "13_15",
    "lootbox": "adult"
  }
}
response
{
  "ok": true
}
GET /v1/dev/games/:id/compliance developer session

Get the compliance policy

Parameters
  • id (path) Game id.
response
{
  "coppa_mode": false,
  "gates": {}
}
GET /v1/dev/games/:id/compliance/players/:pid developer session

Inspect a player's compliance state

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "bracket": "13_15",
  "consent_state": "granted"
}

Dev · Analytics

GET /v1/dev/games/:id/analytics/metrics developer session

DAU/MAU/new-players/events by day

Parameters
  • id (path) Game id.
response
{
  "days": [
    {
      "day": "2026-07-01",
      "dau": 1200,
      "mau": 8000,
      "new_players": 90
    }
  ]
}
GET /v1/dev/games/:id/analytics/retention developer session

Cohort retention grid

Parameters
  • id (path) Game id.
response
{
  "cohorts": [
    {
      "day": "2026-07-01",
      "d1": 0.42,
      "d7": 0.18
    }
  ]
}
GET /v1/dev/games/:id/analytics/sessions developer session

Session counts + lengths

Parameters
  • id (path) Game id.
response
{
  "days": [
    {
      "day": "2026-07-01",
      "sessions": 3400,
      "avg_ms": 480000
    }
  ]
}
GET /v1/dev/games/:id/analytics/economy developer session

Per-currency sources/sinks/net (economy health)

Parameters
  • id (path) Game id.
response
{
  "currencies": [
    {
      "currency": "gold",
      "sources": 150,
      "sinks": 30,
      "net": 120
    }
  ]
}
POST /v1/dev/games/:id/analytics/funnels developer session

Define a funnel (ordered event list)

Parameters
  • id (path) Game id.
request
{
  "key": "onboarding",
  "steps": [
    "install",
    "tutorial",
    "first_purchase"
  ]
}
response
{
  "key": "onboarding"
}
GET /v1/dev/games/:id/analytics/funnels developer session

List funnels + their results

Parameters
  • id (path) Game id.
response
{
  "funnels": [
    {
      "key": "onboarding",
      "steps": [
        {
          "event": "install",
          "reached": 1000
        }
      ]
    }
  ]
}
DELETE /v1/dev/games/:id/analytics/funnels/:key developer session

Delete a funnel

Parameters
  • id (path) Game id.
  • key (path) Funnel key.
response · 204 No Content.
null
GET /v1/dev/games/:id/analytics/crashes developer session

List crash groups (open-first)

Parameters
  • id (path) Game id.
response
{
  "groups": [
    {
      "id": "cg_1",
      "title": "TypeError",
      "occurrences": 42,
      "status": "open"
    }
  ]
}
POST /v1/dev/games/:id/analytics/rollup developer session

Trigger an analytics rollup (manual)

Parameters
  • id (path) Game id.
response
{
  "ok": true
}
GET /v1/dev/games/:id/analytics/crashes/:group/daily developer session

A crash group's daily rate + crash-free %

Parameters
  • id (path) Game id.
  • group (path) Crash group id.
response
{
  "days": [
    {
      "day": "2026-07-01",
      "occurrences": 12,
      "crash_free": 0.98
    }
  ]
}
POST /v1/dev/games/:id/analytics/crashes/:group/status developer session

Set a crash group's status (open/resolved/ignored)

Parameters
  • id (path) Game id.
  • group (path) Crash group id.
request
{
  "status": "resolved"
}
response
{
  "ok": true
}
GET /v1/dev/games/:id/analytics/funnels/:key/results developer session

A funnel's per-step results

Parameters
  • id (path) Game id.
  • key (path) Funnel key.
response
{
  "steps": [
    {
      "event": "install",
      "reached": 1000,
      "conversion": 1
    },
    {
      "event": "tutorial",
      "reached": 660,
      "conversion": 0.66
    }
  ]
}

Dev · Storage

POST /v1/dev/games/:id/storage-collections developer session

Create / upsert a storage collection

Parameters
  • id (path) Game id.
request
{
  "key": "decks",
  "scope": "player",
  "read": "owner",
  "write": "owner",
  "max_bytes": 65536
}
response
{
  "key": "decks"
}
GET /v1/dev/games/:id/storage-collections developer session

List storage collections

Parameters
  • id (path) Game id.
response
{
  "collections": [
    {
      "key": "decks",
      "scope": "player"
    }
  ]
}
PUT /v1/dev/games/:id/storage/shared/:collection/:key developer session

Write a shared storage entry (developer)

Parameters
  • id (path) Game id.
  • collection (path) Collection key.
  • key (path) Entry key.
request
{
  "data": {
    "motd": "Season 2 is live!"
  }
}
response
{
  "key": "motd",
  "version": 2
}

Dev · Inbox

POST /v1/dev/games/:id/inbox developer session

Send an inbox message / announcement (optionally with a reward)

Parameters
  • id (path) Game id.
request
{
  "audience": "all",
  "kind": "announcement",
  "body": {
    "text": "Season 2 is live!"
  },
  "rewards": {
    "stats": [
      {
        "key": "gold",
        "amount": 100
      }
    ]
  }
}
response
{
  "sent": 8000
}

Dev · Usage

GET /v1/dev/games/:id/usage developer session

Get this month's usage vs quota

Parameters
  • id (path) Game id.
response
{
  "month": "2026-07",
  "players": 8000,
  "ops": {
    "saves": 320,
    "leaderboards": 145
  }
}

Dev · Verify

POST /v1/dev/games/:id/verify developer session

Run a server-side integration self-test

Live-probes player → save → leaderboard → CORS in-process and reports pass/fail per service with fixes.

Parameters
  • id (path) Game id.
response
{
  "ok": true,
  "services": [
    {
      "name": "saves",
      "status": "pass"
    }
  ]
}

Admin

GET /v1/admin/me operator session

Get the signed-in operator

response
{
  "id": "op_1",
  "email": "ops@triggair.com",
  "role": "owner"
}
GET /v1/admin/developers operator session

List developers (cross-tenant)

Parameters
  • limit (query) Page size.
  • offset (query) Offset.
response
{
  "developers": [
    {
      "id": "d_1",
      "email": "dev@x.com",
      "plan": "indie",
      "games": 2,
      "mau": 8000
    }
  ]
}
GET /v1/admin/developers/:id operator session

Get a developer (subscription + games)

Parameters
  • id (path) Developer id.
response
{
  "developer": {
    "id": "d_1",
    "email": "dev@x.com",
    "status": "active"
  },
  "subscription": {
    "plan": "indie"
  },
  "games": []
}
GET /v1/admin/developers/:id/usage operator session

Get a developer's usage this month (MAU vs cap, ops)

Parameters
  • id (path) Developer id.
response
{
  "month": "2026-07",
  "plan": "indie",
  "mau": {
    "used": 812,
    "cap": 2000
  },
  "ops": {
    "used": 145233
  }
}
PUT /v1/admin/developers/:id/subscription operator session

Set a developer's plan (operator grant)

Grants an active subscription directly (a comp or support grant), bypassing the payment provider. Audited with the plan + interval.

Parameters
  • id (path) Developer id.
request
{
  "plan": "studio",
  "interval": "year"
}
response
{
  "subscription": {
    "plan": "studio",
    "interval": "year",
    "status": "active",
    "provider": "operator"
  }
}
DELETE /v1/admin/developers/:id/subscription operator session

Cancel a developer's subscription

Parameters
  • id (path) Developer id.
response
{
  "subscription": {
    "plan": "studio",
    "status": "active",
    "cancel_at_period_end": true
  }
}
GET /v1/admin/games operator session

List games (cross-tenant)

response
{
  "games": [
    {
      "id": "g_1",
      "name": "Neon Drift",
      "developer_id": "d_1",
      "players": 42
    }
  ]
}
GET /v1/admin/games/:id operator session

Get a game (metadata + key metadata + counts)

Key metadata only — never a hash/secret. Every operator read is audited.

Parameters
  • id (path) Game id.
response
{
  "game": {
    "id": "g_1",
    "tier": "shared",
    "status": "active"
  },
  "keys": [
    {
      "prefix": "tg_pk_ab12",
      "kind": "publishable"
    }
  ],
  "players": 42,
  "ops": 525
}
GET /v1/admin/audit operator session

Read the operator audit trail

Parameters
  • limit (query) Page size.
response
{
  "entries": [
    {
      "action": "developer.read",
      "actor_email": "ops@triggair.com",
      "created_at": "2026-07-01T00:00:00Z"
    }
  ]
}
POST /v1/admin/games/:id/suspend operator session

Suspend a game (takes it dark at the edge)

Parameters
  • id (path) Game id.
request
{
  "reason": "ToS abuse"
}
response
{
  "id": "g_1",
  "status": "suspended"
}
POST /v1/admin/games/:id/unsuspend operator session

Unsuspend a game

Parameters
  • id (path) Game id.
response
{
  "id": "g_1",
  "status": "active"
}
POST /v1/admin/developers/:id/suspend operator session

Suspend a developer (cascades to all their games)

Parameters
  • id (path) Developer id.
request
{
  "reason": "account abuse"
}
response
{
  "id": "d_1",
  "status": "suspended"
}
POST /v1/admin/developers/:id/unsuspend operator session

Unsuspend a developer

Parameters
  • id (path) Developer id.
response
{
  "id": "d_1",
  "status": "active"
}
POST /v1/admin/games/:id/keys/:keyId/revoke operator session

Revoke a leaked key (incident lever)

Parameters
  • id (path) Game id.
  • keyId (path) Key id.
response · 204 No Content.
null
GET /v1/admin/games/:id/players/:pid/moderation operator session

Cross-tenant player moderation view

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "player_id": "p_9",
  "reports_against": [],
  "actions": []
}
POST /v1/admin/games/:id/players/:pid/ban operator session

Ban a player (cross-tenant)

Parameters
  • id (path) Game id.
  • pid (path) Player id.
request
{
  "kind": "permanent",
  "reason": "cheating"
}
response
{
  "ok": true,
  "banned": true
}
POST /v1/admin/games/:id/players/:pid/unban operator session

Unban a player

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "ok": true,
  "lifted": true
}
POST /v1/admin/games/:id/players/:pid/mute operator session

Mute a player

Parameters
  • id (path) Game id.
  • pid (path) Player id.
request
{
  "effect": "mute"
}
response
{
  "ok": true
}
POST /v1/admin/games/:id/players/:pid/unmute operator session

Unmute a player

Parameters
  • id (path) Game id.
  • pid (path) Player id.
response
{
  "ok": true,
  "lifted": true
}
GET /v1/admin/games/:id/moderation/appeals operator session

List ban appeals (cross-tenant)

Parameters
  • id (path) Game id.
response
{
  "appeals": [
    {
      "id": "ap_1",
      "state": "pending"
    }
  ]
}
POST /v1/admin/games/:id/moderation/appeals/:ap/decide operator session

Decide a ban appeal

Parameters
  • id (path) Game id.
  • ap (path) Appeal id.
request
{
  "grant": true
}
response
{
  "appeal": {
    "id": "ap_1",
    "state": "granted"
  }
}
POST /v1/admin/developers/:id/impersonate operator session

Mint a developer impersonation token

Returns a session-lived token to act AS the developer (full read/write) on /v1/dev/*, for support. Audited.

Parameters
  • id (path) Developer id.
response
{
  "token": "eyJ…",
  "developer": {
    "id": "d_1",
    "email": "dev@x.com"
  },
  "expires_at": "2026-07-11T00:00:00Z"
}

Docs & meta

GET /openapi.json no auth

This OpenAPI 3.1 definition

response
{
  "openapi": "3.1.0"
}
GET /llms.txt no auth

Agent index (concise integration guide)

GET /llms-full.txt no auth

Full agent integration guide

GET /dropin no auth

Copy-paste Drop-In prompt

GET /docs/errors/:code no auth

Per-error-code fix doc

Parameters
  • code (path) Error code.
GET /status no auth

Liveness + resolved game/env echo

response
{
  "status": "ok",
  "game_id": null,
  "env": "prod"
}
GET /healthz no auth

Health check

GET /time no auth

Authoritative server time (for client clocks)

response
{
  "now": "2026-07-10T00:00:00Z",
  "epoch_ms": 1783000000000
}

Dev · Emails

GET /v1/dev/games/:id/email-templates developer session

Get the effective account-email templates

Returns every email type (signup, recovery, email_change, magiclink, invite, reauthentication) with its effective template — the customization if one exists, else the built-in default — plus the placeholder reference. See the 'Customizing account emails' guide.

Parameters
  • id (path) Game id.
response
{
  "templates": {
    "signup": {
      "label": "Confirm signup",
      "customized": false,
      "subject": "Confirm your email for {{GameName}}",
      "html": "<div>…</div>",
      "updated_at": null
    }
  },
  "placeholders": [
    {
      "token": "ConfirmationURL",
      "description": "The action link."
    }
  ]
}
PUT /v1/dev/games/:id/email-templates/:type developer session

Customize one account email

Set the subject + HTML for one email type. The HTML is sanitized to a safe email subset on save (sanitize-and-store-clean); the response reports what was `removed` and any author `warnings` (e.g. a missing action placeholder). Idempotent per (game, type).

Parameters
  • id (path) Game id.
  • type (path) signup | recovery | email_change | magiclink | invite | reauthentication
request
{
  "subject": "Confirm your email for {{GameName}}",
  "html": "<p>Welcome! <a href=\"{{ConfirmationURL}}\">Confirm</a>.</p>"
}
response
{
  "template": {
    "email_type": "signup",
    "subject": "Confirm your email for {{GameName}}",
    "html": "<p>…</p>",
    "updated_at": "2026-07-18T00:00:00Z"
  },
  "removed": [],
  "warnings": []
}
DELETE /v1/dev/games/:id/email-templates/:type developer session

Reset one account email to the default

Deletes the customization for one email type; that type reverts to the built-in default. Returns the default that will now be used.

Parameters
  • id (path) Game id.
  • type (path) The email type to reset.
response
{
  "ok": true,
  "type": "signup",
  "default": {
    "subject": "…",
    "html": "<div>…</div>"
  }
}

MCP

POST /v1/mcp developer session

Model Context Protocol endpoint (streamable HTTP, JSON-RPC 2.0)

The agent-facing management surface: the triggair_* tools (configure games/boards/economy/flags/moderation/compliance, verify_integration, search_docs) over the Web-standard streamable-HTTP MCP transport, stateless JSON mode. Point an MCP client (Cursor, Claude, …) here with your developer session token as `Authorization: Bearer <jwt>`. Tool calls run in-process against your own games — ownership is enforced exactly as on /v1/dev/*.

request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}
response · JSON-RPC result
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "triggair_list_games"
      }
    ]
  }
}