Spaces:
Sleeping
Sleeping
| # Maia3 Chess API Specification | |
| Base URL: `https://<your-space>.hf.space` | |
| Authentication: All endpoints (except `/api/health` and `GET /api/tactical-vision`) require an `x-api-key` header. | |
| ``` | |
| x-api-key: sk-maia3-2026 | |
| ``` | |
| --- | |
| ## Endpoints | |
| | Method | Path | Description | | |
| |--------|------|-------------| | |
| | `GET` | `/api/health` | Health check | | |
| | `POST` | `/api/bestmove` | Best move prediction | | |
| | `POST` | `/api/analyze-move` | Analyze a specific move | | |
| | `POST` | `/api/generate-puzzle` | Generate a tactical puzzle | | |
| | `GET` | `/api/categories` | List puzzle categories | | |
| | `POST` | `/api/tactical-vision` | Full tactical vision (model) | | |
| | `GET` | `/api/tactical-vision` | Lightweight overlay (no model) | | |
| | `POST` | `/api/game-review` | Post-game analysis | | |
| --- | |
| ## `POST /api/tactical-vision` | |
| Real-time board overlay during a live game. Helps the human player see move probabilities, tactical threats, and danger assessment. | |
| ### Request | |
| ```json | |
| { | |
| "fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1", | |
| "elo_self": 1500, | |
| "elo_oppo": 1500, | |
| "top_n": 10, | |
| "player_color": "black", | |
| "bot_last_move": "e2e4", | |
| "compare_elos": true | |
| } | |
| ``` | |
| | Field | Type | Required | Default | Description | | |
| |-------|------|----------|---------|-------------| | |
| | `fen` | string | yes | — | FEN string of the current position | | |
| | `elo_self` | int | no | 1500 | Player's Elo rating (0–5000) | | |
| | `elo_oppo` | int | no | 1500 | Opponent's Elo rating (0–5000) | | |
| | `top_n` | int | no | 10 | Number of top moves to return (1–20) | | |
| | `player_color` | string | no | `"white"` | Player's side: `"white"` or `"black"` | | |
| | `bot_last_move` | string | no | null | UCI of opponent's last move to analyze. Use the FEN from **before** the opponent's move for accurate analysis. | | |
| | `compare_elos` | bool | no | false | Include Elo comparison across 1200/1500/1800/2100/2400 | | |
| ### Response | |
| ```json | |
| { | |
| "fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1", | |
| "elo_self": 1500, | |
| "elo_oppo": 1500, | |
| "player_side": "black", | |
| "position": { | |
| "win_probability": 0.4437, | |
| "eval_cp": -39, | |
| "confidence": "confusing", | |
| "entropy": 3.142, | |
| "max_probability": 0.425, | |
| "legal_move_count": 20, | |
| "danger_level": "low", | |
| "danger_detail": "Position is relatively straightforward." | |
| }, | |
| "top_moves": [ | |
| { | |
| "uci": "e7e5", | |
| "san": "e5", | |
| "probability": 0.4247, | |
| "rank": 1, | |
| "classification": "good", | |
| "result_eval_cp": 5, | |
| "result_win_probability": 0.5063, | |
| "eval_delta_cp": 44, | |
| "is_capture": false, | |
| "is_check": false, | |
| "is_mate": false, | |
| "is_tempting_blunder": false, | |
| "tactical_tags": [] | |
| }, | |
| { | |
| "uci": "e7e6", | |
| "san": "e6", | |
| "probability": 0.1220, | |
| "rank": 2, | |
| "classification": "mistake", | |
| "result_eval_cp": 1, | |
| "result_win_probability": 0.5013, | |
| "eval_delta_cp": 40, | |
| "is_capture": false, | |
| "is_check": false, | |
| "is_mate": false, | |
| "is_tempting_blunder": false, | |
| "tactical_tags": [] | |
| } | |
| ], | |
| "threats": { | |
| "hanging_pieces": [], | |
| "attacked_pieces": [], | |
| "underdefended_squares": [], | |
| "king_safety_concern": false, | |
| "king_safety_detail": "" | |
| }, | |
| "tactical_alerts": [ | |
| { | |
| "type": "hanging_piece", | |
| "square": "e4", | |
| "piece": "pawn", | |
| "description": "Undefended white pawn on e4" | |
| } | |
| ], | |
| "bot_last_move": { | |
| "uci": "e2e4", | |
| "san": "e4", | |
| "probability": 0.5200, | |
| "rank": 1, | |
| "classification": "excellent" | |
| }, | |
| "elo_comparison": { | |
| "1200": { | |
| "best_move": "e7e5", | |
| "best_probability": 0.4985, | |
| "top_moves": [ | |
| { "uci": "e7e5", "san": "e5", "probability": 0.4985 }, | |
| { "uci": "e7e6", "san": "e6", "probability": 0.1320 } | |
| ] | |
| }, | |
| "1500": { | |
| "best_move": "e7e5", | |
| "best_probability": 0.4247, | |
| "top_moves": [ | |
| { "uci": "e7e5", "san": "e5", "probability": 0.4247 } | |
| ] | |
| }, | |
| "1800": { | |
| "best_move": "e7e5", | |
| "best_probability": 0.3875, | |
| "top_moves": [ | |
| { "uci": "e7e5", "san": "e5", "probability": 0.3875 } | |
| ] | |
| }, | |
| "2100": { | |
| "best_move": "e7e5", | |
| "best_probability": 0.3039, | |
| "top_moves": [ | |
| { "uci": "e7e5", "san": "e5", "probability": 0.3039 } | |
| ] | |
| }, | |
| "2400": { | |
| "best_move": "e7e5", | |
| "best_probability": 0.2654, | |
| "top_moves": [ | |
| { "uci": "e7e5", "san": "e5", "probability": 0.2654 } | |
| ] | |
| } | |
| } | |
| } | |
| ``` | |
| ### Field Reference | |
| #### `position` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `win_probability` | float | Maia3's predicted win probability for the side to move (0–1) | | |
| | `eval_cp` | int | Centipawn evaluation derived from win probability | | |
| | `confidence` | string | `"clear"` (one move dominates), `"complex"` (top move 50–85%), `"confusing"` (no clear favorite), `"terminal"` (game over) | | |
| | `entropy` | float | Shannon entropy of the policy distribution over legal moves | | |
| | `max_probability` | float | Probability of the top move | | |
| | `legal_move_count` | int | Number of legal moves | | |
| | `danger_level` | string | `"low"`, `"moderate"`, or `"high"` — how treacherous the position is | | |
| | `danger_detail` | string | Human-readable explanation of the danger level | | |
| #### `top_moves[]` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `uci` | string | Move in UCI format | | |
| | `san` | string | Move in Standard Algebraic Notation | | |
| | `probability` | float | Maia3's predicted probability a human at this Elo plays this move | | |
| | `rank` | int | Rank among all legal moves (1 = most likely) | | |
| | `classification` | string | `"excellent"` (≥60%), `"good"` (≥30%), `"inaccuracy"` (≥15%), `"mistake"` (≥5%), `"blunder"` (<5%) | | |
| | `result_eval_cp` | int | Evaluation after playing this move (centipawns) | | |
| | `result_win_probability` | float | Win probability after playing this move | | |
| | `eval_delta_cp` | int | Change in evaluation: positive = improves position, negative = worsens | | |
| | `is_capture` | bool | Whether the move is a capture | | |
| | `is_check` | bool | Whether the move gives check | | |
| | `is_mate` | bool | Whether the move delivers checkmate | | |
| | `is_tempting_blunder` | bool | High probability (≥15%) but leads to a significantly worse position (eval_delta < -100cp) | | |
| | `tactical_tags` | string[] | Tactical motifs detected: `"fork"`, `"pin"`, `"skewer"`, `"discovered_attack"`, `"hanging_piece"`, `"trapped_piece"`, `"sacrifice"`, `"zwischenzug"`, `"king_safety"` | | |
| #### `threats` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `hanging_pieces` | string[] | Squares of opponent's undefended pieces | | |
| | `attacked_pieces` | string[] | Squares of your attacked but undefended pieces | | |
| | `underdefended_squares` | string[] | Squares where attacker value exceeds defender value | | |
| | `king_safety_concern` | bool | Whether there's a king safety issue | | |
| | `king_safety_detail` | string | Description of the king safety concern | | |
| #### `tactical_alerts[]` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `type` | string | `"hanging_piece"`, `"attacked_piece"`, `"in_check"`, `"fork_opportunity"` | | |
| | `square` | string | Square name (e.g., `"e4"`) | | |
| | `piece` | string | Piece type (e.g., `"pawn"`, `"knight"`) | | |
| | `description` | string | Human-readable description | | |
| #### `bot_last_move` | |
| Only present when `bot_last_move` is provided in the request. | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `uci` | string | The move in UCI format | | |
| | `san` | string | The move in SAN | | |
| | `probability` | float | How likely Maia3 thought a human at this Elo would play this move | | |
| | `rank` | int | Rank among all legal moves | | |
| | `classification` | string | Move quality classification | | |
| #### `elo_comparison` | |
| Only present when `compare_elos: true`. Keys are Elo levels (1200, 1500, 1800, 2100, 2400). | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `best_move` | string | Top move at this Elo | | |
| | `best_probability` | float | Probability of the top move | | |
| | `top_moves` | array | Top 5 moves at this Elo | | |
| --- | |
| ## `GET /api/tactical-vision` | |
| Lightweight chess-only overlay — **no model inference**. Use for fast board overlays showing threats and tactical alerts. | |
| ### Parameters | |
| | Parameter | Type | Required | Default | Description | | |
| |-----------|------|----------|---------|-------------| | |
| | `fen` | string | yes | — | FEN string | | |
| | `player_color` | string | no | `"white"` | Player's side | | |
| ### Response | |
| ```json | |
| { | |
| "fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1", | |
| "player_side": "black", | |
| "threats": { | |
| "hanging_pieces": ["e4"], | |
| "attacked_pieces": [], | |
| "underdefended_squares": [], | |
| "king_safety_concern": false, | |
| "king_safety_detail": "" | |
| }, | |
| "tactical_alerts": [ | |
| { | |
| "type": "hanging_piece", | |
| "square": "e4", | |
| "piece": "pawn", | |
| "description": "Undefended white pawn on e4" | |
| } | |
| ], | |
| "board_info": { | |
| "turn": "black", | |
| "fullmove": 1, | |
| "halfmove_clock": 0, | |
| "is_check": false, | |
| "is_game_over": false, | |
| "piece_count": 31 | |
| } | |
| } | |
| ``` | |
| --- | |
| ## `POST /api/game-review` | |
| Post-game analysis. Reviews every move in a completed game, calculates consistency, identifies blunder patterns, and provides recommendations. | |
| ### Request | |
| Provide either `pgn` or `moves`: | |
| **Option A: PGN** | |
| ```json | |
| { | |
| "pgn": "[Event \"Casual\"]\n[White \"Player1\"]\n[Black \"Player2\"]\n[Result \"1-0\"]\n[WhiteElo \"1500\"]\n[BlackElo \"1480\"]\n\n1. e4 e5 2. Bc4 Nc6 3. Qh5 Nf6 4. Qxf7# 1-0", | |
| "elo_white": 1500, | |
| "elo_black": 1480 | |
| } | |
| ``` | |
| **Option B: Move list** | |
| ```json | |
| { | |
| "moves": ["e2e4", "e7e5", "f1c4", "b8c6", "d1h5", "g8f6", "h5f7"], | |
| "starting_fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", | |
| "elo_white": 1500, | |
| "elo_black": 1500 | |
| } | |
| ``` | |
| | Field | Type | Required | Default | Description | | |
| |-------|------|----------|---------|-------------| | |
| | `pgn` | string | one of pgn/moves | null | PGN string of the game | | |
| | `moves` | string[] | one of pgn/moves | null | List of UCI moves | | |
| | `starting_fen` | string | no | starting position | Starting FEN | | |
| | `elo_white` | int | no | 1500 | White player's Elo | | |
| | `elo_black` | int | no | 1500 | Black player's Elo | | |
| ### Response | |
| ```json | |
| { | |
| "game_info": { | |
| "white": "Player1", | |
| "black": "Player2", | |
| "result": "1-0", | |
| "elo_white": 1500, | |
| "elo_black": 1480, | |
| "total_moves": 7, | |
| "opening": "" | |
| }, | |
| "summary": { | |
| "consistency_score": 0.34, | |
| "consistency_label": "Below your usual level", | |
| "average_move_probability": 0.34, | |
| "blunder_count": 1, | |
| "mistake_count": 1, | |
| "inaccuracy_count": 2, | |
| "good_count": 1, | |
| "excellent_count": 2, | |
| "missed_opportunities": 0 | |
| }, | |
| "phase_breakdown": { | |
| "opening": { | |
| "moves": 7, | |
| "consistency_score": 0.34, | |
| "average_probability": 0.34, | |
| "blunders": 1, | |
| "mistakes": 1, | |
| "inaccuracies": 2, | |
| "good": 1, | |
| "excellent": 2, | |
| "label": "Opening technique needs work" | |
| }, | |
| "middlegame": { | |
| "moves": 0, | |
| "consistency_score": 0.0, | |
| "average_probability": 0.0, | |
| "blunders": 0, | |
| "mistakes": 0, | |
| "inaccuracies": 0, | |
| "good": 0, | |
| "excellent": 0, | |
| "label": "" | |
| }, | |
| "endgame": { | |
| "moves": 0, | |
| "consistency_score": 0.0, | |
| "average_probability": 0.0, | |
| "blunders": 0, | |
| "mistakes": 0, | |
| "inaccuracies": 0, | |
| "good": 0, | |
| "excellent": 0, | |
| "label": "" | |
| } | |
| }, | |
| "moves": [ | |
| { | |
| "move_number": 1, | |
| "side": "white", | |
| "uci": "e2e4", | |
| "san": "e4", | |
| "fen_before": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", | |
| "fen_after": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1", | |
| "probability": 0.6400, | |
| "rank": 1, | |
| "classification": "excellent", | |
| "eval_before": 0, | |
| "eval_after": -18, | |
| "eval_delta": -18, | |
| "best_move": "e2e4", | |
| "best_move_probability": 0.6400, | |
| "is_capture": false, | |
| "is_check": false, | |
| "tactical_tags": [], | |
| "phase": "opening" | |
| } | |
| ], | |
| "blunder_genealogy": [ | |
| { | |
| "blunder_move": 4, | |
| "root_cause_move": 2, | |
| "explanation": "The blunder at move 4 was likely caused by difficulties that started around move 2. The position became complex after Bc4." | |
| } | |
| ], | |
| "missed_opportunities": [ | |
| { | |
| "move_number": 3, | |
| "side": "white", | |
| "played_move": "Qh5", | |
| "best_move": "Nf3", | |
| "eval_delta_missed": 150, | |
| "explanation": "Nf3 would have been much stronger, improving the position by 150 centipawns." | |
| } | |
| ], | |
| "danger_positions": [ | |
| { | |
| "move_number": 3, | |
| "side": "black", | |
| "fen": "r1bqkbnr/pppp1ppp/2n5/4p3/2B1P3/8/PPPP1PPP/RNBQK1NR b KQkq - 1 3", | |
| "danger_level": "moderate", | |
| "danger_detail": "Position was complex with low probability for the played move.", | |
| "player_response": "Nf6 (inaccuracy)", | |
| "correct_response": "Qe7" | |
| } | |
| ], | |
| "eval_trajectory": [ | |
| { "move": 1, "side": "white", "eval": -18 }, | |
| { "move": 1, "side": "black", "eval": -5 }, | |
| { "move": 2, "side": "white", "eval": -38 }, | |
| { "move": 2, "side": "black", "eval": 52 }, | |
| { "move": 3, "side": "white", "eval": -22 }, | |
| { "move": 3, "side": "black", "eval": 493 }, | |
| { "move": 4, "side": "white", "eval": 1000 } | |
| ], | |
| "tactical_patterns": { | |
| "missed_forks": 1, | |
| "missed_pins": 0, | |
| "missed_skewers": 0, | |
| "missed_discovered_attacks": 0, | |
| "hung_pieces": 0, | |
| "walked_into_tactics": 0, | |
| "most_common_mistake": "fork (1 occurrences)" | |
| }, | |
| "recommendations": [ | |
| "Focus on opening technique — your consistency drops significantly in openings", | |
| "Work on fork recognition — you missed opportunities to fork pieces", | |
| "Review your opening repertoire — low consistency suggests unfamiliar positions" | |
| ] | |
| } | |
| ``` | |
| ### Field Reference | |
| #### `summary` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `consistency_score` | float | Average move probability across all moves (0–1) | | |
| | `consistency_label` | string | Human-readable label: `"Excellent performance"`, `"Playing to your rating"`, `"Below your usual level"`, `"Significantly underperforming"` | | |
| | `average_move_probability` | float | Same as consistency_score | | |
| | `blunder_count` | int | Number of blunders (<5% probability) | | |
| | `mistake_count` | int | Number of mistakes (5–15%) | | |
| | `inaccuracy_count` | int | Number of inaccuracies (15–30%) | | |
| | `good_count` | int | Number of good moves (30–60%) | | |
| | `excellent_count` | int | Number of excellent moves (≥60%) | | |
| | `missed_opportunities` | int | Positions where eval dropped >100cp and a better move existed | | |
| #### `phase_breakdown` | |
| Keys: `"opening"` (moves 1–10), `"middlegame"` (moves 11–30), `"endgame"` (move 31+ or ≤8 pieces). | |
| Each phase has the same fields as `summary` plus a `label` describing performance. | |
| #### `moves[]` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `move_number` | int | Full move number | | |
| | `side` | string | `"white"` or `"black"` | | |
| | `uci` | string | Move in UCI format | | |
| | `san` | string | Move in SAN | | |
| | `fen_before` | string | FEN before the move | | |
| | `fen_after` | string | FEN after the move | | |
| | `probability` | float | Maia3's predicted probability | | |
| | `rank` | int | Rank among legal moves | | |
| | `classification` | string | Move quality | | |
| | `eval_before` | int | Evaluation before the move (centipawns) | | |
| | `eval_after` | int | Evaluation after the move (centipawns) | | |
| | `eval_delta` | int | Change in evaluation | | |
| | `best_move` | string | Maia3's top predicted move | | |
| | `best_move_probability` | float | Probability of the best move | | |
| | `is_capture` | bool | Whether the move is a capture | | |
| | `is_check` | bool | Whether the move gives check | | |
| | `tactical_tags` | string[] | Tactical motifs detected | | |
| | `phase` | string | Game phase: `"opening"`, `"middlegame"`, `"endgame"` | | |
| #### `blunder_genealogy[]` | |
| Traces each blunder back to its root cause. | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `blunder_move` | int | Move number of the blunder | | |
| | `root_cause_move` | int | Move number where difficulties began | | |
| | `explanation` | string | Human-readable explanation | | |
| #### `missed_opportunities[]` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `move_number` | int | Move number | | |
| | `side` | string | `"white"` or `"black"` | | |
| | `played_move` | string | SAN of the played move | | |
| | `best_move` | string | UCI of the better move | | |
| | `eval_delta_missed` | int | Centipawns lost by not playing the best move | | |
| | `explanation` | string | Human-readable explanation | | |
| #### `danger_positions[]` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `move_number` | int | Move number | | |
| | `side` | string | `"white"` or `"black"` | | |
| | `fen` | string | FEN of the dangerous position | | |
| | `danger_level` | string | `"high"` or `"moderate"` | | |
| | `danger_detail` | string | Description of the danger | | |
| | `player_response` | string | What the player played (with classification) | | |
| | `correct_response` | string | The better move | | |
| #### `eval_trajectory[]` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `move` | int | Move number | | |
| | `side` | string | `"white"` or `"black"` | | |
| | `eval` | int | Evaluation in centipawns after the move | | |
| #### `tactical_patterns` | |
| | Field | Type | Description | | |
| |-------|------|-------------| | |
| | `missed_forks` | int | Number of missed fork opportunities | | |
| | `missed_pins` | int | Number of missed pins | | |
| | `missed_skewers` | int | Number of missed skewers | | |
| | `missed_discovered_attacks` | int | Number of missed discovered attacks | | |
| | `hung_pieces` | int | Number of times a piece was hung | | |
| | `walked_into_tactics` | int | Number of times the player walked into a tactic | | |
| | `most_common_mistake` | string | Description of the most frequent mistake type | | |
| #### `recommendations` | |
| Array of strings with actionable improvement suggestions based on the analysis. | |
| --- | |
| ## Error Responses | |
| All endpoints return errors in this format: | |
| ```json | |
| { | |
| "error": "Description of the error" | |
| } | |
| ``` | |
| | Status Code | Meaning | | |
| |-------------|---------| | |
| | 400 | Bad request (invalid FEN, missing fields, invalid move) | | |
| | 401 | Unauthorized (missing or invalid API key) | | |
| | 405 | Method not allowed | | |
| | 500 | Internal server error | | |
| | 503 | Model unavailable (still loading or failed) | | |