Server Orchestrator Integration Guide

ServerSpawn API

An API for creating, querying, and tearing down dedicated game servers on the BisectHosting Global Network on-demand, one server per match, lobby, or session.

ServerSpawn™ API

Introduction


ServerSpawn™ allows game developers and platforms to instantly provision, manage, and tear down dedicated BisectHosting game servers remotely on the BisectHosting Global Network, whether you need one server per match, lobby, or play session. Once a server is live, fetch and modify its configuration and runtime state through the Starbase™ panel UI or headlessly via the Starbase™ API (Headless API). The Client API endpoints documented below cover power, console, players, and more.

Audience: server-side / backend engineers. Every call is a server-to-server HTTP request authenticated with an API key. Do NOT ship an API key in a game client.

Dynamic Values


A couple of values are environment-specific and are intentionally left as placeholders throughout this guide. BisectHosting will provide the concrete values for your environment:

PlaceholderMeaning
<PANEL_HOST> The panel host the API is served from, e.g. https://games.example.com. All paths below are relative to this host.
<GAME_EGG_ID> The numeric egg ID for your game image in your environment. Used as egg_id on every provision call.

Region IDs are not hardcoded in this document on purpose; they differ per environment and can change. Always read them live from the regions discovery endpoint.

1Concepts & conventions


  • Base path (ServerSpawn API):
    <PANEL_HOST>/api/serverspawn/v1
  • Base path (Client API):
    <PANEL_HOST>/api/client
  • Transport: HTTPS, JSON.
    Send Content-Type: application/json and Accept: application/json on every request. Do not use cookies or CSRF tokens.
  • Account-scoped: every server created with a given API key is owned by that key's user account.
    The plan tier and billing context are fixed by BisectHosting (you do not choose them) and usage is billed automatically.
  • match_id is your handle: you supply your own identifier (your match/session ID) on provision, and you use it again to look up or tear down that server.
    You never need to persist our internal server ID, but you can also use the returned uuid if you prefer.

match_id rules (read this)

  • You choose it. Allowed characters: ASCII letters, numbers, dashes, and underscores (alpha_dash), 1-128 chars.
  • It is single-use, forever, per account. Every provision attempt, successful or failed, permanently records your match_id. You may not reuse a match_id, even after the server has been deprovisioned. Generate a fresh, unique match_id for every provision call (a UUID, or your own guaranteed-unique key).

uuid vs match_id

provision and status return a uuid (the canonical server identifier). Either identifier works:

  • The ServerSpawn API (/status, /deprovision) accepts match_id oruuid; supply one, not both. If you supply both, it will result in an API error.
  • The Client API addresses a server by uuid in the path (/api/client/servers/{uuid}). The full uuid returned here plugs in directly.

2Authentication


2.1 · Enable ServerSpawn access (one-time)

API keys are ordinary account API keys, but the ServerSpawn endpoints are gated behind a per-account flag. A BisectHosting admin enables “ServerSpawn Access” on the account you'll integrate with. Until that is on, every /api/serverspawn/v1/* call returns:

http
403 Forbidden
{ "errors": [ { "code": "AccessDeniedHttpException", "status": "403", "detail": "You do not have server spawn access." } ] }

Ask your BisectHosting contact to enable ServerSpawn Access on your integration account before you start.

