TypeScript SDK
@truetick/sdk is a small, typed client for the TrueTick API. It handles the x-api-key header,
coerces JSON int64 strings to numbers, derives server identifiers from names, and exposes everything as
ergonomic resource methods.
Install
npm install @truetick/sdkAuthenticate
import { TrueTickClient } from "@truetick/sdk";
// Explicit key
const client = new TrueTickClient({ apiKey: "ttk_your_key" });
// …or from the environment (TRUETICK_API_KEY)
const client2 = new TrueTickClient();
// Point at a non-default base URL (default: https://api.truetick.gg)
const client3 = new TrueTickClient({ apiKey: "ttk_…", baseUrl: "https://api.truetick.gg" });ClientOptions: { apiKey?: string; baseUrl?: string }. apiKey falls back to TRUETICK_API_KEY,
baseUrl to TRUETICK_API_URL. The constructor throws if no key is found.
Account
const me = await client.whoami();
// { accountId, email, emailVerified }Servers
// List / get
const servers = await client.servers.list();
const server = await client.servers.get("my-smp"); // id, hostname, state, ramMb, type, version, region, plan, …
// Create (id/hostname/container derived from name)
const created = await client.servers.create({
name: "My SMP",
ramMb: 4096,
type: "PAPER", // optional
version: "1.21.1", // optional
region: "na", // optional
plan: "metered", // optional
});
// Lifecycle
await client.servers.start("my-smp");
await client.servers.stop("my-smp");
await client.servers.restart("my-smp");
await client.servers.delete("my-smp"); // permanent
// Configure
await client.servers.updateVersion("my-smp", { type: "PURPUR", version: "1.21.1" }); // stopped only
await client.servers.setMotd("my-smp", "Welcome!");
await client.servers.setProperties("my-smp", {
properties: { difficulty: "hard", pvp: "true" },
idleTimeoutMinutes: 20,
});
// Templates
const templates = await client.templates.list();
const fromTpl = await client.servers.createFromTemplate("paper-survival", "my-server", { ramMb: 8192 });Metrics
const m = await client.servers.metrics("my-smp");
// { tps, mspt, players, live } — live:false is an honest "no data", not zeroSee Honesty metrics for how to read these.
Console (RCON)
const { output } = await client.console.run("my-smp", "say Hello from the SDK!");Logs
// Snapshot (+ cursor for incremental polling)
const { lines, cursor, containerMissing } = await client.servers.recentLogs("my-smp", { tail: 100 });
// Live stream — async iterable of plain lines (heartbeats filtered)
for await (const line of client.servers.streamLogs("my-smp", { tail: 50 })) {
console.log(line);
}Full streaming guide: Stream logs.
Files & SFTP
const entries = await client.files.list("my-smp", "/data"); // [{ name, isDir, size }]
const text = await client.files.read("my-smp", "/data/server.properties");
await client.files.write("my-smp", "/data/motd.txt", "New motd"); // text, base64-encoded for you
await client.files.delete("my-smp", "/data/old.txt");
// Binary uploads (jars): use SFTP credentials
const cred = await client.servers.enableSftp("my-smp"); // { host, port, username, password }The file API encodes content as UTF-8 text → base64. For binary artifacts like plugin jars, use the
SFTP credentials from enableSftp instead. See Deploy a plugin.
Backups
const backup = await client.backups.create("my-smp"); // { id, serverId, createdAt, sizeBytes }
const backups = await client.backups.list("my-smp");
await client.backups.restore("my-smp", backup.id); // server must be stoppedMods
const mods = await client.mods.list("my-smp");
await client.mods.add("my-smp", { source: "modrinth", projectId: "sodium", versionSpec: "0.5.11" });
await client.mods.remove("my-smp", { source: "modrinth", projectId: "sodium" });Wallet & billing
const wallet = await client.wallet.get(); // { accountId, balanceMicros }
console.log(`$${(wallet.balanceMicros / 1_000_000).toFixed(2)}`);
const { checkoutUrl } = await client.billing.createCheckout(10); // Paddle checkout for $10Standalone auth helpers
For sign-up / login flows (minting a key from credentials) the SDK also exports standalone functions — these hit the public auth endpoints directly and don't need a client:
import { signup, login, deviceStart, devicePoll } from "@truetick/sdk";
const minted = await login("https://api.truetick.gg", "you@example.com", "password");
// { apiKey, accountId, email, emailVerified }Error handling
Every failed call throws a TrueTickError with status (HTTP code) and code:
import { TrueTickError } from "@truetick/sdk";
try {
await client.servers.start("my-smp");
} catch (e) {
if (e instanceof TrueTickError) {
if (e.status === 401) console.error("invalid key");
if (e.status === 403) console.error("missing scope");
if (e.status === 404) console.error("not found / not yours");
if (e.status === 429) console.error("rate limited — back off");
}
}See Errors for the full status/code reference.
Exported types
TrueTickClient, ClientOptions, TrueTickError, Server, ServerMetrics, Wallet, Backup,
FileEntry, Mod, WhoAmI, CreateServerInput, Template, TemplateOverrides, SftpCredential,
plus the naming helpers parseLabel, serverHostname, gameDomainFromBaseUrl and the auth helpers
above.