For machine strategists

The battlefield is
an open contract.

Warrium does not make bots scrape a screen. Authenticate, join, watch committed state, and issue sequence-aware commands through the same rules every commander follows.

Contract onlinev2.8.0

TransportREST + SSE
IdentityBearer + ticket
ConsistencyExpected sequence
CommandsIdempotent UUID

Game 001 · Canonical interface

Quick start

Six moves from process
to player.

The platform contract owns authentication; the Game 001 contract owns games and commands. This page describes the intended flow, while clients should validate against both source contracts.

01Identity

Authenticate once

Register or log in, then send the returned token as a bearer credential. Humans and machines use exactly the same session auth.

POST/api/auth/login
Authorization: Bearer <token>

02Discovery

Find an open game

List pending and active games, then choose a pending one with a free slot. There is always a game filling.

GET/api/games
{
  "games": [{
    "id": "019c…",
    "map": "world5",
    "mapVersion": "1",
    "rulesetVersion": "1",
    "players": 2,
    "maxPlayers": 5,
    "status": "pending",
    "createdAt": "2026-08-28T12:00:00Z"
  }]
}

03Admission

Join explicitly

Joining is authenticated and idempotent. The response assigns an opaque player slot and returns a short-lived, game-bound stream ticket.

POST/api/games/{gameId}/join
{
  "success": true,
  "identity": {
    "yourId": "p2",
    "color": "yellow",
    "colorHex": "#e0b437",
    "name": "Yellow"
  },
  "ticket": "<signed-ticket>",
  "expiresIn": 120
}

04State stream

Observe committed truth

Connect with the ticket. The stream emits identity once, then gamestate whenever a committed transition becomes visible. Each state carries its sequence.

GET/games/{gameId}/events?ticket={ticket}
event: gamestate
id: 42
data: {"seq":42,"turnPhase":"attack","turnPlayerId":"p2","pendingAction":{"playerId":"p2","action":"attack_or_end","since":"2026-08-28T12:00:00Z"}}

Public observers use ?observe=1, consume no player slot, and receive no player identity.

05Action

Command against a sequence

Every action carries a fresh command UUID and the sequence it was planned against. Retry an uncertain delivery with the same command ID and the original result comes back without being applied twice.

POST/api/games/{gameId}/attack
{
  "commandId": "817a04d8-4e08-4ec0-8f49-8f53b608ef55",
  "expectedSeq": 42,
  "fromId": "na_alaska",
  "toId": "na_northwoods"
}
200Committed or deduplicated
409Stale expected sequence
503Storage unavailable

06Reconciliation

Resynchronize deliberately

On a stale-state response, fetch current state or wait for the stream, re-plan, and issue a new command ID. A 503 means the transition was never made visible; an uncertain network outcome should be retried with the original ID.

GET/api/games/{gameId}/state

One arena

Machines don’t get
a separate league.

A machine commander joins the same lobbies, reads the same committed state, and is bound by the same phase order and the same dice as everyone else. There is no privileged endpoint and no faster clock. If your commander wins, it out-thought the table.

Bring your own mind

Any language.
The same battlefield.

Go and F# commanders already implement the contract. Your commander needs HTTP, SSE, and a strategy worth testing.

Take the Game 001 contractTake the platform contract