Your first $5 top-up doubles to $10 — one-time, for every new account. Get Started
Krova CloudKrova Cloud

TypeScript SDK

The official, fully-typed TypeScript SDK for Krova Cloud — provision and manage Cubes, browse the catalog, and reach every REST API operation from Node.js.

@krovacloud/sdk is the official TypeScript client for Krova Cloud. Request bodies, responses, and path params are generated from the Krova Cloud OpenAPI spec, so you get end-to-end types and editor autocomplete for the whole API. Ergonomic helpers cover the Cube lifecycle and the catalog; a fully-typed escape hatch (client.raw) reaches every other operation. It's published on npm as @krovacloud/sdk.

Install

Add it with your package manager. The only runtime dependency is openapi-fetch; TypeScript declarations are bundled (no @types/* needed).

npm i @krovacloud/sdk
# or: pnpm add @krovacloud/sdk  /  yarn add @krovacloud/sdk

Requires Node.js 18 or newer (it uses the global fetch). It also works in any modern runtime with a WHATWG fetch — Deno, Bun, and edge — and you can pass a custom fetchif the global isn't available.

Authenticate

Create an API key per space from Settings → API keys in the dashboard (see API keys). Keys are scoped to a single space, inherit the permissions of the membership that created them, and look like kro_…. Load the key from an environment variable or a secrets manager — never commit it or embed it in a browser bundle.

import { KrovaClient } from "@krovacloud/sdk";

const krova = new KrovaClient({
  apiKey: process.env.KROVA_API_KEY!, // a "kro_..." token
});

By default the key is sent as the X-API-KEY header. If your gateway expects a bearer token, pass authScheme: "bearer".

Quickstart

Every space-scoped call takes the spaceId as its first argument. Because an API key already belongs to one space, use the space id shown in your dashboard (or resolve it once and reuse it).

// List Cubes in a space
const cubes = await krova.cubes.list("space_123");

// Create a Cube (sshPublicKey is required)
const cube = await krova.cubes.create("space_123", {
  name: "web-server",
  image: "ubuntu-24.04",
  resources: { vcpu: 2, ramGb: 4, diskGb: 40 },
  sshPublicKey: "ssh-ed25519 AAAA...your-key... you@host",
});

console.log(`Created cube ${cube.id} (${cube.state})`);

// Sleep it, then wake it (both are asynchronous / enqueued)
await krova.cubes.sleep("space_123", cube.id);
await krova.cubes.wake("space_123", cube.id);

new KrovaClient(options)

new KrovaClient({
  apiKey: string,               // required — your "kro_..." token
  baseUrl?: string,             // default: "https://krova.cloud/api/v1"
  authScheme?: "x-api-key" | "bearer", // default: "x-api-key"
  maxRetries?: number,          // default: 2 — retries 429/503 (honors Retry-After); 0 disables
  fetch?: typeof fetch,         // optional fetch override (proxy, tests)
});

Throws if apiKey is missing. Exposes client.baseUrl, client.cubes, client.catalog, and client.raw. Mutating POST/DELETEendpoints are rate-limited (10 requests / 60s per client IP); the client automatically retries 429 and 503 up to maxRetries times, honoring Retry-After.

client.cubes — the Cube lifecycle

Ergonomic helpers that unwrap the response body and throw a typed KrovaError on any non-2xx status.

  • list(spaceId) — every Cube in the space.
  • get(spaceId, cubeId) — one Cube.
  • create(spaceId, body, opts?) — the created Cube.
  • update(spaceId, cubeId, body)— update the Cube's SSH port (the only mutable field over the public API).
  • sleep / wake / delete (spaceId, cubeId) — asynchronous lifecycle transitions.
// create — sshPublicKey is required; region + userData (cloud-init) are optional.
// opts.idempotencyKey (<=255 chars, per-space) makes retries safe.
const cube = await krova.cubes.create(
  "space_123",
  {
    name: "web-server",
    image: "ubuntu-24.04",
    resources: { vcpu: 2, ramGb: 4, diskGb: 40 },
    sshPublicKey: "ssh-ed25519 AAAA... you@host",
    region: "us-east",            // optional — slug from catalog.regions()
    userData: "#cloud-config\n",  // optional — cloud-init (max 16 KB)
  },
  { idempotencyKey: "deploy-2026-07-01" },
);

// update — the only mutable Cube field over the public API is the SSH port
await krova.cubes.update("space_123", cube.id, { cubePort: 2222 });

The Cube type is exported for your own signatures:

import type { Cube } from "@krovacloud/sdk";
// {
//   id: string; name: string;
//   state: "pending" | "booting" | "running" | "sleeping" | "stopping" | "error" | "deleted";
//   publicIpv4: string | null;
//   resources: { vcpu: number; ramGb: number; diskGb: number };
//   image: string; costPerHour: number;
//   createdAt: string; updatedAt: string;
// }

client.catalog — regions, images, pricing

Read-only catalog endpoints. Use these to discover the valid image and region slugs before creating a Cube.

const regions = await krova.catalog.regions(); // regions with available capacity
const images = await krova.catalog.images();   // available OS images
const pricing = await krova.catalog.pricing(); // per-resource hourly rates + volume tiers

Domains, snapshots & TCP mappings

Typed helpers for a Cube's attached resources — each unwraps the response and throws KrovaError on failure.

// Custom domains
const domain = await krova.domains.create("space_123", "cube_123", {
  domain: "app.example.com",
  port: 8080,
});
await krova.domains.list("space_123", "cube_123");
await krova.domains.update("space_123", "cube_123", domain.id, { responseCompression: true });
await krova.domains.delete("space_123", "cube_123", domain.id);

// Snapshots + restore
const snap = await krova.snapshots.create("space_123", "cube_123", { name: "nightly" });
await krova.snapshots.list("space_123", "cube_123");
await krova.cubes.restore("space_123", "cube_123", snap.id); // replace the disk from a snapshot
await krova.snapshots.delete("space_123", "cube_123", snap.id);

// TCP port mappings (expose a Cube port on the host)
const mapping = await krova.tcpMappings.create("space_123", "cube_123", {
  cubePort: 5432,
  whitelistIps: ["203.0.113.4/32"],
});
await krova.tcpMappings.list("space_123", "cube_123");
await krova.tcpMappings.delete("space_123", "cube_123", mapping.id);

There are also krova.imports (create / get / complete / cancel a .cube import) and krova.backups.download for a time-limited backup URL, plus krova.getSpace() to resolve the space your key is scoped to and krova.cubes.ssh()for a Cube's SSH connection info. Domain, Snapshot, and TcpMapping are exported types.

client.raw — every endpoint

The helpers cover Cubes, the catalog, domains, snapshots, TCP mappings, imports, and backups. For anything else — e.g. Webhooks — use client.raw, the fully typed openapi-fetch client. It returns { data, error, response } and never throws — path, method, params, and body are all type-checked against the spec.

const { data, error } = await krova.raw.POST("/spaces/{spaceId}/webhooks", {
  params: { path: { spaceId: "space_123" } },
  body: { url: "https://example.com/hook", events: ["cube.running"] },
});

if (error) {
  console.error("Webhook create failed:", error.error);
} else {
  console.log(data);
}

The generated paths and components types are also exported for advanced use:

import type { paths, components } from "@krovacloud/sdk";
type Domain = components["schemas"]["Domain"];

Error handling

The cubes.* / catalog.* helpers throw a KrovaError on any non-2xx response. (client.raw never throws — it returns the error in { error }.) The error carries the HTTP status, the API message, an optional error code, and a requestId — quote the request id when contacting support.

import { KrovaError } from "@krovacloud/sdk";

try {
  await krova.cubes.get("space_123", "cube_missing");
} catch (err) {
  if (err instanceof KrovaError) {
    console.error(`[${err.status}] ${err.message}`);
    if (err.code) console.error("code:", err.code);
    if (err.requestId) console.error("request id:", err.requestId);
  } else {
    throw err;
  }
}

Point at a different base URL

Target a staging environment or a proxy by passing baseUrl:

const krova = new KrovaClient({
  apiKey: "kro_...",
  baseUrl: "https://gateway.internal/krova/api/v1",
});

Next steps

  • API keys — create and scope the key the SDK authenticates with.
  • CLI — the same API from your terminal, plus SSH and port forwarding.
  • Webhooks — receive and verify the events the API emits.
  • REST API reference — the interactive OpenAPI spec every helper is built on.