> ## Documentation Index
> Fetch the complete documentation index at: https://docs.d-sports.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Game Engine API

> Additive catalog and session verbs for the modular mini-game engine. Published in OpenAPI.

## Scope

This guide is the HTTP contract for `/api/v1/engage/games/*`. It is additive to the public [Games catalog](/api-reference/domains/games). Do not replace `GET /api/games/catalog` with the engine catalog. Clients that already consume the unversioned route keep working.

Deep dives: [Game Engine overview](/repositories/game-engine/index) · [Client](/repositories/game-engine/client) · [Server](/repositories/game-engine/server) · [Modularity](/repositories/game-engine/modularity)

## Coverage

Status: **Publish**.

These operations are in generated OpenAPI under the `Game Engine` tag (also tagged `Games` and `Engage`). They landed in [d-sports-api#536](https://github.com/D-Sports-Ecosystem/d-sports-api/pull/536). Use the **Endpoints** group for request/response playgrounds.

## Endpoints

| Method | Path                                                          | Auth   | Notes                                                                                                                                                                                                                                                   |
| ------ | ------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/api/v1/engage/games/catalog`                                | Public | Query `teamId` or `teamSlug`. Omit both for the platform catalogue. `X-Client-Version` is optional on the wire. Returns `{ daily, weekly }` groups of catalog rows that include `playable` and `reason`.                                                |
| `POST` | `/api/v1/engage/games/{gameKey}/session`                      | Bearer | Start or resume the current UTC day slot (`dayKey`). Body `{ teamId?, leaderboardId? }`.                                                                                                                                                                |
| `POST` | `/api/v1/engage/games/{gameKey}/session/{sessionId}/action`   | Bearer | `{ input, sequenceNumber? }`. Server returns `{ outcome, session? }`. If `session` is omitted, keep the session you already have. OpenAPI models `input` and `outcome` as `anyOf` (named prize-wheel / guess-the-player schemas plus a generic object). |
| `POST` | `/api/v1/engage/games/{gameKey}/session/{sessionId}/complete` | Bearer | Settles awarded points / Rep, or returns `PENDING_RESOLUTION` when the result is still outstanding.                                                                                                                                                     |
| `POST` | `/api/v1/engage/games/{gameKey}/session/{sessionId}/forfeit`  | Bearer | `{ reason }`.                                                                                                                                                                                                                                           |

`locker-singularity` does not use those session verbs. Its progression is an idle ledger under `/api/v1/engage/games/locker-singularity/ledger`. The catalog still lists the game (`playable: true` while the `Game` row is `LIVE`). Ledger routes serve a `COMING_SOON` row normally. A missing `Game` row returns `404 GAME_UNKNOWN` and does not create a ledger.

| Method | Path                                             | Auth   | Notes                                                                                                                                                                                                                    |
| ------ | ------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET`  | `/api/v1/engage/games/locker-singularity/ledger` | Bearer | First read creates the row. Later reads credit offline buzz from the server `lastSeenAt` only (8 hour cap at 50% efficiency). Client timestamps are ignored. Returns `{ ledger, accruedBuzz, cappedHours, lastSeenAt }`. |
| `POST` | `.../ledger/taps`                                | Bearer | `{ tapCount, idempotencyKey }`. `tapCount` is an integer ≥ 1. Values above 100 are clamped (`acceptedTaps` 100). Abuse returns `429 IDLE_TAP_RATE_LIMITED` with `Retry-After`.                                           |
| `POST` | `.../ledger/buy`                                 | Bearer | `{ generatorId, quantity, idempotencyKey }`. `quantity` is 1–100. Generators: `rookie-card`, `foam-finger-stand`, `zamboni-fleet`, `banner-press`.                                                                       |
| `POST` | `.../ledger/upgrades`                            | Bearer | `{ nodeId, idempotencyKey }`. Costs 1–3 Playbooks. Unknown or already-owned nodes return `400`. Insufficient Playbooks return `409 IDLE_INSUFFICIENT_BUZZ`.                                                              |
| `POST` | `.../ledger/prestige`                            | Bearer | `{ idempotencyKey }`. Requires `lifetimeBuzz` ≥ 1,000,000 or `409 IDLE_PRESTIGE_NOT_ELIGIBLE`.                                                                                                                           |
| `POST` | `.../ledger/boosts/claim`                        | Bearer | Disabled in v1. Valid body still returns `410 BOOST_DISABLED` and does not touch the ledger.                                                                                                                             |

Buzz counters on the wire are decimal strings. These routes write toy currencies only. They do not change DSC balances, Rep, `PointsHistory`, pack inventory, or marketplace state.

Mutations require a UUID v4 `idempotencyKey`. Replaying the same key returns the stored response. The same key with a different body returns `400` and does not credit twice.

Send optional `X-Client-Version` on ledger reads and on taps, buy, upgrades, and prestige. Below `minClientVersion` those routes return `403 GAME_UPDATE_REQUIRED`. The boost claim route does not apply that gate.

Send `Authorization: Bearer <Clerk token>` on session verbs and on ledger routes.

`X-Client-Version` is optional in OpenAPI. If you build a supported Engage native client, send it on every engine call. If a game has `minClientVersion` and the header is missing or unparseable, the catalog marks the row `UPDATE_REQUIRED` and session start returns `403 GAME_UPDATE_REQUIRED`. If `minClientVersion` is unset, an absent header does not block play.

Session start returns:

* `403 GAME_UPDATE_REQUIRED` when the binary is below `minClientVersion`
* `404 GAME_UNKNOWN` for an unknown key
* `409 GAME_DAILY_NOT_ELIGIBLE` when the current UTC day slot is already used

## Client rules

* Render **awarded** Rep after complete, not `requested`.
* Treat `GAME_UPDATE_REQUIRED` as an update wall. Treat `GAME_DAILY_NOT_ELIGIBLE` as already played.
* Reject scenario payloads that leak answers (`correctIndex`, `resolutionKey`, `answer`).
* Do not call `/api/v1/engage/rep/earn` from a playfield. Awards are server-side.

## Not in this guide

* `GET /api/games/catalog` and legacy play routes — [Games API](/api-reference/domains/games)
* Game Center schedule and realtime — `/api/events/*`
* Admin catalog management — redacted
* Cron settlement — excluded
* Deprecated `POST /api/games/daily-spin/reward` — excluded
