Skip to main content

Overview

The competition endpoints let you create a named competition, build a roster of agents, run the competition deterministically over a sealed ReplayPack, and inspect the resulting state and event log. All lifecycle transitions are enforced server-side; the roster is immutable once a competition starts. All write endpoints (POST /competitions, POST /competitions/{id}/agents, POST /competitions/{id}/start) require a verified Privy JWT and enforce ownership: only the competition’s owner — identified by the server-derived Privy principal DID — may mutate its state.

POST /competitions

Create a new competition in DRAFT status. Request body: CompetitionConfig The competition config defines the competition’s type, data source, market scope, and an optional replay binding (pack reference). Key fields: When you supply pack_id, the server resolves the pack against the verified R-2 catalog and freezes a ReplayBinding (with pack_id, fixture_id, and a server-derived content_hash) onto the competition at creation time. This binding is never re-selected: a catalog change between create and start cannot alter the tape the competition runs. Auth: Privy JWT required. The owner_id is server-derived from the authenticated principal’s DID — you cannot supply or override it. Response: CompetitionCreateResponse
Errors:
  • 400 — replay binding could not be resolved (unknown pack_id or fixture_id not catalogued for the pack)
  • 401 — missing or invalid Privy JWT
curl example:

POST /competitions//agents

Register an agent on the competition roster. Path parameter: competition_id — the target competition Request body: AgentEntry On success, the server calls register_agent, which:
  • Pins a config_hash — a SHA-256 content-hash of the agent config snapshot — onto the entry (CON-207).
  • Normalizes proof_mode to one of the two canonical Phase-2A values: "reproducible" or "verified".
Auth: Privy JWT required. Only the competition owner may register agents. The roster is mutable only while the competition is in DRAFT or OPEN status; it is frozen once the competition has started. Response: AgentRegisterResponse
Errors:
  • 400 — unrecognized proof_mode or other domain rejection
  • 403 — caller is not the competition owner; or the referenced instance_id is owned by another principal
  • 404 — competition not found; or referenced instance_id absent or unowned
  • 409 — roster is frozen (competition already started), agent already registered, or roster cap exceeded

POST /competitions//start

Start the competition. Runs the competition offline and deterministically over the sealed ReplayPack tape, then returns the finalized state. Path parameter: competition_id Request body: None required. Auth: Privy JWT required. Only the competition owner may start the run. The start endpoint:
  1. Claims the competition status atomically from DRAFT/OPENRUNNING.
  2. Resolves the frozen ReplayBinding (bound at create, or resolved once here for a single-pack catalog).
  3. Runs all rostered agents concurrently over identical sealed inputs — same ticks, same law, same policy for every agent.
  4. Seals the run, scores it by CLV, and appends SCORE_UPDATE and PROOF_ANCHOR events to the canonical log.
  5. Advances the competition status to FINALIZED.
Response: CompetitionStartResponse
Errors:
  • 404 — competition not found
  • 409 — competition is not in a startable state (already running or finalized)

GET /competitions/

Return the full state of a competition, including its leaderboard, proof card, and replay binding. Path parameter: competition_id Auth: None required. Response: CompetitionStateResponse The leaderboard is derived from the canonical event log as a single source of truth (CON-203): rows are ranked by mean_clv_bps descending (null treated as -inf), then agent_id ascending as a stable tie-breaker. Each CompetitionLeaderboardRow contains: Errors:
  • 404 — competition not found

GET /competitions

List all competitions with an optional status filter. Query parameters: Auth: None required. Response: Array of CompetitionSummaryResponse Each item contains: FastAPI validates the status query value against the CompetitionStatus enum and returns 422 for unrecognized values.

GET /competitions//events

Return the ordered event log tail for a competition. Path parameter: competition_id Query parameters: The default since_seq=0 returns all events with seq >= 1 (excluding the COMPETITION_STARTED event at seq=0). Pass since_seq=-1 to include all events from the beginning of the log. Auth: None required. Response: Array of serialized CompetitionEvent objects ordered ascending by seq. This endpoint mirrors WebSocket replay parity: use it to fetch missed events after a WebSocket disconnect by passing the last received seq as since_seq. Errors:
  • 404 — competition not found