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
curl -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:

StatuscodeMeaning
400invalid_bodyThe situation sent to the one POST is not valid: the error says what is wrong.
401unauthorizedNo key, or a key that is not valid, has expired or was revoked.
403insufficient_scopeThe key lacks the scope this address needs.
404not_foundUnknown address, or something the owner of the key cannot see.
405method_not_allowedThe API only reads: use GET.
429rate_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
claude 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
{
  "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
{
  "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
http://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

ParameterInDescription
id requiredaddressThe id of the thing.
sincequeryCount 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

ParameterInDescription
family requiredaddressitems, 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

ParameterInDescription
family requiredaddressitems, arcana, spells, stats or tags.
id requiredaddressThe 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

ParameterInDescription
qqueryWords to look for.
pagequeryThe 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

ParameterInDescription
id requiredaddressThe 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
    }
  ]
}

Your scrims scrims

GET/api/v1/seriesYour scrims

Your series, and the ones a team of yours shared.

Tool for an AI: list_series

ParameterInDescription
pagequeryThe page of the list, from 1.
pageSizequeryHow many entries a page holds.
viewquerysummary (lighter) or full.
sortqueryupdated, oldest or created.
statusqueryactive, complete or draw.
modequeryThe game mode: global-ban-pick, free-for-all or classic.
draftModequeryThe draft mode of the series.
qqueryWords to look for.
fromqueryThe first day, YYYY-MM-DD.
toqueryThe 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

ParameterInDescription
id requiredaddressThe 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

ParameterInDescription
statusqueryactive, complete or draw.
modequeryThe game mode: global-ban-pick, free-for-all or classic.
draftModequeryThe draft mode of the series.
qqueryWords to look for.
fromqueryThe first day, YYYY-MM-DD.
toqueryThe last day, YYYY-MM-DD.
minGamesqueryThe 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

ParameterInDescription
statusqueryactive, complete or draw.
modequeryThe game mode: global-ban-pick, free-for-all or classic.
draftModequeryThe draft mode of the series.
qqueryWords to look for.
fromqueryThe first day, YYYY-MM-DD.
toqueryThe last day, YYYY-MM-DD.
minGamesqueryThe fewest games a figure needs to be shown.
pagequeryThe page of the list, from 1.
pageSizequeryHow many entries a page holds.
orderqueryHow the heroes are sorted (presence by default).
heroqueryOnly 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

ParameterInDescription
id requiredaddressThe 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

ParameterInDescription
pagequeryThe page of the list, from 1.
pageSizequeryHow many entries a page holds.
lanequeryOnly the lists of one lane.
qqueryWords 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

ParameterInDescription
id requiredaddressThe 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

ParameterInDescription
qqueryWords to look for.
pagequeryThe page of the list, from 1.
pageSizequeryHow many entries a page holds.
levelqueryOnly the teams of one level.
regionqueryOnly 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

ParameterInDescription
id requiredaddressThe 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

ParameterInDescription
id requiredaddressThe 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

ParameterInDescription
id requiredaddressThe 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

ParameterInDescription
fromqueryThe start of the window, in milliseconds since 1970.
toqueryThe 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

ParameterInDescription
id requiredaddressThe 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
  }
}

Export

Styled report · re-importable

Format

The file contains the series data: import it back from Scrims → Import series. Do not re-save or print it, or the data is lost.