</> codebattle / api v1
Feeding this to an LLM? Use /api-docs.md: the same docs as plain Markdown.

Codebattle Public API v1

A small, me-centric HTTP API for bots, CLIs, editors and devices: see your live game and history, start games against Codebot or a friend, join open games from the lobby, join tournaments and run your own.

Quickstart

  1. Open Settings → API tokens on codebattle and create a token. Copy it right away: it is shown only once and looks like cbp_....
  2. Call the API with the token in the Authorization header:
export CODEBATTLE_TOKEN=cbp_your_token_here

curl -s https://codebattle.hexlet.io/public_api/v1/me \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"
{"user": {"id": 42, "name": "ada", "avatar_url": null, "rating": 1461, "rank": 12, "lang": "dlang"}}
  1. Start a game against Codebot (needs the games:write scope) and watch it:
curl -s -X POST https://codebattle.hexlet.io/public_api/v1/games \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"level": "easy", "opponent": "bot"}'

curl -s https://codebattle.hexlet.io/public_api/v1/me/active_game \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

You solve the task in the browser at the game url; the API tells you what is going on.

The same from Ruby, without gems. Note the explicit Content-Type: without it Net::HTTP sends the body as a form and the API answers 415.

require "net/http"
require "json"

uri = URI("https://codebattle.hexlet.io/public_api/v1/games")
req = Net::HTTP::Post.new(uri, "Authorization" => "Bearer #{ENV["CODEBATTLE_TOKEN"]}",
                               "Content-Type" => "application/json")
req.body = {level: "easy", opponent: "bot"}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)

Authentication

Every request needs a personal token in the header (query parameters are never accepted):

Authorization: Bearer cbp_...

A token belongs to one user, acts as that user and carries scopes:

Scope Allows
read All GET endpoints
games:write Create, join and cancel games; send, accept and cancel invites; join and leave tournaments
tournaments:write Create, edit, start and cancel your tournaments

Conventions

Pagination

GET /me/games uses keyset (cursor) pagination, which stays correct while new games keep arriving:

  1. Request the first page without cursor: you get up to 50 games, newest first, and next_cursor.
  2. Pass next_cursor back as cursor to get the next, older page.
  3. next_cursor: null means there are no more pages.

The cursor is simply the id of the last game on the page. To get games from a period instead of walking pages, use from and to (ISO 8601 dates or datetimes, by game start time). They combine with cursor if a period has more than 50 games.

curl -s "https://codebattle.hexlet.io/public_api/v1/me/games?from=2026-10-01&to=2026-10-08" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

The tournament ranking for creators and moderators uses page / page_size instead.

Errors

Every error has the same shape:

{"error": {"code": "validation_failed", "message": "Invalid parameters: level is required", "details": {"level": "is required"}}}

For validation_failed, message lists every failed field and details maps each field to what is wrong with it, for programs.

HTTP code Meaning
401 unauthorized No Authorization: Bearer header
401 invalid_token The token is unknown, expired or revoked
403 insufficient_scope The token lacks the scope this endpoint needs
404 not_found Missing, or not related to you
415 unsupported_media_type A request body sent without Content-Type: application/json
422 validation_failed Bad or unknown parameters, or an action not allowed in the current state
429 rate_limited Too many requests, see below
429 quota_exceeded Too many games or tournaments created
503 api_disabled The API (or its write operations) is temporarily switched off

Event stream

GET /me/events is a live stream of everything that happens to you, delivered as Server-Sent Events (SSE). It is an ordinary HTTP request that stays open: the server keeps writing events into the response as they happen. Use it instead of polling to react to invites, game starts and tournament rounds within a second.

curl -sN https://codebattle.hexlet.io/public_api/v1/me/events \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Accept: text/event-stream"

Wire format

The response is text/event-stream. Each event is a few field: value lines followed by a blank line; data is always one line of JSON with a server_time:

id: 1791702012345
event: invite.created
data: {"invite":{"id":9001,"direction":"incoming","creator":{"id":77,"name":"grace","rating":1520,"avatar_url":null},...},"server_time":"2026-10-11T07:00:12Z"}

: ping

Lifecycle

  1. You connect and immediately get hello with your current state.
  2. Events arrive as things happen.
  3. After an hour the server sends bye and closes the stream. Reconnect right away.
  4. If the connection drops for any other reason, reconnect after a few seconds.

At most 2 streams per user can be open at the same time; a third request gets 429 rate_limited.

Events

Event When Payload (data)
hello Right after connecting user (Player), active_game (Game or null), invites (Invite[]), tournaments (unfinished Tournament[] you play in or run)
invite.created Someone invited you, or you sent an invite invite
invite.accepted An invite between you and someone was accepted invite with game_id, game_url
invite.canceled Declined by the recipient or withdrawn by the creator invite
invite.dropped Dropped because one of you started another game invite
game.created You created a game that waits for an opponent game
game.started A game with you started: against a bot, from an invite, someone joined your game, or a tournament round paired you game
game.finished Your game ended (game_over or timeout); results are visible game
game.canceled Your game was canceled before it finished game
tournament.joined You joined a tournament tournament
tournament.left You left a tournament tournament
tournament.player_joined Someone joined a tournament you created or moderate tournament, player (Player)
tournament.player_left Someone left a tournament you created or moderate tournament, player_id
tournament.started A tournament you play in or run started tournament
tournament.round_started A new round began; your game arrives as game.started tournament
tournament.round_finished A round ended; tournament.break.active and ends_at tell when the next round starts tournament
tournament.finished The tournament is over tournament
tournament.canceled The tournament was canceled tournament
tournament.restarted An admin restarted the tournament tournament
bye The server is closing the stream; reconnect reason

game, tournament and invite have the same fields as in the REST endpoints (see Objects). New event types may appear in v1; skip the ones you don't know.

