Skip to main content

CPU battles API

The CPU battles API runs a private match between the authenticated player and a server-controlled deck. The server snapshots both decks, validates actions, chooses CPU actions, enforces turn deadlines, and records the final result.

See CPU battles for the player journey and Battle rules for combat rules.

Access and response version​

All routes require bearer authentication and an active player account. Include the current response capability on match and history requests:

Accept: application/vnd.wits-world.cpu.v2+json, application/json;q=0.9

This projection includes voluntary swaps and Creature identifiers in battle-log events. Older clients receive the previous projection, which omits those newer fields. Use identifiers and legal actions from the same current response.

Routes​

Routes below begin with /api/v1.

MethodRoutePurpose
POST/matches/cpuCreate a match from the selected saved deck.
GET/matches/cpu/entryRead the small active-match dashboard projection.
GET/matches/cpuRecover the player's active match.
GET/matches/:matchIdRead one owned CPU match.
POST/matches/:matchId/actionsSubmit one intended player action.
POST/matches/:matchId/forfeitEnd an active match as a CPU victory.
GET/matches/historyList the player's completed CPU matches.

Creation returns 201; other successful operations return 200. Responses include requestId. Match reads return only matches owned by the caller.

Create and recover a match​

Create with { "deckId": "…" }. The saved deck must be owned, active for battle, and valid when the server snapshots it. Later catalogue or saved-deck changes do not rewrite the match.

A player may have only 1 active CPU match. Creation has no idempotency key. If its response is uncertain, use GET /matches/cpu to recover the committed match before trying to create another. No active match returns 404 CPU_MATCH_NOT_FOUND; an immediate not-found cannot rule out a creation request that is still in flight.

Use /matches/cpu/entry for a dashboard check that needs only matchId, status, start time, phase, turn number, and current side. Use /matches/cpu or the identified match route before presenting battle choices.

For a compact landing-page read, use /matches/cpu/entry?view=summary. It returns nullable activeMatch and selectedDeck, plus requestId. An active match makes selectedDeck null; otherwise the selected deck contains only deckId and name. Empty state returns 200 with both values null. This read does not validate the deck, create a match, or advance gameplay.

Use /matches/history?view=summary&limit=5 for completed headers with roundCount, without full rounds, actions, or battle state. limit defaults to 5 and accepts integers from 1 to 20 when view=summary is supplied. Results sort by completion time descending, then match ID descending. Omitting view retains the existing full-history response; open a match for its detailed log.

Match state and actions​

A full match response includes matchId, status, version, outcome and lifecycle timestamps, state with legalActions, lastAction, and battleLog. The player sees their snapshotted cards. The CPU projection reveals its active and defeated Creatures and remaining counts without exposing its unrevealed reserve.

Submit an action with the current version and a caller-generated command ID:

{
"submissionId": "00000000-0000-0000-0000-000000000010",
"expectedVersion": 3,
"action": {
"type": "use_move",
"moveId": "00000000-0000-0000-0000-000000000020"
}
}

Supported action types are select_initial_creature, select_replacement, swap_creature, use_move, and use_power_card. Use the corresponding creatureId, moveId, or powerCardId from legalActions. The server rechecks the match version and legality; a returned action is not a reservation.

After applying the player's intent, the server performs any required CPU actions and returns the resulting committed state. A normal player turn has a 90-second deadline. If an action arrives at or after that deadline, the server records the authoritative timeout instead of the submitted move. Initial selection and mandatory replacement have no turn deadline.

Retries and forfeiting​

Use a new submissionId for each intended battle action. Retry an uncertain action with the same identifier, version, and action body. An identical replay returns its saved response without advancing the match again. A replay can be older than the latest match state, so fetch the match before choosing another action.

Reusing a submission ID with a different version or intent returns 409 CPU_MATCH_IDEMPOTENCY_CONFLICT. Ordinary stale versions return 409 CPU_MATCH_STALE_ACTION; reload rather than automatically changing and resubmitting the choice.

Forfeit with { "expectedVersion": 3 }. Forfeit has no submission ID. If its response is uncertain, read the match: a completed CPU win confirms the result; an active match supplies the version to review before another request. Forfeit records progression once and cannot reopen the match.

Errors and recovery​

ResponseCaller action
400 INVALID_MATCH_DECKRepair or select a valid saved deck before creating a match.
400 ILLEGAL_CPU_MATCH_ACTIONReload and choose from the current legal actions.
404 CPU_MATCH_NOT_FOUNDTreat the match as unavailable; this also protects ownership privacy.
409 CPU_MATCH_ALREADY_ACTIVERecover the existing match instead of creating another.
409 CPU_MATCH_COMPLETEDFetch and display the saved final result.
409 CPU_MATCH_STALE_ACTIONReload the match and review its current version and choices.
409 CPU_MATCH_IDEMPOTENCY_CONFLICTKeep the used command ID attached to its original version and intent.

GET /matches/history returns the completed CPU archive. Completed results and logs remain based on their saved snapshots; they are not recalculated from later deck, catalogue, or rules changes. See CPU battle storage for transaction and retention details.

AI declaration​

Prepared with assistance from Codex[GPT-6], using CPU match routes, response capabilities, action receipts, and recovery behaviour.