2.2 · Create a new API key

  1. Sign in to the panel at <PANEL_HOST> with the integration account.
  2. Open Account → API Credentials.
  3. Click Create, give it a description (e.g. game-prod), and, recommended, set Allowed IPs (a newline-separated allowlist of your backend's egress IPs). Leave blank to allow any IP.
  4. The full key is shown exactly once. Copy it now and store it in your secrets manager. It looks like:
api key
ptlc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

(A 16-character ptlc_… identifier immediately followed by a 32-character secret; a 48-character token in total.)

You may hold up to 25 keys per account. Keys can be revoked any time from the same screen.

Programmatic creation is also possible (POST /api/client/account/api-keys), but it itself requires an existing key/session, so use the panel UI to mint your first key.

2.3 · Send the key

Every request carries the key as a bearer token:

http
Authorization: Bearer ptlc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

2.4 · Rate limit

The ServerSpawn API shares the Client API limiter: 720 requests/minute per account (keyed by account). Exceeding it returns 429 Too Many Requests. Provisioning is far below this ceiling in practice; the limit mainly matters if you poll /status aggressively, so poll at a sane interval (e.g. every 2 to 5s).

3ServerSpawn API endpoints


Three simple endpoints make up the ServerSpawn API:

MethodPathPurpose
POST/api/serverspawn/v1/provisionCreate a server for a match.
GET/api/serverspawn/v1/status Look up a server's lifecycle status.
POST/api/serverspawn/v1/deprovisionSafely delete (terminate) a server.

Across all three endpoints, business errors return a JSON envelope with a machine-readable code and a human-readable error message (plus match_id when known). Shared codes include server_not_found (404) and unexpected_error (500); validation problems return 422 with the field-level errors array instead. Per-endpoint codes are listed with each endpoint below.

3.1 · Provision a server

POST/api/serverspawn/v1/provision

Creates a server synchronously: BisectHosting selects a viable node in your requested region, reserves networking, creates the server, and begins installation. On success you receive the server identity and connection details immediately, with status installing.

Request body

FieldTypeRequiredNotes
match_idstringRequired Your unique handle for this server. ASCII alpha_dash, 1-128 chars. Single-use (see match_id rules).
region_idintegerRequired A region ID from the regions endpoint. The server is placed on the best node in that region (with automatic fallback to the region's secondary).
egg_idintegerRequired The game image. Use <GAME_EGG_ID>.
ramintegerRequired Memory in MB. Range 1 to 49152 (48 GB).
dedicated_ipbooleanRequiredtrue = dedicated IP for this server; false = shared IP (port-mapped).
dedicated_portintegerOptional Only meaningful with dedicated_ip: true. A preferred starting port 1 to 65535, used only when the egg doesn't define its own default dedicated port (the egg default takes precedence).
schedule_restartsnumber[]Optional Hours of day (e.g. [4, 16]) at which to schedule automatic restarts.
env_variablesobjectOptional Map of startup-variable overrides, {"KEY":"value"}. Keys must be variables defined on the egg (unknown keys are rejected). Applied on top of the egg defaults before first boot.

Example request

bash
curl -sS -X POST "<PANEL_HOST>/api/serverspawn/v1/provision" \
  -H "Authorization: Bearer ptlc_XXXXXXXX..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "match_id": "match-7f3a9c2e",
    "region_id": 12,
    "egg_id": <GAME_EGG_ID>,
    "ram": 8192,
    "dedicated_ip": false,
    "schedule_restarts": [5],
    "env_variables": {
      "SERVER_NAME": "Match 7f3a9c2e",
      "MAX_PLAYERS": "60"
    }
  }'

The env_variables keys above are illustrative. The exact variable names come from your game's egg; discover them per server via the Client API GET .../startup endpoint, or ask BisectHosting for the variable list. Unknown keys fail validation.

Success · 200 OK

json
{
  "status": "installing",
  "server": {
    "uuid": "d3f1c8a0-7b2e-4a6c-9f10-2a3b4c5d6e7f",
    "match_id": "match-7f3a9c2e",
    "connection": { "ip": "203.0.113.42", "port": 7777 }
  }
}
  • status is always installing immediately after a successful provision; the server then installs and boots asynchronously on the node. Poll /status until it reports ready before directing players to it.
  • connection.ip / connection.port are the game server's address. (For a brand-new dedicated IP these may take a moment to finalize; re-read them from /status if null.)

Error responses

Business errors share a consistent JSON envelope: a machine-readable code, a human-readable error message, and (when known) the match_id. For example:

json
{
  "code": "no_location_in_region",
  "error": "No available locations found in the specified region."
}
HTTPcodeWhen
422n/a Validation failed: a missing/invalid field, a reused match_id, or an env_variables key not defined on the egg. Returns the field-level errors array, not the envelope.
400server_already_exists A live server already exists for this match_id. Body includes match_id.
400no_location_in_regionThe region has no usable location.
400no_location_with_capacity No capacity anywhere for the request.
400regions_exhausted Region(s) were tried but no node could host the server (capacity / CPU / disk).
403n/a ServerSpawn Access (or the account's enterprise) is not enabled. Returns the errors array with “You do not have server spawn access.”
500unexpected_error Unexpected failure. Safe to retry with a new match_id.

Retry guidance: because match_id is single-use, any retry of a failed provision must use a newmatch_id. Treat a 4xx/5xx as “this match_id is now spent.”

3.2 · Get status

GET/api/serverspawn/v1/status

Returns the current lifecycle status of a server (or of an in-flight provision that hasn't produced a server yet). Identify the server by match_idor uuid (one is required).

Query parameters

ParamTypeRequiredNotes
match_idstringOne of The match_id you provisioned with.
uuidstringOne ofThe server uuid.

Example

bash
curl -sS "<PANEL_HOST>/api/serverspawn/v1/status?match_id=match-7f3a9c2e" \
  -H "Authorization: Bearer ptlc_XXXXXXXX..." \
  -H "Accept: application/json"

Responses

Server exists · 200 OK (includes the server block + live connection details):

json
{
  "status": "ready",
  "server": {
    "uuid": "d3f1c8a0-7b2e-4a6c-9f10-2a3b4c5d6e7f",
    "match_id": "match-7f3a9c2e",
    "connection": { "ip": "203.0.113.42", "port": 7777 }
  }
}

Provision in flight, server not created yet · 200 OK (no server block):

json
{ "status": "provisioning" }

Nothing matches · 404 Not Found:

json
{
  "code": "server_not_found",
  "error": "No server or provision found for the supplied identifier."
}

Status values

statusMeaning
provisioning Still selecting a node / creating the server. No server block yet.
installing Server created; game image installing on the node.
startingContainer is starting up.
ready Running; safe to connect players.
stoppingShutting down.
stoppedNot running.
failedProvision or install failed.
terminated Server has been deprovisioned (soft-deleted).

Once installed, starting / ready / stopping / stopped reflect the live power state reported by the node daemon. If the node can't be reached, status falls back to stopped.

3.3 · Deprovision a server

POST/api/serverspawn/v1/deprovision

Safely deletes a server: removes it from the node and soft-deletes the record. Identify it by match_idor uuid (one is required). Scoped to your account; you can only deprovision your own servers.

Request body

FieldTypeRequiredNotes
match_idstringOne ofThe server's match_id.
uuidstringOne ofThe server's uuid.

Example

bash
curl -sS -X POST "<PANEL_HOST>/api/serverspawn/v1/deprovision" \
  -H "Authorization: Bearer ptlc_XXXXXXXX..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "match_id": "match-7f3a9c2e" }'

Responses

Success · 200 OK:

json
{
  "status": "terminated",
  "server": { "uuid": "d3f1c8a0-7b2e-4a6c-9f10-2a3b4c5d6e7f", "match_id": "match-7f3a9c2e" }
}

No matching live server · 404 Not Found (already deprovisioned, never existed, or not yours):

json
{
  "code": "server_not_found",
  "error": "No matching server was found to deprovision."
}

Deletion failed · 500 Internal Server Error:

json
{
  "code": "unexpected_error",
  "error": "An unexpected error occurred while attempting to deprovision the server.",
  "match_id": "match-7f3a9c2e"
}

Deprovision is idempotent from your side: a second call for the same server returns 404 (it's already gone). Remember the match_id stays spent; you cannot re-provision under it.

4Related Client API endpoints


Once a server exists, manage it with the standard Client API (<PANEL_HOST>/api/client), using the same bearer token. Address a server by its uuid in the path: /api/client/servers/{uuid}/...

Read the full Client API Documentation for more details. Below is a short summary of the most important endpoints.

Regions

GET/api/client/locations/regions

The source of truth for valid region_id values. Read this at integration time (and periodically) rather than hardcoding IDs.

bash
curl -sS "<PANEL_HOST>/api/client/locations/regions" \
  -H "Authorization: Bearer ptlc_XXXXXXXX..." -H "Accept: application/json"
jsonc
{
  "object": "list",
  "data": [
    {
      "object": "region",
      "attributes": {
        "id": 12,                 // use this as region_id
        "name": "US East",
        "slug": "us-east",
        "created_at": "2025-08-05T16:53:45+00:00",
        "updated_at": "2025-08-05T16:53:45+00:00"
      }
    }
    // ... more regions
  ]
}

The actual id / name pairs are environment-specific; the values above are an example shape only.

Server control & inspection

MethodPathPurpose
GET/servers/{uuid} Server details (limits, feature set, current state).
GET/servers/{uuid}/resources Live CPU / RAM / disk usage and power state.
POST/servers/{uuid}/power Power signal. Body: { "signal": "start" | "stop" | "restart" | "kill" }. Returns 204.
POST/servers/{uuid}/command Send a console command. Body: { "command": "..." }.
GET/servers/{uuid}/websocket Get short-lived credentials for the live console / log WebSocket.
GET/servers/{uuid}/startup List startup variables (the valid env_variables keys + current values).
PUT/servers/{uuid}/startup/variableUpdate one startup variable.

Players

MethodPathPurpose
GET/servers/{uuid}/playerConfigured players.
GET/servers/{uuid}/player/onlineCurrently online players.

Some games expose additional, game-specific endpoints (for example, ARK exposes cluster management under /servers/{uuid}/ark/... for cross-server transfers). The available set depends on the egg; inspect GET /servers/{uuid} or ask BisectHosting for your game's feature list.

Account / keys

MethodPathPurpose
GET/account/api-keysList your API keys.
POST/account/api-keys Create a key ({ "description": "...", "allowed_ips": ["..."] }). The bearer token is the response's identifier immediately followed by meta.secret_token.
DELETE/account/api-keys/{identifier}Revoke a key.

5Example end-to-end flow


A typical “spin up a match server, run it, tear it down” lifecycle:

flow
1. (once)  Get region IDs        →  GET  /api/client/locations/regions
2. Provision a match server      →  POST /api/serverspawn/v1/provision    { match_id, region_id, egg_id, ram, ... }
3. Poll until ready              →  GET  /api/serverspawn/v1/status?match_id=...   (until status == "ready")
4. Connect players to connection.ip:connection.port
5. (optional) Control in-match   →  POST /api/client/servers/{uuid}/command   { "command": "..." }
6. Match over → deprovision      →  POST /api/serverspawn/v1/deprovision   { match_id }

The same flow in Bash and TypeScript:

Bash

bash
HOST="<PANEL_HOST>"
KEY="ptlc_XXXXXXXX..."
AUTH=(-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -H "Accept: application/json")

MATCH_ID="match-$(uuidgen | tr 'A-Z' 'a-z')"   # unique per provision, never reuse

# 1. Provision
curl -sS -X POST "$HOST/api/serverspawn/v1/provision" "${AUTH[@]}" -d "{
  \"match_id\": \"$MATCH_ID\",
  \"region_id\": 12,
  \"egg_id\": <GAME_EGG_ID>,
  \"ram\": 8192,
  \"dedicated_ip\": false
}"

# 2. Poll status until ready
until [ "$(curl -sS "$HOST/api/serverspawn/v1/status?match_id=$MATCH_ID" "${AUTH[@]}" \
        | python3 -c 'import sys,json;print(json.load(sys.stdin)["status"])')" = "ready" ]; do
  sleep 3
done
echo "Server ready."

# 3. ... run the match ...

# 4. Deprovision
curl -sS -X POST "$HOST/api/serverspawn/v1/deprovision" "${AUTH[@]}" -d "{ \"match_id\": \"$MATCH_ID\" }"

Node.js (TypeScript)

typescript
const HOST = "<PANEL_HOST>";
const KEY = process.env.BISECT_API_KEY!;             // ptlc_...
const headers = {
  Authorization: `Bearer ${KEY}`,
  "Content-Type": "application/json",
  Accept: "application/json",
};

async function provisionMatch(matchId: string, regionId: number) {
  const res = await fetch(`${HOST}/api/serverspawn/v1/provision`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      match_id: matchId,                              // unique per call, never reuse
      region_id: regionId,
      egg_id: GAME_EGG_ID,                            // <GAME_EGG_ID>
      ram: 8192,
      dedicated_ip: false,
    }),
  });
  if (!res.ok) throw new Error(`provision failed: ${res.status} ${await res.text()}`);
  return res.json() as Promise<{ status: string; server: { uuid: string; match_id: string; connection: { ip: string | null; port: number | null } } }>;
}