Clients

Ruby, standard library only:

require "net/http"
require "json"

uri = URI("https://codebattle.hexlet.io/public_api/v1/me/events")

loop do
  Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 45) do |http|
    req = Net::HTTP::Get.new(uri, "Authorization" => "Bearer #{ENV["CODEBATTLE_TOKEN"]}",
                                  "Accept" => "text/event-stream")
    http.request(req) do |res|
      buffer = +""
      res.read_body do |chunk|
        buffer << chunk
        while (block = buffer.slice!(/\A.*?\n\n/m))
          name = block[/^event: (.+)$/, 1]
          data = block[/^data: (.+)$/, 1]
          next unless name && data # pings and retry hints

          event = JSON.parse(data)
          case name
          when "invite.created"
            puts "Invite from #{event["invite"]["creator"]["name"]}" if event["invite"]["direction"] == "incoming"
          when "game.started"
            system("firefox", "--kiosk", event["game"]["url"])
          end
        end
      end
    end
  end
rescue StandardError => e
  warn "stream dropped: #{e.message}"
ensure
  sleep 3
end

Python with requests:

import json, os, time, requests

URL = "https://codebattle.hexlet.io/public_api/v1/me/events"
HEADERS = {"Authorization": f"Bearer {os.environ['CODEBATTLE_TOKEN']}", "Accept": "text/event-stream"}

while True:
    try:
        with requests.get(URL, headers=HEADERS, stream=True, timeout=(10, 45)) as res:
            name = None
            for line in res.iter_lines(decode_unicode=True):
                if line.startswith("event: "):
                    name = line[7:]
                elif line.startswith("data: ") and name:
                    print(name, json.loads(line[6:]))
                elif line == "":
                    name = None
    except requests.RequestException as error:
        print("stream dropped:", error)
    time.sleep(3)

JavaScript (Node 18+ or a browser; EventSource can't send the Authorization header, so read the stream with fetch):

const res = await fetch("https://codebattle.hexlet.io/public_api/v1/me/events", {
  headers: { Authorization: `Bearer ${process.env.CODEBATTLE_TOKEN}`, Accept: "text/event-stream" },
});
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
let buffer = "";
for (;;) {
  const { value, done } = await reader.read();
  if (done) break; // reconnect here
  buffer += value;
  let end;
  while ((end = buffer.indexOf("\n\n")) >= 0) {
    const block = buffer.slice(0, end);
    buffer = buffer.slice(end + 2);
    const name = block.match(/^event: (.+)$/m)?.[1];
    const data = block.match(/^data: (.+)$/m)?.[1];
    if (name && data) console.log(name, JSON.parse(data));
  }
}

If your environment can't keep a connection open (some corporate proxies, cron jobs), use long polling on GET /me/invites?wait=25 instead, or poll the REST endpoints.

Limits

Limits are per user, shared by all of the user's tokens.

What Limit
Requests 60 per minute. Responses carry x-ratelimit-limit and x-ratelimit-remaining
404 responses More than 30 in 10 minutes blocks the API for an hour
Games created 5 per minute, 30 per day
Tournaments created 5 per day, at most 3 unfinished at a time
Event streams 2 open at a time; each lives up to an hour

Polling GET /me/active_game every 5–10 seconds fits comfortably in the limit, but the event stream is better: one connection, events within a second.

Recipes

Device that vibrates 10 minutes before the end of a game. Listen to the event stream: on game.started store game.ends_at - server_time as the remaining time and count down locally; game.finished or game.canceled stops the countdown. (Without a stream, poll GET /me/active_game.)

Join an open game from the lobby. List the games waiting for an opponent, pick one and join it (needs games:write):

curl -s "https://codebattle.hexlet.io/public_api/v1/games/live?state=waiting_opponent" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" | jq '.games[] | {id, level, timeout_seconds, players}'

curl -s -X POST https://codebattle.hexlet.io/public_api/v1/games/12345/join \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

The game starts at once: open its url. The task of an open game is hidden until someone joins. You can play one game at a time; if you are in another one, the join answers 422 with details.reason already_in_a_game and details.active_game_id: finish that game, or cancel it with POST /games/{id}/cancel while it still waits for an opponent. To wait for someone to join your own game instead, create one with {"opponent": "link"} and share its join_url.

Join a tournament without keeping its page open. Find it in GET /tournaments/schedule (or GET /tournaments/live) and join it (needs games:write); for a private tournament pass the access_token from its invite_url:

curl -s -X POST https://codebattle.hexlet.io/public_api/v1/tournaments/777/join \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

curl -s -X POST https://codebattle.hexlet.io/public_api/v1/tournaments/778/join \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"access_token": "from_the_invite_url"}'

The card comes back with joined: true (joining twice is fine). Now listen to the event stream and open the browser only on game.started: its game.url is your first game. A phone saves a lot of battery compared with a tournament tab open for ten minutes before the start. Changed your mind? POST /tournaments/{id}/leave works until the start. A failed join answers 422 with details.reason: not_open, full or not_running.

Bot that runs a private tournament. POST /tournaments with name, description, starts_at, level, send players the returned invite_url, then POST /tournaments/{id}/start when everyone has joined, and read GET /tournaments/{id}/ranking.

React to invites when you can't hold a stream open. The event stream is the first choice. Without it, long-poll GET /me/invites:

version=""
while true; do
  resp=$(curl -s "https://codebattle.hexlet.io/public_api/v1/me/invites?wait=25&version=$version" \
    -H "Authorization: Bearer $CODEBATTLE_TOKEN")
  version=$(echo "$resp" | jq -r .version)
  echo "$resp" | jq '.invites[] | select(.direction == "incoming")'
done

The request returns as soon as the list changes (or after 25 s), so a new invite shows up within a second at about two requests a minute. Accept it with POST /invites/{id}/accept and open game_url.

One voice command to a private tournament. POST /tournaments with your preset of fields, show invite_url as a QR code (the tournament page has a "Show QR" button too), wait for tournament.player_joined on the event stream, then POST /tournaments/{id}/start and open the game from the game.started event.

A game on a chosen task. List the tasks of a level with GET /tasks?level=medium (add tags=strings,math or name=partition to narrow it), then pass the id or the exact name: POST /games with {"task_name": "minimal_time_partition", "opponent": "bot"}. The level comes from the task. Invites take the same task_id / task_name. You only see and can pick public tasks and your own.

Export your history. Walk GET /me/games with cursor until next_cursor is null, or ask for one period with from / to.

Endpoints

All paths are relative to https://codebattle.hexlet.io/public_api/v1.

Method Path What it does Scope
GET /me Current user read
GET /me/active_game Current live game (null if none). Count down with ends_at - server_time. read
GET /me/games My finished games, newest first read
GET /me/tournaments Tournaments I created, moderate or play read
GET /me/invites My pending invites, incoming and outgoing read
GET /me/events Live stream of everything that happens to you (SSE) read
GET /tournaments/schedule Public upcoming and active tournaments for the next 14 days read
GET /tournaments/live Tournaments running now or open for joining read
POST /tournaments Create a private tournament (always grade open, tasks by level) tournaments:write
GET /tournaments/{id} Tournament card: related to you, or public and scheduled read
PATCH /tournaments/{id} Edit your tournament before it starts tournaments:write
GET /tournaments/{id}/ranking Ranking: full and paginated for the creator/moderators, top 20 plus your row for participants read
POST /tournaments/{id}/start Start your tournament tournaments:write
POST /tournaments/{id}/cancel Cancel your tournament tournaments:write
POST /tournaments/{id}/join Join a tournament as a player games:write
POST /tournaments/{id}/leave Leave a tournament before it starts games:write
GET /tasks Tasks you can play read
GET /games/live Live games read
POST /games Create a game: against a bot, or waiting for an opponent who joins by link games:write
POST /games/{id}/join Join a game that waits for an opponent games:write
POST /games/{id}/cancel Cancel your game that waits for an opponent games:write
POST /invites Invite a user to a game games:write
POST /invites/{id}/accept Accept an invite sent to you games:write
POST /invites/{id}/cancel Decline or withdraw an invite games:write
GET /users/online Who is online read

Me

GET/me

Current user

Who the token belongs to. A cheap way to check that a token works.

Scope: read

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/me" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "user": {
    "id": 42,
    "name": "ada",
    "avatar_url": "https://avatars.githubusercontent.com/u/1?v=4",
    "rating": 1461,
    "rank": 12,
    "lang": "dlang"
  }
}

