Starship Horizons
Log In
☰
Knowledge Base›Server Commands

Server Commands

Packets come down; commands go up. There are four mechanisms, they are not interchangeable, and picking the wrong one is a common mistake.

SendCMD — the socket, fire and forget

SendCMD("VESSEL-THROTTLE", value);
SendCMD("ALERT", "3");
SendCMD("WEAPON-GROUP-FIRE", groupId);

Sends a named command down the existing WebSocket. No response, no callback. This is what almost all gameplay uses, because gameplay is a stream of small changes where the result comes back as a packet anyway.

Use this for anything a player does at a console.

A command sent while the socket is closed, before it has connected or during a reconnect, is dropped, not queued. Packet claims and the fast-lane request are the exceptions: they are remembered and sent again on every connect. See Packets And Topics.

PostCMD — a command with an answer

PostCMD("PRE-FLIGHT-LOAD", "", (data) => { /* ... */ });

Posts a command over HTTP and gives you the reply. For the small number of operations where you need to know it worked, or where the payload is too large to be comfortable on the socket — launching a mission is the example.

PostData is the related form used by the editors for saving whole records, such as a mission or a vessel class.

PostData("MISSION-SAVE", JSON.stringify(mission), "", (result) => {
    if (result !== "OK") alert(result);
});

A save, meaning any command whose name ends in -SAVE, always calls you back. The answer is the server's own, "OK" or a readable reason, or, when the request never got one, a message that says the save did not complete and that the edits are still in the editor. That message also gives the size of what was sent and whether it was over the most the server accepts in one request this way, which is 256 MB. Size is the one fact that tells "too big to save" apart from "the server is restarting". Treat anything other than "OK" as a failure. Commands that are not saves still fail silently, because their callbacks may be expecting data.

CallAPI and GetAPI — reading content

CallAPI("missions", id, (data) => { /* ... */ });
CallAPI("components", "", (data) => { /* ... */ });

A plain HTTP GET against the REST API, which is how you read content — missions, vessel classes, components, factions, models, maps, dialogs. No authentication is required to read. Every endpoint, and what each one takes, is listed in Web API.

CallAPI takes an optional fourth argument, a function called when the request fails outright. Code that guards against sending the same request twice uses it to let go of its guard.

GetAPI was meant as a module‑scoped form of CallAPI, but it sends a POST with no token, and the server treats every POST under api/ as a write, so the answer is always unauthorized. Do not use it to read. Nearly every read endpoint answers with the merged content whichever module the address names; Web API says which ones differ.

This is the right way to load a list of anything. It is not the way to read live game state — that comes down as packets.

WriteAPI — changing content

WriteAPI("PUT", "components", id, body, (res) => { if (!res.ok) alert(res.error); });
WriteAPI("DELETE", "components", oldId, null, cb);

REST writes, and the only one of the four that needs authentication: a bearer token on the request. The callback receives { ok, data } or { ok: false, error }, and error is already a sentence a person can act on; the server's raw code, such as module-sealed, is kept on res.code for code that wants to branch on it.

A page finds the token in one of three places:

  • Written into the page. The editor base pages (console-admin.htm, console-child.htm and Hydra Studio's own) have it filled in by the server, so Hydra Studio can save when it is opened from another machine on the network.
  • Fetched from api/auth/token. The server answers that only for loopback callers, 127.0.0.1 or localhost, so this works only on the server's own machine.
  • Local storage, where both of the above leave it for later pages in the same browser.

A player console (console.htm) has none of its own, so WriteAPI from a player station fails unless that browser already holds the token. See Modding With Hydra Studio.

Which to use

You want toUse
Act on the running game from a consoleSendCMD
Do something and know whether it workedPostCMD
Load a list or a record of contentCallAPI
Save or delete contentWriteAPI or PostData
Know about live state changesNeither — accept a packet. See Packets And Topics.

Writes are whole records

Worth repeating here because it bites hardest at this layer: a content save is not a patch. A save replaces the record. If your code loaded a subset of a record, changed one field, and saved, the fields it never read are gone.

Round‑trip the whole record: read it, modify it, send it all back. Any editor or tool that writes a slice of something needs to be deliberate about it. The ones in the base game that do — the in‑game renderer tuning panel writing a few environment fields, for instance — read the whole record first, change only the fields you touched, and send it back.

A few saves keep a field their editor never shows when the body leaves it out: an input role keeps its controller layouts, and an NPC role keeps its schedule. The user registry's write changes only the fields you send. These are narrow exceptions, not a rule to lean on; Web API lists what each write expects.

Names are keys

Content records are keyed by name or id. There is no rename operation: writing under a new name creates a new record, and the old one has to be deleted separately. The editors do this for you, and anything you write yourself has to as well.

Last updated 19 October 2026