Server API
What a host, a panel or a bot can do with a Horizon server: the horizon-server commands, server.toml and the control API. How to host: hosting.md; the design: server.md.
Overview
horizon-server sets up a server folder, runs the game as a dedicated server under a supervisor (restarts on a crash, backups on a schedule, updates with a rollback), and lets other programs manage it through a local HTTP API with a token. The web panel uses that API, and so can a moderation bot: players, kick, ban and pardon (by name or address), op and deop, the whitelist, and metrics as Prometheus text.
| Count | |
|---|---|
| Commands | 30 (init, run, start, stop, restart, status, cmd, logs, console, backup, backups, restore, service, panel, update, rollback, config, config set, import, mcp, op, deop, whitelist, players, kick, ban, pardon, ban-ip, pardon-ip, version) |
server.toml keys | 25 in 7 sections, plus [properties] for any other vanilla key |
| Control API endpoints | 30 under /api/v1 |
Guide
horizon-server initin an empty folder, thenhorizon-server start(hosting.md).- From a script:
horizon-server status --json,horizon-server cmd say hi,horizon-server backup. By hand:horizon-server consoleattaches to the running server (live log, status header, command line). When the game is stopped, the supervisor and API remain available:POST /api/v1/start(orhorizon-server start) starts it again. From an AI agent:horizon-server --dir /srv/minecraft mcpis an MCP server on stdio with a tool per endpoint (players,ban,events,set_config...); add it to the agent's MCP servers, run as the server's user. - From a program: read
.horizon/api.json(address and token), thenGET /api/v1/statuswithAuthorization: Bearer <token>. A program that runs elsewhere or keeps its settings (a Discord bot) uses a fixed address and token:[api] bindand[api] tokeninserver.toml(hosting.md). - Moderate:
horizon-server players,horizon-server ban NAME [REASON], orPOST /api/v1/players/ban. An action runs vanilla's console command on the running game, so it kicks, logs and savesbanned-players.jsonexactly as an operator's/bandoes; the CLI also edits the vanilla list directly while stopped. The reply says whether anythingchangedand has the console's lines. - Monitor: point Prometheus (or any scraper that sends a bearer token) at
GET /api/v1/metrics/prometheus. - Watch:
GET /api/v1/eventswithAccept: text/event-streamstreams what happens as server-sent events: every log line (log), the supervisor'sphase, and the game's typedjoin,leave,kick,chatanddeathevents with the player's name and UUID (?types=chat,deathpicks some).Last-Event-ID(or?since=N) resumes after a reconnection; withoutAccept: text/event-streamit answers the events aftersinceas JSON. - A tool written for vanilla: turn on vanilla's management protocol (
management-server-enabled = truein[properties], hosting.md); it answers as vanilla 26.3's does, andrpc.discoverdescribes it. - A tool that speaks RCON (a hosting panel, a Discord bridge): turn on
enable-rconwith a password in[properties](hosting.md); a command runs as one typed in the console. - A tool that reads the GS4 query (a server list, a status page): turn on
enable-queryin[properties](hosting.md); it answers the MOTD, the version and the players over UDP.
Reference
server-reference.md, generated from horizon-server's source: the help text, every server.toml key with its default and the server.properties key it writes, and every endpoint.
Examples
token=$(jq -r .token .horizon/api.json); address=$(jq -r .address .horizon/api.json)
curl -s -H "Authorization: Bearer $token" "http://$address/api/v1/status"
curl -s -H "Authorization: Bearer $token" -d '{"line": "list"}' "http://$address/api/v1/command"
curl -s -H "Authorization: Bearer $token" "http://$address/api/v1/players"
curl -s -H "Authorization: Bearer $token" -d '{"name": "Steve", "reason": "griefing"}' "http://$address/api/v1/players/ban"
# {"changed":true,"output":["Banned Steve: griefing"]}
curl -s -H "Authorization: Bearer $token" "http://$address/api/v1/metrics/prometheus"
curl -sN -H "Authorization: Bearer $token" -H "Accept: text/event-stream" "http://$address/api/v1/events?types=join,chat,death"
# id: 41
# event: chat
# data: {"id":41,"type":"chat","name":"Steve","uuid":"...","message":"hi","time":1793451234567}
curl -s -H "Authorization: Bearer $token" -X PATCH -d '{"changes": {"world.difficulty": "hard"}}' "http://$address/api/v1/config"
# {"applied":["world.difficulty"],"restart":[],"running":true,"saved":["world.difficulty"]}
curl -s -H "Authorization: Bearer $token" -o world.zip "http://$address/api/v1/backups/download?name=2026-10-31T12-00-00Z-manual.zip"Stability
Stable (stability.md): the commands, server.toml's keys and /api/v1. A new key or endpoint is an addition; a change to one starts /api/v2, served beside /api/v1.
Not there yet
- Mods on a dedicated server: turn on and off, and their settings, once native mods can be built for the server (mods.md, native-mods.md).
GET /api/v1/modslists the native mods the game program was built with. - Vanilla's management protocol:
serversettings/*(the live settings not yet done) and the world upgrade's notifications (the others are sent). The methods answer an internal error saying so; a kick's translatable message is sent as its key. - Compatibility tests: golden replies for the remaining endpoint groups (the lifecycle replies are pinned), and a
server.tomlfrom each release line.
Changelog
api::ROUTESlists the endpoints; the reference is generated from it./api/v1: status, metrics, logs, command, start, stop, restart, backups, restore, update, panel login.- Commands:
players,kick,ban,pardon,ban-ip,pardon-ip. /api/v1additions:players,players/{kick,ban,pardon,ban-ip,pardon-ip,op,deop},whitelist,whitelist/{add,remove}, stopped-server list edits,metrics/prometheus,GET/PATCH config,DELETE backups,GET backups/download,GET crash-reports(the files incrash-reports/) andGET crash-reports/read?name=(one report's text; only names the list holds);POST startresumes a stopped supervisor;server.tomlgets[api](bind,token,allow_public);GET events(server-sent events, or JSON).- The API compatibility suite pins the
/api/v1status, metrics, logs, start, stop and restart replies. - RCON (
enable-rcon,rcon.port,rcon.password): vanilla's remote console, served by the supervisor. - GS4 query (
enable-query,query.port): vanilla's UDP query (handshake, basic and full stat), served by the supervisor. - Vanilla's management protocol (
management-server-*): the WebSocket, its authentication,rpc.discover,players,players/kick,server/{status,save,stop,system_message}, and the four lists' getters. - The management protocol's TLS (on by default, as in vanilla): a PKCS12 keystore, or a self-signed one generated in
.horizon/when none is set. - The management protocol's
allowlist/{add,remove,set,clear}andbans/{add,remove,set,clear}. - The management protocol's
ip_bans/{add,remove,set,clear}andoperators/{add,remove,set,clear}.
Edit this page on GitHub · Spotted something wrong? Open an issue or ask on Discord.