Appearance
HTTP API Reference
This page documents all HTTP routes exposed by the server and the server config file that controls route behavior.
API conventions
- Base URL:
http://{host}:{port}/api/v1 - Content type:
application/json - Time fields: RFC3339 timestamps
- Identifier inputs:
- user token: 6 uppercase alphanumeric chars
- instance ID:
inst_+ 10 alphanumeric chars
Server config file
Path is --config-file at runtime (default: /etc/encore/config.toml).
toml
template_folder = "/etc/encore/templates"
bind = "127.0.0.1:8080"
# admin_token = "replace-with-strong-random-token"
# upload_folder = "/var/lib/encore/uploads"
# max_upload_size = 524288000Config fields
template_folder: directory scanned for.tomltemplate filesbind: HTTP listen address for the API serviceadmin_token: enables and secures admin routes; if omitted, admin routes are not mountedupload_folder(optional): directory for uploaded binaries; defaults to<template_folder>/../uploads/max_upload_size(optional): maximum upload size in bytes; defaults to524288000(500 MiB)
Admin authentication
When admin_token is set, send one of:
X-Admin-Token: <token>Authorization: Bearer <token>
Missing/invalid token returns 401 with error code unauthorized.
Routes
GET /health
Purpose: liveness check (not under /api/v1).
Success response:
json
{
"status": "ok",
"service": "encore"
}POST /api/v1/instances (public)
Purpose: create and start an instance from a template.
Request body:
json
{
"template_id": "game_QkMtDm7A2x",
"extra_options": {
"max_players": "10",
"map_name": "dm_foundry"
}
}Request fields:
template_id(required): template identifier (game_+ 10 alphanumeric chars)extra_options(optional): key/value map used for template arg substitution
Behavior notes:
- Returns only after spawn + startup readiness checks complete.
- If template does not define
[template.extra_options], provided options are discarded. - If a key is whitelisted but has wrong type, request fails with
400 invalid_extra_option.
Success response (201):
json
{
"instance_id": "inst_kL9mNpQ2rT",
"user_token": "A7K9M2",
"template_id": "game_QkMtDm7A2x",
"template_name": "Quick Match - Deathmatch",
"host": "dm-na.example.com",
"port": 7042,
"created_at": "2026-02-14T10:30:00Z",
"started_at": "2026-02-14T10:30:05Z"
}Primary error cases:
400 invalid_request: malformedtemplate_id404 template_not_found: unknown template400 invalid_extra_option: option type mismatch429 instance_limit_reached: template at max instances503 no_ports_available: no free port in template range503 instance_startup_timeout: process did not become ready in time
GET /api/v1/instances/{identifier} (public)
Purpose: resolve connection info and status by user token or instance ID.
Path parameter:
identifier: user token or instance ID
Success response (200):
json
{
"instance_id": "inst_kL9mNpQ2rT",
"user_token": "A7K9M2",
"template_id": "game_QkMtDm7A2x",
"template_name": "Quick Match - Deathmatch",
"host": "dm-na.example.com",
"port": 7042,
"created_at": "2026-02-14T10:30:00Z",
"started_at": "2026-02-14T10:30:05Z",
"uptime_seconds": 3600,
"extra_options": {
"max_players": "10",
"map_name": "dm_foundry"
}
}Primary error cases:
400 invalid_identifier: format not recognized404 instance_not_found: unknown or expired instance
GET /api/v1/instances (admin)
Purpose: list running instances.
Success response:
json
{
"instances": [
{
"instance_id": "inst_kL9mNpQ2rT",
"user_token": "A7K9M2",
"template_id": "game_QkMtDm7A2x",
"template_name": "Quick Match - Deathmatch",
"host": "dm-na.example.com",
"port": 7042,
"created_at": "2026-02-14T10:30:00Z",
"started_at": "2026-02-14T10:30:05Z",
"uptime_seconds": 3600,
"extra_options": {}
}
],
"count": 1
}GET /api/v1/templates (admin)
Purpose: list currently loaded templates with status info.
Success response:
json
{
"templates": [
{
"id": "game_QkMtDm7A2x",
"name": "Quick Match - Deathmatch",
"max_instances": 60,
"binary_path": "/opt/gameservers/arena/server.x86_64",
"max_lifetime": "1h",
"running_instances": 3,
"disabled": false
}
],
"count": 1
}POST /api/v1/uploads (admin)
Purpose: upload one or more game server files to the Encore host (e.g. a binary and its asset pack).
Request: multipart/form-data with one or more file fields. Each field must carry the original filename via the multipart filename parameter.
Example — single file:
bash
curl -X POST http://localhost:8080/api/v1/uploads \
-H "x-admin-token: $TOKEN" \
-F "file=@server.x86_64"Example — multiple files (Godot binary + PCK):
bash
curl -X POST http://localhost:8080/api/v1/uploads \
-H "x-admin-token: $TOKEN" \
-F "file=@game.x86_64" \
-F "file=@game.pck"Success response (201):
json
{
"directory": "/var/lib/encore/uploads/upl_AbCdEfGh12",
"files": [
{ "filename": "game.x86_64", "path": "/var/lib/encore/uploads/upl_AbCdEfGh12/game.x86_64", "size": 45678912 },
{ "filename": "game.pck", "path": "/var/lib/encore/uploads/upl_AbCdEfGh12/game.pck", "size": 123456789 }
]
}Behavior:
- Creates a new random directory
upl_XXXXXXXXXXunderupload_folder - Writes every file into that directory keeping its original filename
- Filenames are validated, not sanitised — the request is rejected if any name contains path separators, starts with
., or uses characters outside[a-zA-Z0-9._-] - Duplicate filenames within the same request are rejected
- Each file is made executable (
chmod +x) - Per-file size is enforced against
max_upload_size(default 500 MiB) - Use the entry-point file's
pathvalue asbinary_pathwhen creating a template; companion files (e.g..pck) are co-located in the same directory
Primary error cases:
400 file_too_large: a file exceedsmax_upload_size400: nofilefields in multipart body400: invalid or duplicate filename
POST /api/v1/templates (admin)
Purpose: create a new template via API.
Request body:
json
{
"name": "My Game Server",
"binary_path": "/var/lib/encore/uploads/upl_AbCdEfGh12_my-server",
"max_instances": 10,
"max_lifetime": "2h",
"port_liveness_probe": false,
"args": ["--port={{port}}", "--instance={{instance_id}}"],
"working_dir": null,
"env": { "GAME_MODE": "production" },
"extra_options": { "max_players": "int", "map_name": "string" },
"isolation": null
}Only name and binary_path are required. All other fields use template defaults.
Success response (201):
json
{
"id": "game_AbCdEfGh12",
"name": "My Game Server",
"binary_path": "/var/lib/encore/uploads/upl_AbCdEfGh12_my-server",
"max_instances": 10,
"max_lifetime": "2h",
"port_liveness_probe": false,
"args": ["--port={{port}}", "--instance={{instance_id}}"],
"working_dir": null,
"env": { "GAME_MODE": "production" },
"extra_options": { "max_players": "int", "map_name": "string" }
}Behavior:
- Server generates
game_XXXXXXXXXXID - Validates template configuration
- Writes
.tomlfile totemplate_folder - Loads template into in-memory state
Primary error cases:
400 validation_error: invalid template configuration
GET /api/v1/templates/{id} (admin)
Purpose: get full details of a single template.
Success response (200): Full template JSON (same shape as create response).
Primary error cases:
404 template_not_found
PUT /api/v1/templates/{id} (admin)
Purpose: update an existing template. All fields are optional (partial update / merge semantics). The id cannot be changed.
Request body: same shape as create, all fields optional.
Success response (200): Full updated template JSON.
Behavior:
- Validates updated configuration
- Overwrites the existing
.tomlfile on disk - Updates template in memory
- Running instances keep their original config
Primary error cases:
404 template_not_found400 validation_error
DELETE /api/v1/templates/{id} (admin)
Purpose: delete a template.
Success response (200):
json
{
"message": "Template deleted successfully",
"id": "game_AbCdEfGh12",
"had_running_instances": false
}Behavior:
- Deletes
.tomlfile from disk - If running instances exist: marks template as spawn-disabled
- If no running instances: removes template from memory entirely
- Does NOT delete uploaded binaries (they may be shared)
Primary error cases:
404 template_not_found
DELETE /api/v1/instances/{identifier} (admin)
Purpose: terminate a running instance by user token or instance ID.
Success response:
json
{
"message": "Instance terminated successfully",
"instance_id": "inst_kL9mNpQ2rT",
"user_token": "A7K9M2"
}Primary error cases:
400 invalid_identifier404 instance_not_found
POST /api/v1/serve/reload (admin)
Purpose: reload templates from disk and reconcile them with in-memory state.
Success response:
json
{
"message": "Template reload complete",
"added": 1,
"updated": 2,
"removed": 0,
"kept_disabled": 0,
"reenabled": 0,
"total_templates": 3,
"disabled_templates": 0
}Error envelope
Error responses always include message. Most also include an error code.
Example:
json
{
"error": "invalid_extra_option",
"message": "Invalid type for 'max_players': expected int, got string value 'abc'",
"parameter": "max_players",
"expected_type": "int",
"provided_value": "abc"
}