async function waitUntilReady(matchId: string, { intervalMs = 3000, timeoutMs = 600_000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const res = await fetch(`${HOST}/api/serverspawn/v1/status?match_id=${encodeURIComponent(matchId)}`, { headers });
    const body = await res.json();
    if (body.status === "ready") return body.server;
    if (body.status === "failed") throw new Error(`provision failed for ${matchId}`);
    await new Promise((r) => setTimeout(r, intervalMs));
  }
  throw new Error(`timed out waiting for ${matchId}`);
}

async function deprovisionMatch(matchId: string) {
  await fetch(`${HOST}/api/serverspawn/v1/deprovision`, {
    method: "POST",
    headers,
    body: JSON.stringify({ match_id: matchId }),
  });
}

// usage
const matchId = `match-${crypto.randomUUID()}`;
await provisionMatch(matchId, 12);
const server = await waitUntilReady(matchId);
console.log(`Connect players to ${server.connection.ip}:${server.connection.port}`);
// ... later ...
await deprovisionMatch(matchId);

6Available regions


Region IDs are environment-specific and may change, so this guide does not hardcode them. Fetch the current list from the Client API and use the returned id as your region_id:

GET<PANEL_HOST>/api/client/locations/regions

See the Regions section above for the response shape. If you want a fixed mapping of friendly names → region IDs for your launcher, pull this once at deploy time and cache it; re-check periodically in case capacity is added.

