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

84 lines
5.5 KiB
Markdown

# 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](../hosting.md); the design: [server.md](../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](../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](../hosting.md#a-bot-or-a-tool-of-your-own)).
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](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
```sh
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](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](../mods.md), [native-mods.md](../native-mods.md#multiplayer)).
- **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).