Errors: 401, 403, 404, 429

GET/me/active_game

Current live game (null if none). Count down with ends_at - server_time.

Your live game, or null: the one you are playing, or one you created that still waits for an opponent (state: waiting_opponent). Poll it (every few seconds is fine) to notice a game started from the web or by a tournament. Compute the remaining time as ends_at - server_time, not against your own clock.

Scope: read

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/me/active_game" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "game": {
    "id": 324274,
    "url": "https://codebattle.hexlet.io/games/324274",
    "state": "playing",
    "level": "easy",
    "type": "duo",
    "starts_at": "2026-10-10T18:40:00Z",
    "timeout_seconds": 600,
    "ends_at": "2026-10-10T18:50:00Z",
    "finishes_at": null,
    "tournament_id": null,
    "task": {
      "id": 1201,
      "name": "pair_with_maximum_product",
      "level": "easy",
      "tags": [
        "collections"
      ],
      "visibility": "public",
      "url": "https://codebattle.hexlet.io/tasks/1201"
    },
    "players": [
      {
        "id": 42,
        "name": "ada",
        "avatar_url": null,
        "rating": 1461,
        "rank": 12,
        "lang": "python",
        "is_bot": false,
        "result": null,
        "result_percent": 60.0
      },
      {
        "id": -1,
        "name": "Codebot",
        "avatar_url": null,
        "rating": 1200,
        "rank": null,
        "lang": "js",
        "is_bot": true,
        "result": null
      }
    ]
  },
  "server_time": "2026-10-10T18:43:20Z"
}

Errors: 401, 403, 404, 429

GET/me/games

My finished games, newest first

Finished games (game_over or timeout), 50 per page, newest first. Pagination is keyset-based: next_cursor is the id of the last game on the page; pass it back as cursor to get the next, older page. next_cursor is null on the last page. from/to narrow the result by game start time and combine with cursor.

Scope: read

Query parameters

Name Type Description
cursor integer next_cursor from the previous page: returns games with a smaller id.
from datetime Only games started at or after this moment. ISO 8601 date (2026-10-01, midnight UTC) or datetime.
to datetime Only games started before this moment. ISO 8601 date or datetime.

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/me/games?from=2026-10-01&to=2026-10-10T18:00:00Z" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "games": [
    {
      "id": 324274,
      "url": "https://codebattle.hexlet.io/games/324274",
      "state": "game_over",
      "level": "easy",
      "type": "duo",
      "starts_at": "2026-10-10T18:40:00Z",
      "timeout_seconds": 600,
      "ends_at": "2026-10-10T18:50:00Z",
      "finishes_at": "2026-10-10T18:46:12Z",
      "tournament_id": null,
      "task": {
        "id": 1201,
        "name": "pair_with_maximum_product",
        "level": "easy",
        "tags": [
          "collections"
        ],
        "visibility": "public",
        "url": "https://codebattle.hexlet.io/tasks/1201"
      },
      "players": [
        {
          "id": 42,
          "name": "ada",
          "avatar_url": null,
          "rating": 1461,
          "rank": 12,
          "lang": "python",
          "is_bot": false,
          "result": "won",
          "result_percent": 100.0
        },
        {
          "id": -1,
          "name": "Codebot",
          "avatar_url": null,
          "rating": 1200,
          "rank": null,
          "lang": "js",
          "is_bot": true,
          "result": "lost",
          "result_percent": 40.0
        }
      ]
    }
  ],
  "next_cursor": 324100
}

