HOK API: Honor of Kings data for your programs Read the heroes, items, arcana, spells, tier list and tournament drafts of Honor of Kings Global, and your own scrims, from a program or an AI assistant. Read-only, free, with a key.
Get a key
Authentication
Every address takes an API key, sent as a bearer token. A key only reads, and sees what its owner sees: the data of the game for everybody, your own scrims, tier lists and teams for you.
Your first call Copycurl -H "Authorization: Bearer hok_YOUR_KEY" http://127.0.0.1:3000/api/v1/heroes
The X-API-Key header works too. A key put in the address is ignored: addresses end up in logs.
Limits and errors
Each key may make 120 requests a minute. Errors are JSON with a stable code:
Status code Meaning 400 invalid_bodyThe situation sent to the one POST is not valid: the error says what is wrong. 401 unauthorizedNo key, or a key that is not valid, has expired or was revoked. 403 insufficient_scopeThe key lacks the scope this address needs. 404 not_foundUnknown address, or something the owner of the key cannot see. 405 method_not_allowedThe API only reads: use GET. 429 rate_limitedToo many requests: wait for the seconds of Retry-After.
Use with an AI
The API is also an MCP server, at http://127.0.0.1:3000/api/v1/mcp: an assistant gets one tool per address its key can read.
Make one key for each assistant, with only what it needs (the public data of the game is enough to ask about heroes, items and drafts). If one leaks, revoke it without touching the others.
Claude Code Run this in a terminal:
Terminal Copyclaude mcp add --transport http hok-api http://127.0.0.1:3000/api/v1/mcp --header "Authorization: Bearer hok_YOUR_KEY"Claude Desktop Add this to claude_desktop_config.json (Settings, Developer, Edit config), then restart Claude. It needs Node.js.
claude_desktop_config.json Copy{
"mcpServers": {
"hok-api": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://127.0.0.1:3000/api/v1/mcp",
"--header",
"Authorization:${HOK_API_KEY}"
],
"env": {
"HOK_API_KEY": "Bearer hok_YOUR_KEY"
}
}
}
}Cursor Add this to .cursor/mcp.json, in your project or in your home folder:
.cursor/mcp.json Copy{
"mcpServers": {
"hok-api": {
"url": "http://127.0.0.1:3000/api/v1/mcp",
"headers": {
"Authorization": "Bearer hok_YOUR_KEY"
}
}
}
}ChatGPT In a custom GPT: Configure, Create new action, Import from URL with this address. Then Authentication: API key, type Bearer, and paste your key.
OpenAPI Copyhttp://127.0.0.1:3000/api/v1/openapi.json
Replace hok_YOUR_KEY with your key. The assistant then sees one tool per address your key can read, and only reads.
Addresses
The full description, to import in a tool: /api/v1/openapi.json (OpenAPI 3.1)
Game data game
GET /api/v1/heroesGame data
The heroes of the Global roster (name, classes, lanes, picture).
Tool for an AI: list_heroes
Example answer {
"heroes": [
{
"id": "h105",
"name": "Arli",
"displayName": "Arli",
"image": "https://camp.honorofkings.com/h105.png",
"roles": [
"Marksman"
],
"lanes": [
"Farm Lane"
],
"laneSources": {
"Farm Lane": "camp"
},
"sourceIds": [
"105"
],
"availableGlobal": true,
"isFlowborn": false,
"sourceUpdated": "20260925"
}
],
"lastUpdated": "2026-10-31T08:00:00.000Z",
"sourceUpdated": "20260925",
"usingCache": true,
"language": "en",
"namesLanguage": "en"
}
GET /api/v1/heroes/{id}Game data
One hero: its sheet (skills, art), its recommended builds, its combos, its official ratings and the competitive figures.
Tool for an AI: get_hero
Parameter In Description id required address The id of the thing. sincequery Count the tournament games from this day on, YYYY-MM-DD.
Example answer {
"hero": {
"id": "h105",
"name": "Arli",
"roles": [
"Marksman"
],
"lanes": [
"Farm Lane"
]
},
"competitive": [],
"tournament": {
"since": null,
"totalGames": 48,
"picks": 21,
"bans": 9,
"wins": 12,
"losses": 9,
"winRate": 0.571,
"pickRate": 0.438,
"banRate": 0.188,
"byRule": {},
"range": {
"first": "2026-08-01",
"last": "2026-10-30"
}
},
"builds": [],
"profile": null,
"ratings": {
"Farm Lane": "A"
},
"ratingSources": {
"Farm Lane": "tournaments"
},
"combos": [],
"details": null,
"detailsFetchedAt": null,
"detailsLanguage": "en",
"language": "en"
}
GET /api/v1/tier-listGame data
The public tier list of each lane: tournament results first, the editors' ratings for the heroes played too little.
Tool for an AI: get_tier_list
Example answer {
"period": {
"from": "2026-08-01",
"to": "2026-10-31"
},
"minGames": 10,
"totalGames": 120,
"lanes": [
{
"lane": "Farm Lane",
"slug": "farm",
"tiers": [
{
"label": "SS",
"heroes": [
{
"heroId": "h105",
"source": "tournaments",
"games": 48,
"winRate": 0.571,
"pickRate": 0.438,
"score": 0.62
}
]
}
],
"unranked": [
"h199"
]
}
],
"updatedAt": "2026-10-31T08:00:00.000Z"
}
GET /api/v1/catalogGame data
The items, the arcana, the battle spells, the stats and the tags of the game, in one answer.
Tool for an AI: get_catalog
Example answer {
"stats": [
{
"id": 1,
"name": "Physical Attack"
}
],
"tags": [
{
"id": 3,
"name": "Burst"
}
],
"tagGroups": {
"red": "Damage"
},
"items": [],
"arcana": [],
"spells": [
{
"id": 1,
"name": "Flash",
"imageId": null,
"description": "Blink a short distance.",
"cooldownSeconds": 120,
"unlockLevel": null
}
],
"heroTags": {}
}
GET /api/v1/catalog/{family}Game data
One family of the catalogue: items, arcana, spells, stats or tags.
Tool for an AI: list_catalog_family
Parameter In Description family required address items, arcana, spells, stats or tags.
Example answer {
"spells": [
{
"id": 1,
"name": "Flash",
"imageId": null,
"description": "Blink a short distance.",
"cooldownSeconds": 120,
"unlockLevel": null
}
]
}
GET /api/v1/catalog/{family}/{id}Game data
One item, arcana, spell, stat or tag, by its number: everything its page shows (stats and tags by their number).
Tool for an AI: get_catalog_entry
Parameter In Description family required address items, arcana, spells, stats or tags. id required address The id of the thing.
Example answer {
"id": 1,
"name": "Flash",
"imageId": null,
"description": "Blink a short distance.",
"cooldownSeconds": 120,
"unlockLevel": null
}
Competitive scene competitive
GET /api/v1/tournamentsCompetitive scene
The tournament series entered by the staff.
Tool for an AI: list_tournaments
Parameter In Description qquery Words to look for. pagequery The page of the list, from 1.
Example answer {
"items": [
{
"id": "8d1f6a52-3c1e-4b7e-9a51-1f2c3d4e5f60",
"name": "KPL West Finals",
"teamA": "Alpha",
"teamB": "Bravo",
"bestOf": 5,
"status": "complete"
}
],
"total": 1,
"page": 1,
"pageSize": 25
}
GET /api/v1/tournaments/{id}Competitive scene
One tournament series with all its games: bans, picks, lanes, winner, duration.
Tool for an AI: get_tournament
Parameter In Description id required address The id of the thing.
Example answer {
"id": "8d1f6a52-3c1e-4b7e-9a51-1f2c3d4e5f60",
"teamA": {
"name": "Alpha"
},
"teamB": {
"name": "Bravo"
},
"bestOf": 5,
"gameMode": "global-ban-pick",
"status": "complete",
"games": [
{
"number": 1,
"bans": {
"blue": [
"h105"
],
"red": [
"h199"
]
},
"picks": {
"blue": [
"h101"
],
"red": [
"h120"
]
},
"winner": "blue",
"durationSeconds": 1104
}
]
}
GET /api/v1/popular/draftsCompetitive scene
The drafts that win and are played most in the tournament games.
Tool for an AI: popular_drafts
Parameter In Description fromquery The first day of the period, YYYY-MM-DD (the period spans 3 months at least). toquery The last day of the period, YYYY-MM-DD. rulequery Only the games of one draft rule (empty: every rule). minGamesquery The fewest games a draft or a hero needs to be ranked, 1 to 50.
Example answer {
"period": {
"from": "2026-08-01",
"to": "2026-10-31",
"first": "2026-08-03",
"last": "2026-10-30",
"minMonths": 3
},
"rule": "",
"rules": [
"classic"
],
"minGames": 1,
"totalGames": 120,
"sides": {
"blue": {
"different": 80,
"groups": 12,
"eligible": 9,
"byWinRate": [],
"byPlays": []
},
"red": {
"different": 77,
"groups": 11,
"eligible": 8,
"byWinRate": [],
"byPlays": []
}
},
"duos": {
"all": [],
"mostPlayed": [],
"byLanes": {}
}
}
GET /api/v1/popular/heroesCompetitive scene
The heroes that win and are played most in the tournament games, by lane.
Tool for an AI: popular_heroes
Parameter In Description fromquery The first day of the period, YYYY-MM-DD (the period spans 3 months at least). toquery The last day of the period, YYYY-MM-DD. rulequery Only the games of one draft rule (empty: every rule). minGamesquery The fewest games a draft or a hero needs to be ranked, 1 to 50.
Example answer {
"period": {
"from": "2026-08-01",
"to": "2026-10-31",
"first": "2026-08-03",
"last": "2026-10-30",
"minMonths": 3
},
"rule": "",
"rules": [
"classic"
],
"minGames": 1,
"totalGames": 120,
"lanes": [
{
"lane": "Farm Lane",
"picks": 120,
"all": {
"different": 14,
"eligible": 9,
"byWinRate": [],
"byPlays": [],
"byPresence": []
}
}
],
"placed": 1180,
"unplaced": 20,
"games": 120
}
Your scrims scrims
GET /api/v1/seriesYour scrims
Your series, and the ones a team of yours shared.
Tool for an AI: list_series
Parameter In Description pagequery The page of the list, from 1. pageSizequery How many entries a page holds. viewquery summary (lighter) or full. sortquery updated, oldest or created. statusquery active, complete or draw. modequery The game mode: global-ban-pick, free-for-all or classic. draftModequery The draft mode of the series. qquery Words to look for. fromquery The first day, YYYY-MM-DD. toquery The last day, YYYY-MM-DD.
Example answer {
"items": [
{
"id": "16f3cb87-fb93-4a70-91e0-01f01f863f11",
"teamA": "Alpha",
"teamB": "Bravo",
"bestOf": 3,
"winsRequired": 2,
"gameMode": "free-for-all",
"draftMode": "solo",
"status": "active",
"score": {
"teamA": 1,
"teamB": 0
},
"gamesCount": 1,
"role": "owner",
"createdAt": "2026-10-31T20:15:23.262Z",
"updatedAt": "2026-10-31T20:45:00.000Z"
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
GET /api/v1/series/{id}Your scrims
One series with every game of it.
Tool for an AI: get_series
Parameter In Description id required address The id of the thing.
Example answer {
"id": "16f3cb87-fb93-4a70-91e0-01f01f863f11",
"createdAt": "2026-10-31T20:15:23.262Z",
"updatedAt": "2026-10-31T20:45:00.000Z",
"teamA": {
"name": "Alpha"
},
"teamB": {
"name": "Bravo"
},
"bestOf": 3,
"winsRequired": 2,
"gameMode": "free-for-all",
"draftMode": "solo",
"status": "active",
"games": [],
"currentGame": null,
"version": 4,
"serverTime": 1793477723366,
"viewer": {
"role": "owner",
"side": null,
"canDrive": true
}
}
GET /api/v1/stats/overviewYour scrims
The statistics of your scrims (figures under the minimum sample are withheld).
Tool for an AI: scrim_stats_overview
Parameter In Description statusquery active, complete or draw. modequery The game mode: global-ban-pick, free-for-all or classic. draftModequery The draft mode of the series. qquery Words to look for. fromquery The first day, YYYY-MM-DD. toquery The last day, YYYY-MM-DD. minGamesquery The fewest games a figure needs to be shown.
Example answer {
"label": "Your scrims",
"minGames": 30,
"seriesCount": 14,
"gamesCount": 37,
"totalDurationSeconds": 42180,
"averageDurationSeconds": 1140,
"shortestSeconds": 702,
"longestSeconds": 1598,
"blueWins": 20,
"redWins": 17,
"blueWinRate": 0.541,
"byMode": {
"global-ban-pick": 30,
"free-for-all": 7,
"classic": 0
}
}
GET /api/v1/stats/heroesYour scrims
The per-hero statistics of your scrims.
Tool for an AI: scrim_stats_heroes
Parameter In Description statusquery active, complete or draw. modequery The game mode: global-ban-pick, free-for-all or classic. draftModequery The draft mode of the series. qquery Words to look for. fromquery The first day, YYYY-MM-DD. toquery The last day, YYYY-MM-DD. minGamesquery The fewest games a figure needs to be shown. pagequery The page of the list, from 1. pageSizequery How many entries a page holds. orderquery How the heroes are sorted (presence by default). heroquery Only the heroes whose name holds these letters.
Example answer {
"label": "Your scrims",
"minGames": 30,
"totalGames": 37,
"sort": "presence",
"rows": [
{
"heroId": "h105",
"picks": 12,
"bans": 9,
"wins": 7,
"presence": 0.568
}
],
"total": 1,
"page": 1,
"pageSize": 10
}
GET /api/v1/heroes/{id}/scrimsYour scrims
What your scrims say of one hero: picks, bans, synergies, matchups.
Tool for an AI: hero_scrim_stats
Parameter In Description id required address The id of the thing.
Example answer {
"label": "Your scrims",
"minGames": 30,
"seriesCount": 9,
"totalGames": 37,
"picked": 12,
"wins": 7,
"losses": 5,
"banned": 9,
"winRate": null,
"pickRate": null,
"banRate": null,
"insufficient": true,
"lanes": [],
"synergies": [],
"matchups": []
}
Your tier lists tier-lists
GET /api/v1/tier-listsYour tier lists
Your tier lists, and the ones shared with you.
Tool for an AI: list_my_tier_lists
Parameter In Description pagequery The page of the list, from 1. pageSizequery How many entries a page holds. lanequery Only the lists of one lane. qquery Words to look for.
Example answer {
"items": [
{
"id": "44d20ad7-4f74-4207-80f2-6e0b352ba662",
"name": "Farm lane, season 4",
"lane": "Farm Lane",
"updatedAt": "2026-10-31T20:15:23.224Z"
}
],
"total": 1,
"page": 1,
"pageSize": 50
}
GET /api/v1/tier-lists/{id}Your tier lists
One tier list with its placements.
Tool for an AI: get_my_tier_list
Parameter In Description id required address The id of the thing.
Example answer {
"id": "44d20ad7-4f74-4207-80f2-6e0b352ba662",
"createdAt": "2026-10-31T20:15:23.224Z",
"updatedAt": "2026-10-31T20:15:23.224Z",
"name": "Farm lane, season 4",
"lane": "Farm Lane",
"tiers": [
{
"id": "t1",
"label": "S",
"heroes": [
"h105"
]
}
],
"unranked": [
"h199"
],
"version": 0,
"viewer": {
"role": "owner",
"canEdit": true,
"canDelete": true,
"canShare": true
}
}
Your teams teams
GET /api/v1/me/teamsYour teams
The teams you belong to, with your role in each.
Tool for an AI: my_teams
Example answer {
"items": [
{
"id": "07db7f13-4df0-4d4e-b6c9-453d26c41fe5",
"name": "Learn Squad",
"tag": "LERN",
"region": "EU",
"level": "amateur",
"memberCount": 5,
"myRole": "owner"
}
]
}
GET /api/v1/teamsYour teams
The teams of the community.
Tool for an AI: list_teams
Parameter In Description qquery Words to look for. pagequery The page of the list, from 1. pageSizequery How many entries a page holds. levelquery Only the teams of one level. regionquery Only the teams of one region.
Example answer {
"items": [
{
"id": "07db7f13-4df0-4d4e-b6c9-453d26c41fe5",
"name": "Learn Squad",
"tag": "LERN",
"region": "EU",
"level": "amateur",
"memberCount": 5
}
],
"total": 1,
"page": 1,
"pageSize": 18
}
GET /api/v1/teams/{id}Your teams
One team: its members and its settings that you may see.
Tool for an AI: get_team
Parameter In Description id required address The id of the thing.
Example answer {
"id": "07db7f13-4df0-4d4e-b6c9-453d26c41fe5",
"name": "Learn Squad",
"tag": "LERN",
"description": "",
"region": "EU",
"timezone": "UTC+1",
"languages": [
"en"
],
"level": "amateur",
"maxMembers": 10,
"createdAt": 1793477723239,
"members": [
{
"name": "Kai",
"tag": "YHX7EA",
"role": "owner",
"lane": "Jungle"
}
],
"myRole": "owner"
}
GET /api/v1/teams/{id}/eventsYour teams
The agenda of one of your teams.
Tool for an AI: team_events
Parameter In Description id required address The id of the thing.
Example answer {
"items": [
{
"id": "2b9c0e3a-6f0d-4a8e-b1c2-3d4e5f6a7b8c",
"title": "Scrim vs Bravo",
"startsAt": 1793563200000
}
],
"canSchedule": true
}
GET /api/v1/teams/{id}/seriesYour teams
The series that this team shared with its members.
Tool for an AI: team_series
Parameter In Description id required address The id of the thing.
Example answer {
"items": [],
"total": 0,
"page": 1,
"pageSize": 20
}
GET /api/v1/me/agendaYour teams
Your agenda: the events of all your teams.
Tool for an AI: my_agenda
Parameter In Description fromquery The start of the window, in milliseconds since 1970. toquery The end of the window, in milliseconds since 1970.
Example answer {
"items": [
{
"id": "2b9c0e3a-6f0d-4a8e-b1c2-3d4e5f6a7b8c",
"title": "Scrim vs Bravo",
"startsAt": 1793563200000
}
]
}
Your training training
GET /api/v1/training/focusYour training
The heroes you work on.
Tool for an AI: training_focus
Example answer {
"heroIds": [
"h105",
"h120"
]
}
GET /api/v1/training/notesYour training
Your training notebook.
Tool for an AI: training_notes
Example answer {
"notes": []
}
GET /api/v1/training/combosYour training
The combos you have acquired.
Tool for an AI: training_combos
Example answer {
"progress": {}
}
GET /api/v1/training/combos/reviewYour training
The combos that are due for a check.
Tool for an AI: training_combos_due
Example answer {
"now": 1793477503716,
"due": [],
"dueTotal": 0,
"toLearn": [],
"toLearnTotal": 0,
"skills": {}
}
GET /api/v1/training/mapsYour training
The maps of the situations.
Tool for an AI: training_maps
Example answer {
"maps": []
}
GET /api/v1/training/scenariosYour training
The situations prepared by the staff.
Tool for an AI: list_training_scenarios
Example answer {
"scenarios": []
}
GET /api/v1/training/scenarios/{id}Your training
One situation.
Tool for an AI: get_training_scenario
Parameter In Description id required address The id of the thing.
Example answer {
"id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
"title": "Defend the second tower",
"mapId": "main"
}
GET /api/v1/training/reflexYour training
Your reflex training results.
Tool for an AI: training_reflex
Example answer {
"exercises": {
"reaction": {
"runs": 12,
"best": 231,
"last": []
}
},
"doneToday": [],
"today": {
"runs": 3,
"minutes": 4
},
"week": {
"runs": 12,
"minutes": 18
},
"streak": 2,
"teams": []
}
GET /api/v1/spaceYour training
Your personal space (the builds and notes you keep).
Tool for an AI: my_space
Example answer {
"tierLists": [],
"builds": [],
"training": {
"focus": [],
"notes": [],
"combos": [],
"reflex": {
"streak": 0,
"best": {}
}
},
"links": [],
"limits": {
"builds": 300,
"buildsPerHero": 30,
"links": 20,
"days": [
7
]
}
}
Your account account
GET /api/v1/meYour account
Who the key belongs to (tag and name, never the email), its scopes and its expiry.
Tool for an AI: whoami
Example answer {
"account": {
"tag": "YHX7EA",
"name": "Kai"
},
"key": {
"id": "25bf6418-4cbf-448a-baed-30349809947e",
"name": "Stats bot",
"scopes": [
"game",
"competitive"
],
"expiresAt": 1801253503341
}
}