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
{
"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
{
"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
{
"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
{
"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
{
"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
{
"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:
{
"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) |