Errors: 401, 403, 404, 422, 429

GET/me/tournaments

Tournaments I created, moderate or play

Up to 50 tournaments you created, moderate or joined as a player, newest first.

Scope: read

Query parameters

Name Type Description
state string Filter by state, e.g. active or finished.

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/me/tournaments" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tournaments": [
    {
      "id": 5775,
      "name": "Friday practice",
      "url": "https://codebattle.hexlet.io/tournaments/5775",
      "type": "swiss",
      "state": "active",
      "level": "easy",
      "grade": "open",
      "access_type": "token",
      "starts_at": "2026-10-10T19:00:00Z",
      "started_at": "2026-10-10T19:00:04Z",
      "players_count": 8,
      "players_limit": 16,
      "rounds_limit": 3,
      "current_round": {
        "position": 1,
        "started_at": "2026-10-10T19:12:00Z",
        "ends_at": "2026-10-10T19:22:00Z"
      },
      "break": {
        "active": false,
        "ends_at": null
      },
      "access_token": "Xy7pQw2LmN4rTz8aB",
      "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
    }
  ]
}

Errors: 401, 403, 404, 429

GET/me/invites

My pending invites, incoming and outgoing

Pending invites where you are the creator or the recipient. Supports long polling instead of frequent polls: pass wait (seconds, up to 30) and the version from your previous response. If the list already differs from that version the answer is immediate; otherwise the request is held until an invite is created, accepted or canceled, or until wait runs out, and then returns the current list. Loop on it to react to invites within a second with about two requests a minute. An accepted invite leaves the list; the creator finds the game via GET /me/active_game.

Scope: read

Query parameters

Name Type Description
wait integer Hold the request up to this many seconds (0..30) while nothing changes.
version string version from the previous response.

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/me/invites?wait=25&version=1x3kq9" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "invites": [
    {
      "id": 9001,
      "state": "pending",
      "direction": "incoming",
      "level": "easy",
      "timeout_seconds": 600,
      "creator": {
        "id": 77,
        "name": "grace",
        "avatar_url": null,
        "rating": 1520
      },
      "recipient": {
        "id": 42,
        "name": "ada",
        "avatar_url": null,
        "rating": 1461
      },
      "game_id": null,
      "game_url": null,
      "created_at": "2026-10-10T19:01:00Z"
    }
  ],
  "version": "1x3kq9",
  "server_time": "2026-10-10T19:01:05Z"
}

Errors: 401, 403, 404, 422, 429

GET/me/events

Live stream of everything that happens to you (SSE)

A Server-Sent Events stream: one request that stays open. It starts with hello (your current state: active game, pending invites, unfinished tournaments), then sends one event per change: invites, your games, tournaments you play in or run. A : ping comment comes every 15 seconds. The server closes the stream after an hour with a bye event; reconnect and you get a fresh hello. At most 2 open streams per user. See Event stream above for every event and client examples.

Scope: read

Example request

curl -sN "https://codebattle.hexlet.io/public_api/v1/me/events" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Accept: text/event-stream"

Response 200 (text/event-stream, stays open)

retry: 3000

id: 1791702000000
event: hello
data: {"user":{"id":42,"name":"ada",...},"active_game":null,"invites":[],"tournaments":[],"server_time":"2026-10-11T07:00:00Z"}

id: 1791702012345
event: invite.created
data: {"invite":{"id":9001,"direction":"incoming","creator":{"id":77,"name":"grace",...},...},"server_time":"2026-10-11T07:00:12Z"}

: ping

id: 1791702020000
event: game.started
data: {"game":{"id":324274,"state":"playing","url":"https://codebattle.hexlet.io/games/324274",...},"server_time":"2026-10-11T07:00:20Z"}

Errors: 401, 403, 429

Tournaments

GET/tournaments/schedule

Public upcoming and active tournaments for the next 14 days

Public tournaments that start between 1 day ago and 14 days ahead and are not finished yet: what the lobby shows as upcoming. For everything running right now use GET /tournaments/live.

Scope: read

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/tournaments/schedule" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tournaments": [
    {
      "id": 5775,
      "name": "Friday practice",
      "url": "https://codebattle.hexlet.io/tournaments/5775",
      "type": "swiss",
      "state": "active",
      "level": "easy",
      "grade": "open",
      "access_type": "token",
      "starts_at": "2026-10-10T19:00:00Z",
      "started_at": "2026-10-10T19:00:04Z",
      "players_count": 8,
      "players_limit": 16,
      "rounds_limit": 3,
      "current_round": {
        "position": 1,
        "started_at": "2026-10-10T19:12:00Z",
        "ends_at": "2026-10-10T19:22:00Z"
      },
      "break": {
        "active": false,
        "ends_at": null
      },
      "access_token": "Xy7pQw2LmN4rTz8aB",
      "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
    }
  ]
}

Errors: 401, 403, 404, 429

GET/tournaments/live

Tournaments running now or open for joining

Currently running tournament processes in waiting_participants or active state: public ones plus private ones you created, moderate or play in. Uses live state and participant counts, excluding abandoned database records. A running tournament can have an old starts_at. Newest first, at most 100.

