API Reference
Complete endpoint documentation for the ChessGrammar API v1.
Base URLs
- Free tier:
https://chessgrammar.com/api/v1 - Paid tiers (Builder, Scale):
https://api.chessgrammar.com/v1
Authentication
The free tier is unauthenticated and rate-limited per IP (30 req/min). Paid tiers require an API key sent in the Authorization header:
Authorization: Bearer cg_YOUR_API_KEY
See Limits & Access for plan details and how to obtain a key.
POST /extract
Analyze a single position (FEN) for tactical patterns.
Request
{
"fen": "6k1/5p1p/4p3/4q3/3n4/2Q3P1/PP1N1P1P/6K1 b - - 3 37",
"patterns": ["fork", "pin"],
"depth": "l2",
"with_sequence": true
}
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
fen | string | yes | — | Valid FEN string |
patterns | string[] | no | all 10 | Filter by pattern names |
depth | string | no | "l2" | "l1" (fast scan) or "l2" (forcing tree confirmation) |
with_sequence | boolean | no | false | Include forcing move sequences (~205ms/tactic). Ignored when depth="l1". |
Response
{
"tactics": [
{
"pattern": "fork",
"color": "black",
"key_squares": ["e2"],
"target_squares": ["g1", "c3"],
"targets": [
{"square": "g1", "piece": "K", "piece_name": "king", "color": "white"},
{"square": "c3", "piece": "Q", "piece_name": "queen", "color": "white"}
],
"gain": 700,
"gain_confirmed": true,
"is_mate": false,
"trigger_move": "d4e2",
"sequence": ["d4e2", "g1g2", "e2c3", "b2c3"],
"fen": "6k1/5p1p/..."
}
],
"count": 1,
"depth": "l2",
"performance_ms": 48.2,
"fen": "6k1/5p1p/..."
}
Tactic object
| Field | Type | Description |
|---|---|---|
pattern | string | Tactic type (fork, pin, skewer, discovered_attack, double_check, back_rank_mate, smothered_mate, deflection, interference, trapped_piece) |
color | string | Side with the tactic (white or black) |
trigger_move | string | Initiating move in UCI format |
key_squares | string[] | Critical squares involved |
target_squares | string[] | Attacked/affected piece squares |
targets | object[] | Detailed target info (square, piece, piece_name, color) |
gain | integer | Material gain in centipawns |
gain_confirmed | boolean | true if confirmed via forcing tree (L2) |
is_mate | boolean | true if tactic leads to checkmate |
sequence | string[] or null | Forcing moves in UCI format (when with_sequence: true) |
fen | string | Position FEN |
Pattern names
Valid values for the patterns filter:
fork, pin, skewer, discovered_attack, double_check, back_rank_mate, smothered_mate, deflection, interference, trapped_piece
POST /extract_game
Analyze a complete game (PGN) for tactical patterns across every position.
Request
{
"pgn": "1. e4 e5 2. Nf3 Nc6 3. Bc4 ...",
"mode": "played",
"patterns": ["fork", "discovered_attack"],
"depth": "l2",
"with_sequence": false
}
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
pgn | string | yes | — | PGN string of a complete game |
mode | string | no | "played" | "played" (tactics actually executed) or "available" (all tactical opportunities) |
patterns | string[] | no | all 10 | Filter by pattern names |
depth | string | no | "l2" | "l1" (fast scan) or "l2" (forcing tree confirmation) |
with_sequence | boolean | no | false | Include forcing move sequences. Ignored when depth="l1". |
Response
Same tactic structure as /extract, with additional per-tactic fields:
| Field | Description |
|---|---|
ply | Half-move number in the game |
status | "played" or "existing" (in mode: "played" only) |
GET /health
Returns service status and engine info.
curl https://chessgrammar.com/api/v1/health
{
"status": "ok",
"engine_version": "2.5",
"api_version": "1.0",
"patterns": ["fork", "pin", "skewer", "discovered_attack", "double_check", "back_rank_mate", "smothered_mate", "deflection", "interference", "trapped_piece"],
"patterns_count": 10
}
Errors
| Status | Body | Cause |
|---|---|---|
| 400 | "error": "Missing 'fen' or 'pgn' field" | No input provided |
| 400 | "error": "Invalid FEN" | Malformed FEN string |
| 400 | "error": "Invalid PGN" | Malformed PGN |
| 400 | "error": "Invalid pattern: xyz" | Unknown pattern name in filter |
| 401 | "error": "Missing or invalid API key" | Paid endpoint called without a valid Authorization: Bearer header |
| 429 | "error": "Rate limit exceeded" | Plan rate limit exceeded — see Limits |