REST API Reference
The HTTP API exposed by the Saba-chan daemon. Authentication scheme and a catalog of the major endpoints.
REST API Reference
The Saba-chan daemon (saba-core) exposes an HTTP REST API on 127.0.0.1:57474. The GUI and CLI call only this API, and Discord commands arriving through the Cloud Relay are processed by the same functionality inside the daemon. You can build a custom client against the same contract.
This reference summarizes the routes a user or integrator is likely to need, taken from the daemon's route definitions (src/ipc/). Some internal routes are omitted, and field schemas may change, so consult the code for the latest.
1. Basics
- Base URL:
http://127.0.0.1:57474(default). Can be changed via theSABA_IPC_PORTenvironment variable orgui.ipcPortinconfig.json(takes effect after the daemon restarts). - Bind address: Fixed to
127.0.0.1, so it isn't reachable from outside. Requests whoseHostheader is not loopback (127.0.0.1,localhost,::1) get a 403. - Authentication: Every request except
/healthneeds anX-Saba-Tokenheader. The daemon generates a new token each time it starts and writes it to the.ipc_tokenfile in the data folder (Windows:%APPDATA%\saba-chan\.ipc_token). A missing or wrong token gets a 401 with no body. - Content-Type: Request bodies are
application/json. Most responses are JSON too (extension GUI bundles, icons, etc. are exceptions). - Error format: Varies by route. Common shapes are
{"error": "...", "error_code": "..."},{"success": false, "error": ..., "error_code": ...}, and{"ok": false, "error": ...}. Some routes return HTTP 200 withok:falseon failure, so check the body as well.
2. Health check & daemon
GET /health # no token required
GET /api/version
GET /api/diagnostics
GET /api/events # event stream (SSE)
POST /api/daemon/shutdown
/health:{"ok": true, "version": "x.y.z", "pid": 1234, "token": "valid" | "invalid" | "missing"}.tokenonly tells you whether theX-Saba-Tokenyou sent is correct; it never reveals the value./api/version:{version, components: {...}}(core, module, and extension versions)./api/events: Server-Sent Events. The main kinds areinstance.exit(server exit / crash verdict),backup.done,update.available,schedule.warn,provision.progress, andaction.run. When reconnecting, you can catch up on missed events with theLast-Event-IDheader or?since=<n>./api/daemon/shutdown: Shuts the daemon down.
3. Servers (instances)
Saba-chan manages each server as an instance, identified by a UUID (id). The older /api/server/:name/* paths identify servers by name, but new clients should use /api/instance/:id/*.
3.1 Listing, creating, updating, deleting
GET /api/servers # server list + running state
GET /api/instances # instance list
POST /api/instances # create
PUT /api/instances/reorder # body: { "order": [id, ...] }
GET /api/instance/:id # details (+ terms consent state in agreements)
PATCH /api/instance/:id # change settings (key-value object)
DELETE /api/instance/:id # delete
POST /api/instance/:id/rename # body: { "name": "..." }
- Main fields of
POST /api/instances:{ "name", "module_name", "port"?, "preset"?, "module_settings"?, "accept_agreements"?: [id] }. On success it returns 201{success, id, ...}, and if the module defines an install step, installing the server files starts in the background (§3.5). - Besides the port and module settings,
PATCH /api/instance/:idalso accepts daemon settings such as:auto_restart,restart_on_unknown_exit: whether to restart automatically after a crash / an unknown exitextra_args: extra launch arguments (a string or an array of strings;nullclears them)memory_limit_mb: memory limit (MiB, at least 256;"4G"/"4096M"forms are accepted;null/0means no limit). Applies on Windows only.
- Renaming requires the server to be stopped; a name already in use returns 409
name_taken.
3.2 Start / stop / restart
POST /api/instance/:id/start
POST /api/instance/:id/stop # optional body: { "force": true }
POST /api/instance/:id/restart # optional body: { "force": true }
GET /api/instance/:id/events # recent exit history
GET /api/server/:name/status # status by name (older path)
- Before starting, the daemon checks terms consent and runs the module's checks. Unaccepted terms return 409
agreement_required(withagreements); a critical check failure returns 409preflight_failed. - Stopping sends the game's graceful stop command, waits for the module's timeout (30 seconds by default), and force-kills the process if it's still alive. With
force: trueit is killed immediately. eventsreturns{events: [...]}with the exit verdict (user_stop,in_game_stop,crash,unknown_exit), its evidence, any scheduled auto restart, and so on.
3.3 Console and commands
GET /api/instance/:id/console?since=<id>&count=<n>
POST /api/instance/:id/stdin # body: { "command": "say hello" }
POST /api/instance/:id/command # body: { "command": "<name>", "args"?: {...} }
GET /api/instance/:id/commands # commands available for this server
POST /api/instance/:id/rest # REST-only games (e.g. Palworld)
POST /api/instance/:id/rcon # compatibility name; actually sends to the console (stdin)
- Console polling: The response is
{success, lines: [{id, timestamp, source, content, level}], running, ...}. Withsince, lines whoseidis greater than or equal to it are returned, so send the lastidyou received+ 1next time. Withoutsince, you get the most recentcountlines (default 100). The daemon keeps the last 10,000 lines per server in memory. - RCON is not used. Commands go to the server console (stdin), and games that support only REST, like Palworld, go through REST.
/rconis a path kept only by name for older clients and always sends to stdin. Servers without a console return 409no_command_path. /stdinreturns 409stdin_not_supportedif the module doesn't support stdin./commandruns a command defined by the module; if the server is stopped it returns 409server_not_running.
3.4 Settings, terms, checks
POST /api/instance/:id/launch-preview # body: { "settings"?: {...}, "extra_args"?: "..." }
POST /api/instance/:id/agreements # body: { "accept": ["eula"] }
GET /api/instance/:id/properties # read the game's config file
PUT /api/instance/:id/properties # body: { "settings": {...} }
POST /api/instance/:id/validate # server check
POST /api/instance/:id/diagnose # log diagnosis
launch-previewcomputes the launch command line without starting the server. Example response:{success: true, has_launch_args, command_line, program, args, extra_args, errors: [...]}. Password values are masked as***. If the module declares no launch arguments, it returnshas_launch_args: false.agreementsrecords consent to terms the module declares (e.g. Minecrafteula). It works locally only; requests from remote sources (Discord, etc.) get 403agreement_local_only. Undeclared ids get 400invalid_format.
3.5 Install progress and game server updates
GET /api/provision-progress/:name # :name = instance name
DELETE /api/provision-progress/:name # dismiss a failed progress state
GET /api/instance/:id/check-update
POST /api/instance/:id/apply-update
Example provision-progress response:
{
"active": true,
"step": 2,
"total": 5,
"label": "...",
"message": "...",
"percent": 40,
"done": false,
"error": null
}
When nothing is in progress it returns {"active": false}. A successful progress state is cleared automatically after 5 seconds; a failed one stays until you dismiss it with DELETE (if the server was being newly created, it is rolled back at that point). Progress is also available as provision.progress on /api/events.
apply-update returns 409 server_running if the server is running. A backup is taken before updating (for modules that support backups).
3.6 Backups and scheduled tasks
GET /api/instance/:id/backups # { success, backups: [{ name, kind, created, size }] }
POST /api/instance/:id/backups # back up now
DELETE /api/instance/:id/backups/:name
POST /api/instance/:id/backups/:name/restore # server must be stopped
GET /api/instance/:id/schedule
PUT /api/instance/:id/schedule # body: { "schedule": [...], "backup_keep"?: 10 }
- Backup
kind:manual,scheduled,pre-update,pre-restore. If the module doesn't support backups you get 400backup_unsupported; if there's nothing to back up yet, 400nothing_to_back_up. - Restoring returns 409
server_runningif the server is running, and the current state is backed up aspre-restorebefore restoring. - The shape of one scheduled task:
{ "action": "restart", "at": "05:00", "warn_minutes": [10, 5, 1], "enabled": true }
action is backup | restart | announce | update, and you use exactly one of every_minutes (every N minutes) and at (daily at HH:MM). announce needs a message, and warn_minutes applies only to restart and update. Invalid tasks return 400 validation_failed (with details).
4. Modules
GET /api/modules # installed modules
POST /api/modules/refresh # re-read the modules folder
GET /api/module/:name # module metadata
GET /api/module/:name/versions # installable game server versions
GET /api/module/:name/locales
GET /api/modules/manifest # catalog of installable modules
POST /api/modules/manifest/:id/install # install a module from the catalog
DELETE /api/modules/:id # remove a module
The module catalog comes from the signed release list, and downloaded files are installed only after their hash is verified.
5. Extensions
GET /api/extensions # list with install/enabled state
POST /api/extensions/rescan
GET /api/extensions/manifest # catalog of installable extensions
GET /api/extensions/updates
POST /api/extensions/:id/install
DELETE /api/extensions/:id
POST /api/extensions/:id/enable # runs the daemon.startup hook asynchronously
POST /api/extensions/:id/disable
GET /api/extensions/:id/config
PUT /api/extensions/:id/config
GET /api/extensions/:id/gui # GUI bundle (UMD JavaScript)
GET /api/extensions/:id/gui/styles # CSS
GET /api/extensions/:id/i18n/:locale # ko / en / ja / ...
Errors from extension routes use the {success: false, error, error_code, ...} shape.
6. Settings
GET /api/config/gui
PUT /api/config/gui # partial JSON (shallow merge)
GET /api/config/bot
PUT /api/config/bot # bot settings such as prefix and aliases (partial JSON)
GET /api/system/metrics # CPU, memory, disk, per-server usage
All user settings are stored per namespace in a single config.json file in the data folder. The daemon syncs bot settings to the relay. The Discord bot itself runs on the Cloud Relay, so the daemon has no API to start or stop a bot process.
7. Updates
GET /api/updates/status # current state and per-component versions
POST /api/updates/check # check for updates now
POST /api/updates/download # optional body: { "components": [...] }
GET /api/updates/download/progress
POST /api/updates/apply # optional body: { "components": [...] }
POST /api/updates/launch-updater # launch the updater (the daemon stops)
GET /api/updates/config
PUT /api/updates/config
Update information comes from the signed release list. Components whose running files must be replaced are flagged in the apply response as needing the updater; calling launch-updater starts the separate updater, which stops, replaces, and restarts the daemon. These routes respond in the {ok: ...} shape.
8. Cloud Relay pairing
For the GUI ↔ relay server pairing flow. See the Discord Bot page for the detailed flow.
POST /api/relay/pair/initiate # issue a pairing code (forwarded to the relay)
GET /api/relay/pair/:code/status # poll whether pairing has completed
GET /api/relay/agent # relay agent status
POST /api/relay/agent/start
POST /api/relay/agent/stop
DELETE /api/config/node-token # delete this PC's node token (stops the agent)
Once pairing completes (status: "claimed"), the daemon saves the node token automatically and reconnects the relay agent with the new token. The daemon handles authentication toward the relay, so clients don't need to deal with it.
9. Authentication example (curl)
TOKEN=$(cat "$APPDATA/saba-chan/.ipc_token")
curl -H "X-Saba-Token: $TOKEN" \
http://127.0.0.1:57474/api/servers
curl -X POST \
-H "X-Saba-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"command":"list"}' \
http://127.0.0.1:57474/api/instance/<instance-id>/stdin
<instance-id> is the id from the GET /api/servers or GET /api/instances response.
10. Version compatibility
- This API is classified as a private IPC. It isn't a public contract, so paths and schemas may change even in minor versions.
- If you distribute a custom client, check the daemon version (
versionfromGET /health) and handle it conservatively.
If you run into problems, head to Troubleshooting.