Files
horizon/docs/api/server.md
T
Ludovic MarieandClaude Opus 5.5 fd091af76a horizon-server console: attach to the running server
The recent log, then every new line as it happens (the control API's event
stream), a header with the TPS, MSPT, players and RAM refreshed every second on
a terminal (an ANSI scroll region; no TUI framework), and a command line whose
lines run as console commands. Ctrl-D detaches and leaves the server running;
when stdout isn't a terminal it prints plain lines. The admin e2e attaches
through a pipe and runs two commands.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 15:59:57 +01:00

5.5 KiB

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 29 (init, run, start, stop, restart, status, cmd, logs, console, backup, backups, restore, service, panel, update, rollback, config, config set, import, 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 28 under /api/v1

Guide

  1. horizon-server init in an empty folder, then horizon-server start (hosting.md).
  2. From a script: horizon-server status --json, horizon-server cmd say hi, horizon-server backup. By hand: horizon-server console attaches to the running server (live log, status header, command line).
  3. From a program: read .horizon/api.json (address and token), then GET /api/v1/status with Authorization: Bearer <token>. A program that runs elsewhere or keeps its settings (a Discord bot) uses a fixed address and token: [api] bind and [api] token in server.toml (hosting.md).
  4. Moderate: horizon-server players, horizon-server ban NAME [REASON], or POST /api/v1/players/ban. An action runs vanilla's console command on the running game, so it kicks, logs and saves banned-players.json exactly as an operator's /ban does; the reply says whether anything changed and has the console's lines.
  5. Monitor: point Prometheus (or any scraper that sends a bearer token) at GET /api/v1/metrics/prometheus.
  6. Watch: GET /api/v1/events with Accept: text/event-stream streams what happens as server-sent events: every log line (log), the supervisor's phase, and the game's typed join, leave, kick, chat and death events with the player's name and UUID (?types=chat,death picks some). Last-Event-ID (or ?since=N) resumes after a reconnection; without Accept: text/event-stream it answers the events after since as JSON.

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

  • Players: positions in players; editing the lists while the game is stopped through the API (the CLI's op, deop and whitelist already do).
  • Metrics: entities and per-dimension counts in the Prometheus text.
  • Backups: restore a single dimension.
  • Mods on a dedicated server: list, turn on and off, and their settings, once native mods can be built for the server (mods.md, native-mods.md).
  • An MCP server for the same endpoints, so a host's agent manages the server as it manages the game.
  • Compatibility tests: golden replies per endpoint, and a server.toml from each release line.

Changelog

  • api::ROUTES lists the endpoints; the reference is generated from it.
  • /api/v1: status, metrics, logs, command, stop, restart, backups, restore, update, panel login.
  • Commands: players, kick, ban, pardon, ban-ip, pardon-ip.
  • /api/v1 additions: players, players/{kick,ban,pardon,ban-ip,pardon-ip,op,deop}, whitelist, whitelist/{add,remove}, metrics/prometheus, GET/PATCH config, DELETE backups, GET backups/download; server.toml gets [api] (bind, token, allow_public); GET events (server-sent events, or JSON).