# Maia3 Chess API Specification Base URL: `https://.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) |