Scope: read

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/tournaments/live" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tournaments": [
    {
      "id": 5775,
      "name": "Friday practice",
      "url": "https://codebattle.hexlet.io/tournaments/5775",
      "type": "swiss",
      "state": "active",
      "level": "easy",
      "grade": "open",
      "access_type": "token",
      "starts_at": "2026-10-10T19:00:00Z",
      "started_at": "2026-10-10T19:00:04Z",
      "players_count": 8,
      "players_limit": 16,
      "rounds_limit": 3,
      "current_round": {
        "position": 1,
        "started_at": "2026-10-10T19:12:00Z",
        "ends_at": "2026-10-10T19:22:00Z"
      },
      "break": {
        "active": false,
        "ends_at": null
      },
      "access_token": "Xy7pQw2LmN4rTz8aB",
      "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
    }
  ]
}

Errors: 401, 403, 404, 429

POST/tournaments

Create a private tournament (always grade open, tasks by level)

Creates a private (access_type: token) tournament of grade open; tasks are picked by level. Share invite_url with players. Quota: 5 per day and at most 3 unfinished API-created tournaments.

Scope: tournaments:write

Request body

Field Type Description
name (required) string 3..100 characters
description (required) string 3..2000 characters
starts_at (required) datetime In the future, at most 30 days ahead
level (required) string One of elementary, easy, medium, hard
players_limit integer 2..64
rounds_limit integer 1..10
timeout_mode string One of per_task, per_round_fixed
match_timeout_seconds integer 60..3600
round_timeout_seconds integer 60..3600
break_duration_seconds integer 0..600
use_chat boolean

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/tournaments" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"ada","description":"Weekly practice for our team","starts_at":"2026-10-10T19:03:18Z","level":"elementary"}'

Response 201

{
  "tournament": {
    "id": 5775,
    "name": "Friday practice",
    "url": "https://codebattle.hexlet.io/tournaments/5775",
    "type": "swiss",
    "state": "active",
    "level": "easy",
    "grade": "open",
    "access_type": "token",
    "starts_at": "2026-10-10T19:00:00Z",
    "started_at": "2026-10-10T19:00:04Z",
    "players_count": 8,
    "players_limit": 16,
    "rounds_limit": 3,
    "current_round": {
      "position": 1,
      "started_at": "2026-10-10T19:12:00Z",
      "ends_at": "2026-10-10T19:22:00Z"
    },
    "break": {
      "active": false,
      "ends_at": null
    },
    "access_token": "Xy7pQw2LmN4rTz8aB",
    "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
  }
}

Errors: 401, 403, 404, 415, 422, 429

GET/tournaments/{id}

Tournament card: related to you, or public and scheduled

Works for tournaments related to you and for public ones. The creator and moderators also get access_token and invite_url.

Scope: read

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/tournaments/123" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tournament": {
    "id": 5775,
    "name": "Friday practice",
    "url": "https://codebattle.hexlet.io/tournaments/5775",
    "type": "swiss",
    "state": "active",
    "level": "easy",
    "grade": "open",
    "access_type": "token",
    "starts_at": "2026-10-10T19:00:00Z",
    "started_at": "2026-10-10T19:00:04Z",
    "players_count": 8,
    "players_limit": 16,
    "rounds_limit": 3,
    "current_round": {
      "position": 1,
      "started_at": "2026-10-10T19:12:00Z",
      "ends_at": "2026-10-10T19:22:00Z"
    },
    "break": {
      "active": false,
      "ends_at": null
    },
    "access_token": "Xy7pQw2LmN4rTz8aB",
    "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
  }
}

Errors: 401, 403, 404, 429

PATCH/tournaments/{id}

Edit your tournament before it starts

Only the fields you send change. Allowed while the tournament is upcoming or waiting_participants.

Scope: tournaments:write

Request body

Field Type Description
name string 3..100 characters
description string 3..2000 characters
starts_at datetime In the future, at most 30 days ahead
level string One of elementary, easy, medium, hard
players_limit integer 2..64
rounds_limit integer 1..10
timeout_mode string One of per_task, per_round_fixed
match_timeout_seconds integer 60..3600
round_timeout_seconds integer 60..3600
break_duration_seconds integer 0..600
use_chat boolean

Example request

curl -s -X PATCH "https://codebattle.hexlet.io/public_api/v1/tournaments/123" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

Response 200

{
  "tournament": {
    "id": 5775,
    "name": "Friday practice",
    "url": "https://codebattle.hexlet.io/tournaments/5775",
    "type": "swiss",
    "state": "active",
    "level": "easy",
    "grade": "open",
    "access_type": "token",
    "starts_at": "2026-10-10T19:00:00Z",
    "started_at": "2026-10-10T19:00:04Z",
    "players_count": 8,
    "players_limit": 16,
    "rounds_limit": 3,
    "current_round": {
      "position": 1,
      "started_at": "2026-10-10T19:12:00Z",
      "ends_at": "2026-10-10T19:22:00Z"
    },
    "break": {
      "active": false,
      "ends_at": null
    },
    "access_token": "Xy7pQw2LmN4rTz8aB",
    "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
  }
}

Errors: 401, 403, 404, 415, 422, 429

GET/tournaments/{id}/ranking

Ranking: full and paginated for the creator/moderators, top 20 plus your row for participants

The creator and moderators get the full ranking with page / page_size (max 100). Participants get the top 20 and their own row in me.

Scope: read

Query parameters

Name Type Description
page integer
page_size integer

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/tournaments/123/ranking" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "ranking": [
    {
      "id": 42,
      "name": "ada",
      "place": 1,
      "score": 42,
      "lang": "python"
    }
  ],
  "me": {
    "id": 42,
    "name": "ada",
    "place": 1,
    "score": 42,
    "lang": "python"
  },
  "page_info": {
    "page_number": 1,
    "page_size": 1,
    "total_entries": 1
  }
}

Errors: 401, 403, 404, 429

POST/tournaments/{id}/start

Start your tournament

Starts your tournament now with the players who have joined.

