Classic Chess · REST API
Accounts & collections
Account endpoints accept bearer credentials. Automation should use personal API tokens created from profile settings; native mobile apps can use the mobile login endpoint to exchange username/password plus TOTP, if enabled, for a mobile session credential. All credentials are stored hashed server-side, revocable, and limited by explicit scopes.
Authorization: Bearer andm_pat_... Authorization: Bearer andm_mobile_...
| Scope | Allows |
|---|---|
account:read | Read the authenticated account summary. |
library:read | List account game collections. |
library:write | Create collections and import public archive games into them. |
notifications:read | Read the notification inbox and notification preferences. |
notifications:write | Mark notifications read, dismiss them, and change notification preferences. |
notebooks:read | List Notebooks and export them as .ccnb files or chapter PGN. |
gym:read | Read your Gym games and download them as PGN. |
gym:play | Start, play, resign, abort and delete your Gym games. |
puzzles:read | Read puzzles, your puzzle figures and your puzzle history. |
puzzles:write | Save how you did on a puzzle and reset your puzzles. |
Device sessions from the mobile and desktop apps are first-party and pass every scope. Browser cookie sessions are not accepted by account endpoints.
/api/v1/account/mobile/login/
Native-app username/password sign-in. If the account has authenticator 2FA enabled, retry with two_factor_code after receiving two_factor_required.
Example
curl -X POST "https://classicchess.com/api/v1/account/mobile/login/" -H "Content-Type: application/json" -d '{"username":"YOUR_USERNAME","password":"YOUR_PASSWORD","device_name":"Android phone"}'/api/v1/account/mobile/logout/
Revoke the current mobile session credential.
/api/v1/account/mobile/sessions/
List active Android and Desktop sessions owned by the authenticated account. The response contains device metadata and a current-session marker, never bearer material.
/api/v1/account/mobile/sessions/{session_id}/revoke/
Revoke one active device session owned by the authenticated account.
/api/v1/account/mobile/sessions/revoke-all/
Revoke every device session, including the credential making the request.
/api/v1/account/mobile/settings/
Native-app account settings for board theme, piece set, and Stockfish preferences. Requires a mobile session credential.
/api/v1/account/me/
Authenticated account summary. Requires account:read.
/api/v1/account/collections/
List collections with library:read, or create one with library:write.
Create example
curl -X POST "https://classicchess.com/api/v1/account/collections/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN" -H "Content-Type: application/json" -d '{"name":"Tal 1960-1965"}'/api/v1/account/collections/{id}/
List games inside one owned collection with library:read; rename or delete it with library:write. Other users' collections return 404.
/api/v1/account/collections/{id}/items/{item_id}/
Remove one game from an owned collection. Requires library:write; other users' collections return 404.
/api/v1/account/collections/import/
Create or reuse a collection and import public archive player games. Requires library:write.
Example
curl -X POST "https://classicchess.com/api/v1/account/collections/import/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN" -H "Content-Type: application/json" -d '{"source":"public_player_games","name":"Tal 1960-1965","archive_player":"mikhail-tal","since":1960,"until":1965}'Response
{
"ok": true,
"collection": { "id": 123, "name": "Tal 1960-1965", "sort": "added", "game_count": 42 },
"created_collection": true,
"matched": 42,
"added": 42,
"already_present": 0,
"skipped": 0
}/api/v1/account/imported-games/
List/search imported games with library:read, or import one pasted PGN / supported public game URL with library:write.
/api/v1/account/imported-games/{slug}/
Owned imported-game detail with PGN and board-ready mainline, with library:read. With library:write, PATCH {"visibility": "private"} or "public" changes who can see it, and DELETE permanently removes it, including from every collection and starred list. Other users' imports return 404. Making a game private hides it from other accounts' collections and stars.
/api/v1/account/imported-games/{slug}/gif/
Animated GIF of one of your own imports, public or private, with library:read. Accepts ?orientation=black and format=mp4 for an MP4 video. Shares the site-wide per-account GIF limit; a 429 carries Retry-After.
/api/v1/account/collections/{id}/items/
Add one game to an owned collection with library:write. Send {"game": "GAME_SLUG"}: any public archive game, a public imported game, or your own import. Returns 201 with the new item, or 200 with changed false if it was already there. Other accounts' private imports and collections return 404.
Example
curl -X POST "https://classicchess.com/api/v1/account/collections/123/items/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN" -H "Content-Type: application/json" -d '{"game":"tal-vs-larsen-1965"}'/api/v1/account/starred/players/{player_slug}/
GET /api/v1/account/starred/players/ lists your starred players, newest first, with library:read. PUT stars and DELETE unstars one public archive player with library:write; both are idempotent and report changed. The older toggle at /api/v1/account/players/{player_slug}/bookmark/ remains supported.
Example
curl -X PUT "https://classicchess.com/api/v1/account/starred/players/mikhail-tal/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/starred/games/{game_slug}/
GET /api/v1/account/starred/games/ lists your starred games, newest first, with library:read. PUT stars any game you can open and DELETE unstars it, with library:write. A game another account imported and later made private disappears from your list but can still be unstarred.
Example
curl -X DELETE "https://classicchess.com/api/v1/account/starred/games/tal-vs-larsen-1965/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/notifications/
Your notification inbox, newest first, with notifications:read. Paged with page and page_size (at most 100). unread_count matches the website bell.
Example
curl "https://classicchess.com/api/v1/account/notifications/?page_size=20" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/notifications/{notification_id}/read/
Mark one notification read with notifications:write. Safe to retry; returns the new unread_count.
/api/v1/account/notifications/read-all/
Mark every notification read with notifications:write. Returns how many changed.
/api/v1/account/notifications/{notification_id}/
Dismiss one notification from the inbox with notifications:write. Notifications outside your inbox return 404.
/api/v1/account/notifications/dismiss-all/
Empty the inbox: dismiss every notification in it with notifications:write, as the website's trash beside the notification settings does. Safe to retry; returns how many were dismissed as dismissed and the new unread_count.
/api/v1/account/notifications/preferences/
Each topic with its on-site choice and default, plus the sound setting, with notifications:read. PATCH with notifications:write and a body such as {"topics": {"TOPIC_KEY": false}, "sound_enabled": true}; only the named settings change. Unknown topics or non-boolean values return 400 and change nothing.
/api/v1/account/notebooks/
Notebooks you own or were invited to, most recently updated first, with notebooks:read. Each summary says whether you can export it.
Example
curl "https://classicchess.com/api/v1/account/notebooks/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/notebooks/{notebook_uuid}/
Folders and chapters of any Notebook you can open, with notebooks:read. A chapter urls.api_pgn is empty when you cannot export the Notebook.
/api/v1/account/notebooks/{notebook_uuid}/file/
Download the whole Notebook as a .ccnb file with notebooks:read. Members may always export; other accounts only when the owner allowed public exports. Members may POST {"password": "..."} for a password-protected file; the password is not stored.
Example
curl --output notebook.ccnb "https://classicchess.com/api/v1/account/notebooks/NOTEBOOK_UUID/file/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/notebooks/{notebook_uuid}/chapters/{chapter_id}/pgn/
Download one chapter as PGN with notebooks:read, under the same export rule.
The Gym's bots play over the API with the same rules as the website:
every account may play, your games are yours alone, and one account
starts at most 30 games an hour, counted together with the website. The
bot's moves are computed on the server. Its engine plays one move at a
time and serves waiting accounts in turn; while it is busy,
bot-move/ answers 429 capacity_exhausted with
Retry-After: 1, so ask again with the same ply. Each
account also has an hour's budget of engine time; once it is spent the
answer is 429 engine_budget with Retry-After set to the
seconds until the hour ends. Opening-book moves cost nothing.
/api/v1/account/gym/
The bots, the time controls a new game may use, and your newest games, with gym:read.
Example
curl "https://classicchess.com/api/v1/account/gym/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/gym/games/
Your games, newest first, paged with page and page_size (up to 100).
/api/v1/account/gym/bots/{bot_key}/games/
Start a game with gym:play. The body may give color (white, black or random) and time: unlimited, a preset such as 3+0, or custom with minutes and increment. When you play Black, bot_to_move is true; ask for the bot's move next.
Example
curl -X POST "https://classicchess.com/api/v1/account/gym/bots/morphy/games/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN" -H "Content-Type: application/json" -d '{"color":"white","time":"5+0"}'/api/v1/account/gym/games/{game_id}/
One game with its clock settled, with gym:read; DELETE removes it with gym:play. /pgn/ downloads the game as PGN.
/api/v1/account/gym/games/{game_id}/move/
Play your move as UCI with the ply you have seen, for example {"move": "e2e4", "ply": 0}. A stale ply returns 409 and plays nothing, so a repeated request is safe. Then POST bot-move/ with the new ply for the bot's reply.
Example
curl -X POST "https://classicchess.com/api/v1/account/gym/games/GAME_ID/move/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN" -H "Content-Type: application/json" -d '{"move":"e2e4","ply":0}'/api/v1/account/gym/games/{game_id}/{action}/
resign/, takeback/, clock/ (call when a clock you show reaches zero; the server decides) and abort/ (before your first move; the game is deleted), each with gym:play.
Puzzles come from master games and are for signed-in accounts only, as
on the website. Each account has its own rotation: a puzzle solved on
the first try leaves it until you reset your puzzles, and a missed one
stays. Report each play once: missed at the first wrong move or
when you show the solution, solved for a clean finish.
/api/v1/account/puzzles/
Your figures, with puzzles:read: puzzles solved on the first try, puzzles missed, what is left in your rotation, and the total.
Example
curl "https://classicchess.com/api/v1/account/puzzles/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/puzzles/next/
A random puzzle from your rotation. Pass after with the puzzle you just played to get another one. The puzzle has the game so far (start_fen and lead), its position (fen) and solution.moves: the accepted moves at each point are the entries whose after equals the moves played so far. When every puzzle is solved the answer is 404 rotation_empty.
Example
curl "https://classicchess.com/api/v1/account/puzzles/next/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN"
/api/v1/account/puzzles/{public_id}/
One puzzle, for example from your history. game links the source game's API address and page at the puzzle position when the game is available.
/api/v1/account/puzzles/{public_id}/result/
Save how one play went, with puzzles:write, for example {"result": "solved"}. A first-try solve stands until you reset your puzzles, so the saved result in the answer can differ from the one you sent.
Example
curl -X POST "https://classicchess.com/api/v1/account/puzzles/PUZZLE_ID/result/" -H "Authorization: Bearer $CLASSICCHESS_API_TOKEN" -H "Content-Type: application/json" -d '{"result":"solved"}'/api/v1/account/puzzles/history/
The puzzles you have played and how you did, most recent first, paged with page and page_size (up to 100).
/api/v1/account/puzzles/reset/
Reset your puzzles, with puzzles:write: every puzzle goes back into your rotation. Your history stays.