NGCP Game server control panel
Documentation
Contents

Reference

API

Everything the web panel does goes through a REST API under /api/v1, documented as OpenAPI 3.1. Use it for billing systems, Discord bots, scripts and monitoring.

  • API reference: every endpoint, parameter and response, generated from the OpenAPI document.
  • Your own panel serves the same reference at /api/v1/docs and the raw document at /api/v1/openapi.json.

Authentication

There are two ways to authenticate.

Create a key on your account page under API keys (Users and permissions) and send it as a bearer token:

curl -s https://panel.example.com/api/v1/services \
  -H "Authorization: Bearer ngcpk_..."
  • A key acts as the account that created it, limited by the key’s scopes if it has any.
  • Keys do not need CSRF tokens.
  • Keys cannot create other keys, change passwords or change two-step verification.
  • The admin IP allow-list applies to keys of SuperAdmins and Admins.
  • A scoped key reaches services only if its scopes include services:all or services:create.
  1. Sign in:

    curl -s -c jar.txt -H "Content-Type: application/json" \
      -d '{"login": "alice", "password": "..."}' \
      https://panel.example.com/api/v1/auth/login
    

    The answer is either {"status": "ok", "csrf_token": "...", "user": {...}}, or, with two-step verification on, {"status": "mfa_required", "mfa_token": "..."}. In the second case send the code within five minutes:

    curl -s -c jar.txt -H "Content-Type: application/json" \
      -d '{"mfa_token": "...", "code": "123456"}' \
      https://panel.example.com/api/v1/auth/login/mfa
    

    ("recovery_code" instead of "code" uses a recovery code.)

  2. The session lives in the ngcp_session cookie (HttpOnly). Every state-changing request (POST, PUT, PATCH, DELETE) must also carry the CSRF token in the X-CSRF-Token header. GET /api/v1/auth/me returns it again:

    curl -s -b jar.txt -X POST -H "X-CSRF-Token: <csrf_token>" \
      https://panel.example.com/api/v1/services/12/restart
    
  3. POST /api/v1/auth/logout ends the session; POST /api/v1/auth/logout-all ends all of yours.

Request bodies must be JSON (Content-Type: application/json); the only exception is upload chunks.

Responses

Status Meaning
200 OK, body follows
201 Created
202 Accepted: the node does the work and reports later (backups, restores)
204 Done, no body
401 Not signed in, or the key is invalid / expired
403 Signed in, but not allowed
404 Not found, or you are not allowed to see it (services and accounts you may not see are “not found”)
409 Conflict with the current state (wrong status, node offline, in use)
422 Validation failed
429 Rate limited; wait for Retry-After

Errors

Every error uses the same envelope:

{
  "error": {
    "code": "validation_failed",
    "message": "slots must be 2 to 256",
    "details": [
      {"location": "body.slots", "message": "must be 2 to 256", "value": 500}
    ]
  }
}

code is stable and meant for programs; message is meant for people. Common codes:

Code When
unauthenticated No or invalid credentials
invalid_credentials, invalid_mfa_code Sign-in failed
account_locked, account_inactive Lockout, suspended or disabled account
csrf_failed Missing or wrong X-CSRF-Token on a cookie request
mfa_enrollment_required The account must turn on two-step verification first
ip_not_allowed The admin IP allow-list refused the address
forbidden Missing permission
not_found Missing or not visible
conflict See message, for example “the service’s node is offline”
last_superadmin The last active SuperAdmin cannot be changed that way
validation_failed See details
rate_limited Too many requests

Unknown paths under /api/ always answer with this envelope, never with the web page.

Rate limits

Who Limit
Sign-in, per IP 10 attempts, then one every 6 seconds
Signed-in callers (session or key) Bursts of 200, then 20 requests per second
Anonymous endpoints, per IP Bursts of 60, then 10 per second

Behind a reverse proxy, set NGCP_TRUSTED_PROXIES so limits apply per client, not per proxy.

Common tasks

H='Authorization: Bearer ngcpk_...'
P=https://panel.example.com/api/v1

# Services you can see, with live status
curl -s "$P/services" -H "$H"

# Start / stop / restart / kill / update / reinstall / cancel_install / suspend / unsuspend
curl -s -X POST "$P/services/12/start" -H "$H"

# Send a console line
curl -s -X POST "$P/services/12/console" -H "$H" -H 'Content-Type: application/json' -d '{"line": "say hello"}'

# Create a service
curl -s -X POST "$P/services" -H "$H" -H 'Content-Type: application/json' \
  -d '{"name": "Survival", "game_id": "minecraft_java", "node_id": 3, "slots": 20,
       "variables": {"accept_eula": "true"}, "start": true}'

# Nodes with status and metrics
curl -s "$P/nodes" -H "$H"

# Audit log
curl -s "$P/audit-events?limit=50" -H "$H"

Automation endpoints: Scheduled tasks, Backups, RCON and player counts, Mod manager, Notifications.

WebSocket

GET /ws upgrades to a WebSocket that carries live service updates and consoles. Browsers authenticate with the session cookie; tools can send Authorization: Bearer ngcpk_... on the upgrade request. The Origin, if sent, must be the panel’s own host.

Messages are JSON. Subscribe to topics:

{"type": "subscribe", "topic": "service:12"}
{"type": "subscribe", "topic": "console:12"}
{"type": "unsubscribe", "topic": "console:12"}
{"type": "input", "service_id": 12, "line": "say hello"}
Topic Needs Events
service:<id> view service (the service with its status, players …), metrics (CPU, memory, processes), backups (a backup or restore changed), deleted
console:<id> console console: {"service_id": 12, "lines": [...], "backlog": false}. A batch with backlog: true replaces what you show (sent first, and after an agent reconnect).

Events look like {"type": "metrics", "topic": "service:12", "data": {...}}. Control answers are {"type": "subscribed" | "unsubscribed" | "error", "topic": "...", "message": "..."}.

  • One socket can hold up to 64 topics. input lines are console input and are audited.
  • The server pings every 25 seconds and re-checks your session every 30 seconds; signing out closes the socket with code 4001.
  • A client that cannot keep up is disconnected (code 1013); reconnect and subscribe again.

Versioning

The API path carries the major version (/api/v1). NGCP is pre-1.0: endpoints may still be added or changed between releases; check the changelog. GET /api/v1/version returns the controller’s build version.