Scope: tournaments:write

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/tournaments/123/start" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tournament": {
    "id": 5775,
    "name": "Friday practice",
    "url": "https://codebattle.hexlet.io/tournaments/5775",
    "type": "swiss",
    "state": "active",
    "level": "easy",
    "grade": "open",
    "access_type": "token",
    "starts_at": "2026-10-10T19:00:00Z",
    "started_at": "2026-10-10T19:00:04Z",
    "players_count": 8,
    "players_limit": 16,
    "rounds_limit": 3,
    "current_round": {
      "position": 1,
      "started_at": "2026-10-10T19:12:00Z",
      "ends_at": "2026-10-10T19:22:00Z"
    },
    "break": {
      "active": false,
      "ends_at": null
    },
    "access_token": "Xy7pQw2LmN4rTz8aB",
    "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
  }
}

Errors: 401, 403, 404, 422, 429

POST/tournaments/{id}/cancel

Cancel your tournament

Cancels your tournament and finishes its games.

Scope: tournaments:write

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/tournaments/123/cancel" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tournament": {
    "id": 5775,
    "name": "Friday practice",
    "url": "https://codebattle.hexlet.io/tournaments/5775",
    "type": "swiss",
    "state": "active",
    "level": "easy",
    "grade": "open",
    "access_type": "token",
    "starts_at": "2026-10-10T19:00:00Z",
    "started_at": "2026-10-10T19:00:04Z",
    "players_count": 8,
    "players_limit": 16,
    "rounds_limit": 3,
    "current_round": {
      "position": 1,
      "started_at": "2026-10-10T19:12:00Z",
      "ends_at": "2026-10-10T19:22:00Z"
    },
    "break": {
      "active": false,
      "ends_at": null
    },
    "access_token": "Xy7pQw2LmN4rTz8aB",
    "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
  }
}

Errors: 401, 403, 404, 429

POST/tournaments/{id}/join

Join a tournament as a player

Same as the Join button on the tournament page: works for a public tournament from the schedule, or a private one when you pass the access_token from its invite_url (without it, a private tournament you are not related to answers 404). Possible while the tournament is waiting_participants, and for swiss and ladder also while it is active. Joining twice is not an error: you get the card with joined: true. Then wait for tournament.started / game.started on GET /me/events and open the game url only when it begins, instead of keeping the tournament page open. A failed join answers 422 validation_failed with details.reason: not_open (finished, canceled or not open yet), full (players_limit reached), not_running (the tournament process is stopped; an organizer has to restart it) or rejected (the tournament didn't accept the join).

Scope: games:write

Request body

Field Type Description
access_token string The access_token query parameter of a private tournament's invite_url

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/tournaments/123/join" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

Response 200

{
  "tournament": {
    "id": 5775,
    "name": "Friday practice",
    "url": "https://codebattle.hexlet.io/tournaments/5775",
    "type": "swiss",
    "state": "active",
    "level": "easy",
    "grade": "open",
    "access_type": "token",
    "starts_at": "2026-10-10T19:00:00Z",
    "started_at": "2026-10-10T19:00:04Z",
    "players_count": 8,
    "players_limit": 16,
    "rounds_limit": 3,
    "current_round": {
      "position": 1,
      "started_at": "2026-10-10T19:12:00Z",
      "ends_at": "2026-10-10T19:22:00Z"
    },
    "break": {
      "active": false,
      "ends_at": null
    },
    "access_token": "Xy7pQw2LmN4rTz8aB",
    "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
  }
}

Errors: 401, 403, 404, 422, 429

POST/tournaments/{id}/leave

Leave a tournament before it starts

Removes you from the players while the tournament is waiting_participants. Leaving a tournament you don't play in returns the card with joined: false. After the start it answers 422 validation_failed with details.reason already_started; not_running means the tournament process is stopped.

Scope: games:write

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/tournaments/123/leave" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tournament": {
    "id": 5775,
    "name": "Friday practice",
    "url": "https://codebattle.hexlet.io/tournaments/5775",
    "type": "swiss",
    "state": "active",
    "level": "easy",
    "grade": "open",
    "access_type": "token",
    "starts_at": "2026-10-10T19:00:00Z",
    "started_at": "2026-10-10T19:00:04Z",
    "players_count": 8,
    "players_limit": 16,
    "rounds_limit": 3,
    "current_round": {
      "position": 1,
      "started_at": "2026-10-10T19:12:00Z",
      "ends_at": "2026-10-10T19:22:00Z"
    },
    "break": {
      "active": false,
      "ends_at": null
    },
    "access_token": "Xy7pQw2LmN4rTz8aB",
    "invite_url": "https://codebattle.hexlet.io/tournaments/5775?access_token=Xy7pQw2LmN4rTz8aB"
  }
}

Errors: 401, 403, 404, 422, 429

Tasks

GET/tasks

Tasks you can play

Public active tasks plus your own, ordered by level and name. Use an id or name from here in POST /games or POST /invites.

Scope: read

Query parameters

Name Type Description
level string Only tasks of this level.
tags string Comma-separated; tasks having any of these tags.
name string Case-insensitive substring of the task name.

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/tasks?level=medium&tags=strings,math" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "tasks": [
    {
      "id": 42,
      "name": "minimal_time_partition",
      "level": "medium",
      "tags": [
        "math",
        "collections"
      ],
      "visibility": "public",
      "url": "https://codebattle.hexlet.io/tasks/42"
    }
  ]
}

Errors: 401, 403, 422, 429

Games

GET/games/live

Live games

What the lobby shows: games being played and games waiting for an opponent (usually a few Codebot games are waiting), newest first. Tournament games and other people's link games are not listed. Pass state=waiting_opponent for just the games you can join, then join one with POST /games/{id}/join; their task stays hidden until someone joins. Changes often; poll every 10–30 seconds.