7Game egg


The game image is selected by egg_id. For your game, use:

egg id
egg_id = <GAME_EGG_ID>

BisectHosting will provide the concrete numeric ID for your environment. To customize a server's configuration (session name, player limits, passwords, ports, etc.), pass env_variables on provision. The set of valid keys is defined by this egg; discover them at runtime per server via:

http
GET <PANEL_HOST>/api/client/servers/{uuid}/startup

Any env_variables key not defined on the egg is rejected with 422, so validate against /startup (or the list BisectHosting gives you) when building your provision payloads.

8Quick reference


Auth header (all calls):Authorization: Bearer ptlc_…

ActionCall
List regionsGET/api/client/locations/regions
ProvisionPOST/api/serverspawn/v1/provision
StatusGET/api/serverspawn/v1/status?match_id=…
DeprovisionPOST/api/serverspawn/v1/deprovision
PowerPOST/api/client/servers/{uuid}/power · { "signal": "restart" }
Console commandPOST/api/client/servers/{uuid}/command · { "command": "…" }
Live console (WS)GET/api/client/servers/{uuid}/websocket
Startup variablesGET/api/client/servers/{uuid}/startup

Remember:

  • ServerSpawn Access must be enabled on the account (ask BisectHosting).
  • match_id is unique and single-use; generate a fresh one per provision, even after deprovision.
  • provision returns installing; poll /status until ready before connecting players.
  • Rate limit: 720 req/min per account.

For questions, capacity planning, the egg ID, or to enable ServerSpawn Access, contact your BisectHosting integration contact.

BisectHosting · ServerSpawn API v1, for game studios and platform engineers.

BisectHosting Logo