DevelopersTypeScript SDK
Hostwolf SDK for JavaScript & TypeScript
@hostwolf/sdk is the official typed client for the Hostwolf API. With it you can control your game servers from code: power, console, files, backups, mods, players, schedules and more.
npm install https://game.hostwolf.net/dl/hostwolf-sdk-0.1.6.tgz
The SDK is served from hostwolf.net rather than the npm registry. The command above adds it to your package.json as "@hostwolf/sdk": "https://game.hostwolf.net/dl/hostwolf-sdk-0.1.6.tgz", and you import it as @hostwolf/sdk. pnpm, yarn and bun accept the same URL. Every release has its own URL; see Releases.
It works in Node 18+, Bun and Deno, and has no runtime dependencies. For the live console in Node below 22, also run npm install ws.
Also see: REST API reference · MCP server · Changelog · Get an API key
Quick start#
Create an API key at panel.hostwolf.net/account/api, then:
import { Hostwolf } from '@hostwolf/sdk';
const hw = new Hostwolf({ apiKey: process.env.HOSTWOLF_API_KEY! });
const { data: servers } = await hw.servers.list();
for (const s of servers) {
const res = await hw.servers.resources(s.identifier);
console.log(s.name, s.egg_name, res.current_state);
}
const id = servers[0].identifier;
await hw.servers.command(id, 'say Backup in 1 minute');
await hw.backups.create(id, { name: 'before-update' });
console.log(await hw.tail(id, { lines: 20 }));
Every server method takes the server's short identifier (the 8 characters in its panel URL) or its uuid as the first argument. Response objects use the API's own field names (snake_case). Their TypeScript types are exported, e.g. Server, Backup and FileObject.
Options#
new Hostwolf({
apiKey: 'ptlc_...', // required
baseUrl: 'https://panel.hostwolf.net', // default
timeoutMs: 30_000, // per request
maxRetries: 2, // 429s, and 502/503/504 on GET
maxRetryWaitMs: 10_000, // longer Retry-After waits fail fast instead
fetch: customFetch, // optional
WebSocket: customWebSocket, // optional, for the console
});
Servers#
REST: Servers endpoints
| Method | What it does |
|---|---|
servers.list({ page, per_page }) | A page of your servers: { data, pagination } |
servers.listAll() | Async iterator over every server |
servers.get(id, ['egg', 'subusers']) | Server details, with allocations and startup variables |
servers.resources(id) | Live state, CPU, memory, disk, network, uptime |
servers.power(id, signal) / start / stop / restart / kill | Power actions |
servers.command(id, command) | Run a console command |
servers.activity(id) | Activity log (paginated) |
servers.rename(id, name, description?) | Rename |
servers.reinstall(id) | Re-run the install script |
servers.setDockerImage(id, image) | Switch the runtime image (e.g. Java version) |
Console#
const c = await hw.console(id).connect();
c.on('output', (line) => console.log(line));
c.on('stats', (s) => console.log(s.state, s.memory_bytes));
c.requestLogs(); // replay recent output
c.sendCommand('list');
// later
c.close();
// Or just fetch the recent lines (ANSI colours stripped):
const lines = await hw.tail(id, { lines: 50 });
The console connects straight to the node running your server and refreshes its token automatically.
Events:
readyandcloseoutputstatusstatsinstall outputdaemon messageanddaemon errorerror
Files#
REST: Files endpoints
await hw.files.list(id, '/plugins');
const props = await hw.files.read(id, 'server.properties');
await hw.files.write(id, 'server.properties', props.replace('pvp=true', 'pvp=false'));
await hw.files.rename(id, '/', [{ from: 'world', to: 'world-old' }]);
await hw.files.delete(id, '/logs', ['old.log']);
await hw.files.createFolder(id, '/', 'maps');
await hw.files.compress(id, '/', ['world']); // returns the archive
await hw.files.decompress(id, '/', 'world.tar.gz');
await hw.files.pull(id, 'https://example.com/map.zip', { directory: '/maps' });
const url = await hw.files.downloadUrl(id, 'world.tar.gz');
const uploadUrl = await hw.files.uploadUrl(id); // POST multipart "files" to `${uploadUrl}&directory=/maps`
Backups#
REST: Backups endpoints
const { data } = await hw.backups.list(id);
const b = await hw.backups.create(id, { name: 'nightly', is_locked: false });
await hw.backups.restore(id, b.uuid, { truncate: false });
await hw.backups.toggleLock(id, b.uuid);
await hw.backups.downloadUrl(id, b.uuid);
await hw.backups.delete(id, b.uuid);
await hw.backups.setSmart(id, true); // automatic backups before risky changes
Game, players and settings#
await hw.game.versions(id); // current + available versions
await hw.game.setVersion(id, '1.21.4'); // switches and reinstalls
await hw.game.settings(id); // friendly settings, grouped by file
await hw.game.updateSettings(id, { difficulty: 'hard' }, true);
await hw.game.diagnostics(id); // "Fix my server" checks
await hw.players.info(id); // online count (+ names on Minecraft)
await hw.players.list(id); // live list via RCON/query
await hw.players.kick(id, 'Steve');
await hw.players.ban(id, { steamid: '7656...' });
await hw.players.broadcast(id, 'Restarting in 5 minutes');
Mods, plugins and modpacks#
const profile = await hw.addons.profile(id); // sources, install dir, frameworks
const { items } = await hw.addons.search(id, 'modrinth', 'worldedit');
await hw.addons.install(id, 'modrinth', items[0].id); // newest compatible version
const installed = await hw.addons.installed(id, { checkUpdates: true });
await hw.addons.uninstall(id, installed.addons[0].id);
const packs = await hw.modpacks.search(id, 'cobblemon');
await hw.modpacks.install(id, packs.items[0].id, { freshWorld: false });
Other addon calls:
addons.upload(id, blob, name)addons.setFrameworkaddons.workshop/setWorkshop(Steam Workshop games)addons.cs2Frameworkmodpacks.current/versions/remove
More#
| Namespace | Methods |
|---|---|
startup | get(id), setVariable(id, key, value) |
schedules | list, get, create, update, execute, delete, createTask, updateTask, deleteTask |
databases | list(id, { includePassword }), create, rotatePassword, delete |
network | allocations, createAllocation, setNotes, setPrimary, deleteAllocation |
users | list, get, create(id, email, permissions), update, delete, permissions() |
notifications | Per-server Discord alerts: get, update, test |
domain | Custom domain: get, check, set, remove |
mcNetwork | Velocity/BungeeCord networks: get, link, unlink, installFabricProxy |
account | get, updateEmail, updatePassword, updateProfile, updateLanguage, activity, getNotifications, updateNotifications, apiKeys.*, sshKeys.*, setCurseforgeKey |
store | Read-only: catalog(), orders(), billing() |
Ordering, cancelling and paying for servers can only be done in the panel, so an API key can never spend money.
Pagination#
servers.list, backups.list and the activity methods return { data, pagination }. To walk through every server:
import { collect } from '@hostwolf/sdk';
const all = await collect(hw.servers.listAll());
Errors#
Failed calls throw a HostwolfError.
import { HostwolfError } from '@hostwolf/sdk';
try {
await hw.game.setVersion(id, '1.16.5');
} catch (e) {
if (e instanceof HostwolfError && e.code === 'downgrade_requires_reset') {
// older versions can't load a newer world: retry with { resetWorld: true } or { force: true }
}
}
It has these properties:
status: the HTTP status, or 0 for network errors and timeouts.code: the error code.retryAfter: on a 429, seconds until the action is allowed again. Short waits are retried for you; longer ones (like the 2-backups-per-10-minutes limit) fail at once with this set.message: a readable description.errors: the raw error list.body: the response body.- Shortcut flags:
isNotFound,isRateLimitedandisValidation.
Raw requests#
If an endpoint has no wrapper yet, call it directly:
await hw.http.get(`/servers/${id}/players`);
await hw.http.post(`/servers/${id}/command`, { command: 'list' });
Paths are relative to /api/client, and responses are unwrapped the same way as the wrapped methods. See the API reference for every endpoint.
Releases#
| File | Use |
|---|---|
https://game.hostwolf.net/dl/hostwolf-sdk-<version>.tgz | A fixed release. Use this in package.json. |
https://game.hostwolf.net/dl/hostwolf-sdk.tgz | Always the newest release. Package managers cache by URL, so prefer versioned URLs. |
https://game.hostwolf.net/dl/index.json | Current versions, with SHA-256 and npm integrity hashes. |
To upgrade, install the newer versioned URL.
License#
MIT