Classic Chess · REST API
SDK examples
To connect Claude Code, Codex or another MCP client, see MCP server.
Each example discovers a player, reads their biography, lists notable PGN links, and follows every page of their game archive. Install your language's SDK using its public README first. These examples use public data without credentials and handle empty archives and missing biographies.
Python users can install the MIT-licensed classicchess-sdk package from PyPI. In a Python 3.10+ virtual environment, run:
python -m pip install classicchess-sdk classicchess-api public players --names
Python
from urllib.parse import urljoin
from classicchess_api import ClassicChessClient
api = ClassicChessClient(user_agent="my-chess-app/1.0")
players = api.public_players()["results"]
if not players:
raise SystemExit("No curated player archives are available")
player = players[0]
print(player["name"])
bio = api.public_player_bio(player["slug"])["bio"]
print(bio["lede"] if bio else "Biography unavailable")
notable = api.public_notable_games(player["slug"])
for entry in notable["results"]:
print(entry["title"], urljoin(api.base_url, entry["game"]["urls"]["api_pgn"]))
for game in api.iterate_public_games(archive_player=player["slug"]):
print(game["token"], urljoin(api.base_url, game["urls"]["api_pgn"]))JavaScript and TypeScript users can install the MIT-licensed classicchess-sdk package from npm. It requires Node.js 22 or later and includes ESM, CommonJS and TypeScript definitions. From your app directory, run:
npm install classicchess-sdk
Save the following example as example.mjs and run node example.mjs. CommonJS apps use require('classicchess-sdk') and wrap awaited calls in an async function.
JavaScript
import { ClassicChessClient } from "classicchess-sdk";
const api = new ClassicChessClient({ userAgent: "my-chess-app/1.0" });
const { results: players } = await api.publicPlayers();
if (!players.length) throw new Error("No curated player archives are available");
const player = players[0];
console.log(player.name);
const { bio } = await api.publicPlayerBio(player.slug);
console.log(bio?.lede ?? "Biography unavailable");
const notable = await api.publicNotableGames(player.slug);
for (const entry of notable.results) {
console.log(entry.title, new URL(entry.game.urls.api_pgn, api.baseUrl).href);
}
for await (const game of api.iteratePublicGames({ archivePlayer: player.slug })) {
console.log(game.token, new URL(game.urls.api_pgn, api.baseUrl).href);
}Kotlin
import com.classicchess.api.ClassicChessClient
import com.classicchess.api.PublicGameFilters
import java.net.URI
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
ClassicChessClient().use { api ->
val players = api.publicPlayers().results
val player = players.firstOrNull()
if (player == null) {
println("No curated player archives are available")
return@use
}
println(player.name)
val bio = api.publicPlayerBio(player.slug).bio
println(bio?.lede ?: "Biography unavailable")
val notable = api.publicNotableGames(player.slug)
for (entry in notable.results) {
println("${entry.title} ${URI(api.baseUrl).resolve(entry.game.urls.getValue("api_pgn")!!)}")
}
api.iteratePublicGames(PublicGameFilters(archivePlayer = player.slug)).collect { game ->
println("${game.token} ${URI(api.baseUrl).resolve(game.urls.getValue("api_pgn")!!)}")
}
}
}The JavaScript example runs on a server. Cross-origin browser access is not currently enabled; browser apps should call their own backend. Keep account bearer tokens on trusted clients or your backend and send them only to the configured HTTPS API origin.
- Requests and retries: use timeouts, a descriptive User-Agent, and sequential pagination. HTTP 429 means slow down. Honor
Retry-Afterwhen present; otherwise back off with a bounded retry count. Application export limits use a 15-minute window. A proxy can reject a request before the application, so error responses are not always JSON. Retry read requests deliberately; do not blindly retry account writes. - Cache public catalogs: reuse catalog responses between views and refresh periodically. Profiles can include the caller's bookmark state; do not share authenticated responses between users.
- Stable identity: use returned slugs and canonical game URLs, not display names or database row IDs. A single game can belong to a player archive and several events; keep one record per canonical game.
- Versioning: these additions use
/api/v1/. Existing routes and default JSON fields remain available. Accept additional response fields, handle nulls, and use the OpenAPI schemas to validate the fields your app depends on. - Sources and reuse: preserve biography sources and annotation attribution. Book downloads and annotations carry their own source and license metadata; public API access is not a blanket license for every linked asset. See site terms and contact support for questions about your integration.