Scope: read

Query parameters

Name Type Description
state string Only games in this state: waiting_opponent (open to join) or playing.

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/games/live?state=waiting_opponent" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "games": [
    {
      "id": 324274,
      "url": "https://codebattle.hexlet.io/games/324274",
      "state": "game_over",
      "level": "easy",
      "type": "duo",
      "starts_at": "2026-10-10T18:40:00Z",
      "timeout_seconds": 600,
      "ends_at": "2026-10-10T18:50:00Z",
      "finishes_at": "2026-10-10T18:46:12Z",
      "tournament_id": null,
      "task": {
        "id": 1201,
        "name": "pair_with_maximum_product",
        "level": "easy",
        "tags": [
          "collections"
        ],
        "visibility": "public",
        "url": "https://codebattle.hexlet.io/tasks/1201"
      },
      "players": [
        {
          "id": 42,
          "name": "ada",
          "avatar_url": null,
          "rating": 1461,
          "rank": 12,
          "lang": "python",
          "is_bot": false,
          "result": "won",
          "result_percent": 100.0
        },
        {
          "id": -1,
          "name": "Codebot",
          "avatar_url": null,
          "rating": 1200,
          "rank": null,
          "lang": "js",
          "is_bot": true,
          "result": "lost",
          "result_percent": 40.0
        }
      ]
    }
  ],
  "server_time": "2026-10-10T19:03:18Z"
}

Errors: 401, 403, 422, 429

POST/games

Create a game: against a bot, or waiting for an opponent who joins by link

opponent: bot starts the game immediately against Codebot. opponent: link creates a hidden game waiting for an opponent; send them join_url. Pick the task with task_id or task_name (see GET /tasks), or let the server pick a random one of level. Only tasks you may play are accepted: public ones and your own; any other answers 422 no such task. You can have only one active game at a time. Quota: 5 games per minute, 30 per day.

Scope: games:write

Request body

Field Type Description
level string Required unless task_id or task_name is given; with a task it must equal the task's level.. One of elementary, easy, medium, hard
task_id integer Play this task (from GET /tasks). Pass this or task_name; without both a random task of level is picked.
task_name string Exact task name, e.g. minimal_time_partition
opponent (required) string One of bot, link
timeout_seconds integer 60..3600

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/games" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"opponent":"bot"}'

Response 201

{
  "game": {
    "id": 324274,
    "url": "https://codebattle.hexlet.io/games/324274",
    "state": "waiting_opponent",
    "level": "easy",
    "type": "duo",
    "starts_at": "2026-10-10T19:03:18Z",
    "timeout_seconds": 600,
    "ends_at": "2026-10-10T19:03:18Z",
    "finishes_at": "2026-10-10T19:03:18Z",
    "tournament_id": null,
    "task": {
      "id": 42,
      "name": "minimal_time_partition",
      "level": "medium",
      "tags": [
        "math",
        "collections"
      ],
      "visibility": "public",
      "url": "https://codebattle.hexlet.io/tasks/42"
    },
    "players": [
      {
        "id": 42,
        "name": "ada",
        "avatar_url": null,
        "rating": 1461,
        "rank": 12,
        "lang": "python",
        "is_bot": false,
        "result": "won",
        "result_percent": 100.0
      }
    ],
    "join_url": "string"
  }
}

Errors: 401, 403, 404, 415, 422, 429

POST/games/{id}/join

Join a game that waits for an opponent

Joins a game from GET /games/live?state=waiting_opponent, or a link game whose id someone shared with you. The game starts at once; open its url. A failed join answers 422 validation_failed with details.reason: not_waiting_opponent (the game already started), already_in_a_game (you play another game: details.active_game_id; finish it or POST /games/{id}/cancel it if it still waits) or already_joined (you are already a player of this game).

Scope: games:write

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/games/123/join" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "game": {
    "id": 324274,
    "url": "https://codebattle.hexlet.io/games/324274",
    "state": "game_over",
    "level": "easy",
    "type": "duo",
    "starts_at": "2026-10-10T18:40:00Z",
    "timeout_seconds": 600,
    "ends_at": "2026-10-10T18:50:00Z",
    "finishes_at": "2026-10-10T18:46:12Z",
    "tournament_id": null,
    "task": {
      "id": 1201,
      "name": "pair_with_maximum_product",
      "level": "easy",
      "tags": [
        "collections"
      ],
      "visibility": "public",
      "url": "https://codebattle.hexlet.io/tasks/1201"
    },
    "players": [
      {
        "id": 42,
        "name": "ada",
        "avatar_url": null,
        "rating": 1461,
        "rank": 12,
        "lang": "python",
        "is_bot": false,
        "result": "won",
        "result_percent": 100.0
      },
      {
        "id": -1,
        "name": "Codebot",
        "avatar_url": null,
        "rating": 1200,
        "rank": null,
        "lang": "js",
        "is_bot": true,
        "result": "lost",
        "result_percent": 40.0
      }
    ]
  }
}

Errors: 401, 403, 404, 422, 429

POST/games/{id}/cancel

Cancel your game that waits for an opponent

Only a game in waiting_opponent state can be canceled.

Scope: games:write

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/games/123/cancel" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "game": {
    "id": 324274,
    "state": "canceled"
  }
}

Errors: 401, 403, 404, 422, 429

Invites

POST/invites

Invite a user to a game

Sends an invite that the recipient sees in the lobby and in GET /me/invites. One pending invite per pair of users.

Scope: games:write

Request body

Field Type Description
recipient_id integer Whom to invite. Pass this or recipient_name.
recipient_name string Exact user name, handy for voice commands
level string One of elementary, easy, medium, hard
task_id integer Play this task (from GET /tasks). Pass this or task_name; without both a random task of level is picked.
task_name string Exact task name, e.g. minimal_time_partition
timeout_seconds integer Game length, default 3600. 60..3600

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/invites" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

