Skip to content

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 = 524288000

Config fields

  • template_folder: directory scanned for .toml template files
  • bind: HTTP listen address for the API service
  • admin_token: enables and secures admin routes; if omitted, admin routes are not mounted
  • upload_folder (optional): directory for uploaded binaries; defaults to <template_folder>/../uploads/
  • max_upload_size (optional): maximum upload size in bytes; defaults to 524288000 (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: malformed template_id
  • 404 template_not_found: unknown template
  • 400 invalid_extra_option: option type mismatch
  • 429 instance_limit_reached: template at max instances
  • 503 no_ports_available: no free port in template range
  • 503 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 recognized
  • 404 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_XXXXXXXXXX under upload_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 path value as binary_path when creating a template; companion files (e.g. .pck) are co-located in the same directory

Primary error cases:

  • 400 file_too_large: a file exceeds max_upload_size
  • 400: no file fields in multipart body
  • 400: 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_XXXXXXXXXX ID
  • Validates template configuration
  • Writes .toml file to template_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 .toml file on disk
  • Updates template in memory
  • Running instances keep their original config

Primary error cases:

  • 404 template_not_found
  • 400 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 .toml file 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_identifier
  • 404 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"
}