Response 201

{
  "invite": {
    "id": 9001,
    "state": "pending",
    "direction": "incoming",
    "level": "easy",
    "timeout_seconds": 600,
    "creator": {
      "id": 77,
      "name": "grace",
      "avatar_url": null,
      "rating": 1520
    },
    "recipient": {
      "id": 42,
      "name": "ada",
      "avatar_url": null,
      "rating": 1461
    },
    "task_id": null,
    "game_id": null,
    "game_url": null,
    "created_at": "2026-10-10T19:01:00Z"
  }
}

Errors: 401, 403, 404, 415, 422, 429

POST/invites/{id}/accept

Accept an invite sent to you

Starts the game for both players; the response has game_id and game_url. Fails with 422 if one of you is already in a game (the invite is then dropped).

Scope: games:write

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/invites/123/accept" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "invite": {
    "id": 9001,
    "state": "pending",
    "direction": "incoming",
    "level": "easy",
    "timeout_seconds": 600,
    "creator": {
      "id": 77,
      "name": "grace",
      "avatar_url": null,
      "rating": 1520
    },
    "recipient": {
      "id": 42,
      "name": "ada",
      "avatar_url": null,
      "rating": 1461
    },
    "task_id": null,
    "game_id": null,
    "game_url": null,
    "created_at": "2026-10-10T19:01:00Z"
  }
}

Errors: 401, 403, 404, 422, 429

POST/invites/{id}/cancel

Decline or withdraw an invite

The recipient declines, the creator withdraws. Only pending invites.

Scope: games:write

Example request

curl -s -X POST "https://codebattle.hexlet.io/public_api/v1/invites/123/cancel" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "invite": {
    "id": 9001,
    "state": "pending",
    "direction": "incoming",
    "level": "easy",
    "timeout_seconds": 600,
    "creator": {
      "id": 77,
      "name": "grace",
      "avatar_url": null,
      "rating": 1520
    },
    "recipient": {
      "id": 42,
      "name": "ada",
      "avatar_url": null,
      "rating": 1461
    },
    "task_id": null,
    "game_id": null,
    "game_url": null,
    "created_at": "2026-10-10T19:01:00Z"
  }
}

Errors: 401, 403, 404, 422, 429

Users

GET/users/online

Who is online

Registered users with codebattle open right now, highest rating first, with what they are doing. Changes slowly: polling every 30–60 seconds is plenty.

Scope: read

Example request

curl -s "https://codebattle.hexlet.io/public_api/v1/users/online" \
  -H "Authorization: Bearer $CODEBATTLE_TOKEN"

Response 200

{
  "users": [
    {
      "id": 77,
      "name": "grace",
      "avatar_url": null,
      "rating": 1520,
      "rank": 8,
      "lang": "dlang",
      "state": "playing",
      "url": "https://codebattle.hexlet.io/games/324274"
    }
  ],
  "server_time": "2026-10-10T19:03:18Z"
}

Errors: 401, 403, 404, 429

Objects

Fields of the objects the endpoints return. Nullable fields may be null.

Player

Field Type Description
id integer
name string
avatar_url string, nullable
rating integer, nullable
rank integer, nullable Place in the global rating
lang string, nullable Preferred programming language

Game

Field Type Description
id integer
url string
state string One of waiting_opponent, playing, game_over, timeout, canceled
level string
type string
starts_at datetime, nullable
timeout_seconds integer
ends_at datetime, nullable starts_at + timeout_seconds: when the game times out
finishes_at datetime, nullable
tournament_id integer, nullable
task Task, nullable null while the game waits for an opponent, unless it is your game
players array of GamePlayer

GamePlayer

Every field of Player, plus its own.

Field Type Description
id integer
name string
avatar_url string, nullable
rating integer, nullable
rank integer, nullable Place in the global rating
lang string, nullable Language of the player's editor in this game
is_bot boolean, nullable
result string, nullable null until the player's game is decided. One of won, lost, gave_up, timeout, ``
result_percent number, nullable Hidden for opponents while the game is live

Task

Field Type Description
id integer
name string Unique, e.g. minimal_time_partition; usable as task_name
level string One of elementary, easy, medium, hard
tags array of string
visibility string hidden tasks are listed only for their creator. One of public, hidden
url string

Tournament

Field Type Description
id integer
name string
url string
type string
state string One of upcoming, waiting_participants, active, finished, canceled, timeout
level string
grade string open for user tournaments; season grades for official ones
access_type string One of public, token
starts_at datetime, nullable
started_at datetime, nullable
players_count integer, nullable
players_limit integer, nullable
rounds_limit integer, nullable
current_round object, nullable Fields: position, started_at, ends_at
break object Fields: active, ends_at
joined boolean Whether you are a player of this tournament
access_token string Creator and moderators only
invite_url string Creator and moderators only

RankingEntry

Field Type Description
id integer
name string
place integer
score number
lang string, nullable

Invite

Field Type Description
id integer
state string One of pending, accepted, canceled, expired, dropped
direction string incoming: you are the recipient and can accept. One of incoming, outgoing
level string, nullable
timeout_seconds integer, nullable
creator Player, nullable
recipient Player, nullable
task_id integer, nullable Task chosen by the creator, if any
game_id integer, nullable Set once accepted
game_url string, nullable
created_at datetime

OnlineUser

Every field of Player, plus its own.

Field Type Description
id integer
name string
avatar_url string, nullable
rating integer, nullable
rank integer, nullable Place in the global rating
lang string, nullable Preferred programming language
state string The busiest of the user's open tabs. One of online, lobby, task, tournament, watching, playing
url string, nullable Game or tournament the user is on, if any

Error

Field Type Description
error object Fields: code, message, details