On this page

The official TypeScript/JavaScript SDK for MIOSA. Works with Node.js 18+, Deno, Bun, and modern bundlers. Fully typed - no any.

Install

What’s new in 1.1.0

AreaWhat shipped
Sandbox lifecycleslug, externalUserId, externalProjectId on create; sandbox.update(); sandbox.previewToken()
Tenant preview domainclient.tenant.previewDomain.get/set/verify/delete()
Tenant brandingclient.tenant.branding.get/set/delete()
Webhooksclient.webhooks.create/list/get/delete/test()
Files advancedsandbox.files.tree(), sandbox.files.writeMany(), sandbox.files.watch()
Sandbox envsandbox.env.list/set/delete()
Processessandbox.processes.start/list/get/stop/logs/stream()
Templates + forkclient.sandboxTemplates.*, sandbox.fork()
Usage / quotasclient.usage.get(), client.quotas.get/set/delete()
Audit logclient.auditLog.list()
Tenant events (SSE)client.events.stream({ tenantWide: true })
Sharingsandbox.share.create/list/revoke()
Workspace membersclient.workspaceMembers.*, client.workspaceInvites.*
Org invitesclient.orgInvites.*

First request

import { Miosa } from "@miosa/sdk";

const client = new Miosa({ apiKey: "msk_live_..." });

// Create a sandbox, run a command, destroy it
const sandbox = await client.sandboxes.create({ templateId: "miosa-sandbox" });
const result = await sandbox.exec.run("python3 -c 'print(1 + 1)'");
console.log(result.stdout); // "2\n"
await sandbox.destroy();

Configure

OptionEnv varDefaultDescription
apiKeyMIOSA_API_KEY-Workspace key (msk_live_*)
baseUrlMIOSA_BASE_URLhttps://api.miosa.ai/api/v1API endpoint
timeout-30000Per-request timeout in milliseconds
maxRetries-3Automatic retries on 429 / 5xx
import { Miosa } from "@miosa/sdk";

// Reads MIOSA_API_KEY from process.env
const client = new Miosa({ apiKey: process.env.MIOSA_API_KEY! });

// Explicit configuration
const client2 = new Miosa({
  apiKey: "msk_live_...",
  baseUrl: "https://api.miosa.ai/api/v1",
  timeout: 60_000,
  maxRetries: 3,
});

Authentication

The API key is sent as Authorization: Bearer <key> on every request.

import { Miosa } from "@miosa/sdk";

// Standard  -  key from environment
const client = new Miosa({ apiKey: process.env.MIOSA_API_KEY! });

// With additional default headers (e.g., for white-label proxies)
const client2 = new Miosa({
  apiKey: "msk_live_...",
  defaultHeaders: { "X-Tenant-ID": "acme-corp" },
});

Error handling

import {
  Miosa,
  MiosaError,
  AuthenticationError,
  NotFoundError,
  PermissionError,
  RateLimitError,
  ValidationError,
  InsufficientCreditsError,
  ServerError,
} from "@miosa/sdk";

const client = new Miosa({ apiKey: process.env.MIOSA_API_KEY! });

try {
  await client.computers.get("nonexistent-id");
} catch (err) {
  if (err instanceof NotFoundError) {
    console.log("Computer not found");
  } else if (err instanceof AuthenticationError) {
    console.log("Invalid API key");
  } else if (err instanceof RateLimitError) {
    console.log(`Rate limited  -  retry after ${err.retryAfter}s`);
  } else if (err instanceof MiosaError) {
    console.log(`API error ${err.statusCode}: ${err.message}`);
  }
}

Streaming events

sandbox.events.stream() returns an AsyncIterableIterator:

for await (const event of sandbox.events.stream()) {
  const type = event["type"] as string | undefined;
  console.log(type, event["data"]);
  if (["build.completed", "build.failed"].includes(type ?? "")) break;
}

Phase 1-5 API Reference

Sandbox lifecycle (Phase 1)

import { randomUUID } from "crypto";
import type { SandboxCreateParams } from "@miosa/sdk";

// Create  -  full signature
const sandbox = await client.sandboxes.create({
  templateId: "miosa-sandbox",       // template image
  name: "my-sandbox",                // optional display name
  slug: "acme-backend",              // optional URL-safe identifier
  externalUserId: "usr_123",         // white-label user attribution
  externalProjectId: "proj_456",     // white-label project attribution
  externalWorkspaceId: "ws_789",     // white-label workspace attribution
  metadata: { env: "staging" },      // arbitrary key-value pairs
  timeoutSec: 300,                   // sandbox lifetime in seconds
  alwaysOn: false,                   // keep alive past idle timeout
  idempotencyKey: randomUUID(),      // safe for retries
});

const found = await client.sandboxes.get(sandboxId);
const list  = await client.sandboxes.list({ state: "running" });
await client.sandboxes.destroy(sandboxId);

// Update mutable fields
await sandbox.update({
  name: "updated-name",
  slug: "new-slug",
  timeoutSec: 600,
  alwaysOn: true,
  metadata: { version: "2" },
});

// Mint a short-lived preview token
const tokenInfo = await sandbox.previewToken({ expiresIn: 3600 });
// Returns: { token: "mp_...", url: "https://...", expiresAt: "..." }

// Fork from a snapshot or running sandbox
const forked = await sandbox.fork({ snapshotId: "snap_abc", name: "forked" });
ParameterTypeDescription
namestringDisplay name
slugstringURL-safe identifier
externalUserIdstringWhite-label user attribution
externalProjectIdstringWhite-label project attribution
externalWorkspaceIdstringWhite-label workspace attribution
metadataRecord<string, unknown>Arbitrary key-value pairs
timeoutSecnumberLifetime in seconds
alwaysOnbooleanStay alive past idle timeout
idempotencyKeystringDeduplication key for retries

Tenant preview domain (Phase 1)

client.tenant.previewDomain

// Get current custom preview domain
const info = await client.tenant.previewDomain.get();
// { domain: "preview.acme.com", verifiedAt: "...", cnameTarget: "..." }

// Set custom preview domain
await client.tenant.previewDomain.set("preview.acme.com");

// Trigger DNS verification
const result = await client.tenant.previewDomain.verify();
// { verified: true, target: "...", records: [...] }

// Remove custom domain
await client.tenant.previewDomain.delete();

Tenant branding (Phase 1)

client.tenant.branding

// Get current branding
const branding = await client.tenant.branding.get();

// Set branding
await client.tenant.branding.set({
  productName: "Acme AI",
  logoUrl: "https://cdn.acme.com/logo.png",
  supportUrl: "https://acme.com/support",
  supportEmail: "help@acme.com",
  primaryColor: "#ff6600",
  backgroundColor: "#ffffff",
});

// Reset to platform defaults
await client.tenant.branding.delete();

Webhooks (Phase 1)

client.webhooks

// Create a webhook
const wh = await client.webhooks.create({
  url: "https://example.com/webhooks/miosa",
  events: ["sandbox.created", "sandbox.ready", "sandbox.destroyed"],
});

const list = await client.webhooks.list();
const one  = await client.webhooks.get(wh.id);
await client.webhooks.delete(wh.id);

// Send a test ping to verify the endpoint is reachable
await client.webhooks.test(wh.id);

Supported events: sandbox.created, sandbox.ready, sandbox.destroyed, sandbox.error, computer.started, computer.stopped, computer.error

Files advanced (Phase 2)

sandbox.files

// Recursive directory tree
const tree = await sandbox.files.tree("/workspace", { recursive: true });

// Batch file write
await sandbox.files.writeMany([
  { path: "/workspace/app.ts", content: 'console.log("hello")' },
  { path: "/workspace/config.json", content: new TextEncoder().encode('{}') },
]);

// Watch for file-system changes (SSE async iterator)
for await (const event of sandbox.files.watch()) {
  console.log(event.type, event.path); // "modified", "/workspace/app.ts"
}

Sandbox environment variables (Phase 2)

sandbox.env

const vars = await sandbox.env.list();
await sandbox.env.set("DATABASE_URL", "postgres://...");
await sandbox.env.delete("DATABASE_URL");

Processes (Phase 2)

sandbox.processes

// Start a long-running background process
const proc = await sandbox.processes.start({
  command: "npm run dev",
  env: { NODE_ENV: "development" },
});

const list = await sandbox.processes.list();
const one  = await sandbox.processes.get(proc.pid);
await sandbox.processes.stop(proc.pid);

const logs = await sandbox.processes.logs(proc.pid);

// Streaming process output (SSE)
for await (const line of sandbox.processes.stream(proc.pid)) {
  process.stdout.write(line.data ?? "");
}

Usage and quotas (Phase 3)

client.usage - client.quotas

// Usage rollup
const report = await client.usage.get({
  externalUserId: "usr_123",
  groupBy: "externalUserId",   // or "externalProjectId", "workspaceId"
  period: "30d",               // or pass start/end ISO strings
});

// Set per-user quotas
await client.quotas.set("usr_123", {
  maxSandboxes: 5,
  maxConcurrent: 2,
  maxStorageGb: 10,
  maxCreditCents: 10000,  // $100.00
});

const quota = await client.quotas.get("usr_123");
await client.quotas.delete("usr_123"); // revert to tenant default

Audit log (Phase 3)

client.auditLog

let cursor: string | undefined;
do {
  const page = await client.auditLog.list({ after: cursor, limit: 50 });
  for (const entry of page.items) {
    console.log(entry.action, entry.createdAt);
  }
  cursor = page.nextCursor ?? undefined;
} while (cursor);

Tenant-wide event stream (Phase 3)

for await (const event of client.events.stream({ tenantWide: true })) {
  console.log(event.type, event.data);
}

Sharing (Phase 4)

sandbox.share

// Create a public share URL
const share = await sandbox.share.create({ expiresIn: 3600 });
// { shareId: "ms_...", shareUrl: "https://...", expiresAt: "...", scope: "read" }

const shares = await sandbox.share.list();
await sandbox.share.revoke(share.shareId);

White-label integrator flow

import { Miosa } from "@miosa/sdk";
import { randomUUID } from "crypto";

const client = new Miosa({ apiKey: process.env.MIOSA_API_KEY! });

// 1. Configure tenant branding once at startup
await client.tenant.branding.set({
  productName: "Acme AI",
  logoUrl: "https://cdn.acme.com/logo.png",
  primaryColor: "#ff6600",
});

// 2. Set a custom preview domain
await client.tenant.previewDomain.set("preview.acme.com");
await client.tenant.previewDomain.verify();

// 3. Register webhook for lifecycle events
await client.webhooks.create({
  url: "https://api.acme.com/webhooks/miosa",
  events: ["sandbox.created", "sandbox.ready", "sandbox.destroyed"],
});

// 4. Cap per-user resources
await client.quotas.set("usr_dr_smith", {
  maxSandboxes: 3,
  maxConcurrent: 1,
});

// 5. Create a sandbox attributed to a user + project
const sandbox = await client.sandboxes.create({
  templateId: "miosa-sandbox",
  name: "smile-dental",
  externalUserId: "usr_dr_smith",
  externalProjectId: "proj_landing_page",
  externalWorkspaceId: "ws_smile_dental",
  metadata: { plan: "pro" },
  idempotencyKey: randomUUID(),
});

// 6. Write files and execute a build
await sandbox.files.writeMany([
  { path: "/workspace/index.html", content: "<h1>Hello</h1>" },
]);
const result = await sandbox.exec.run("echo build done");

// 7. Mint a preview token for the end user
const tokenInfo = await sandbox.previewToken({ expiresIn: 3600 });
const previewUrl = tokenInfo.url; // share with the end user

// 8. Create a public share link
const share = await sandbox.share.create({ expiresIn: 86400 });
const publicUrl = share.shareUrl;

// 9. Query usage
const report = await client.usage.get({
  externalUserId: "usr_dr_smith",
  period: "30d",
});

// 10. Clean up
await sandbox.destroy();

Common patterns

Idempotency key

import { randomUUID } from "crypto";

const sandbox = await client.sandboxes.create({
  templateId: "miosa-sandbox",
  idempotencyKey: randomUUID(),
});

Parallel sandbox creation

const [sb1, sb2] = await Promise.all([
  client.sandboxes.create({ name: "worker-a" }),
  client.sandboxes.create({ name: "worker-b" }),
]);

Pagination

let cursor: string | undefined;
do {
  const page = await client.auditLog.list({ after: cursor, limit: 50 });
  for (const entry of page.items) {
    console.log(entry.action, entry.createdAt);
  }
  cursor = page.nextCursor ?? undefined;
} while (cursor);

Custom base URL (self-hosted)

const client = new Miosa({
  apiKey: "msk_live_...",
  baseUrl: "https://api.your-domain.com/api/v1",
});

Webhook verification

import { createHmac } from "crypto";

function verifyWebhook(payload: Buffer, signature: string, secret: string): boolean {
  const expected = createHmac("sha256", secret).update(payload).digest("hex");
  return expected === signature;
}

Resource coverage

Resource groupAvailable
Sandboxes (create, get, list, destroy, exec, events, files, previews, tags, snapshots)
Sandbox Phase 1-4 (update, previewToken, fork, env, processes, share)
Computers (CRUD + lifecycle)
Computer sub-resources (terminal, env, ports, volumes, logs, auto-stop, OSA)
Desktop (screenshot, click, type, drag, scroll, key, windows)
Files (upload, download, list, delete)
Exec
Deployments
Databases (managed Postgres)
Storage (object storage)
Volumes
Custom domains (flat + per-deployment)
Functions / cron jobs / health checks / webhooks
Sandbox templates
API keys
Tenant (plan, preview domain, branding)
Regions / settings
Dashboard / analytics / audit log / usage / quotas
Channels / integrations / project integrations
External keys
MCP
Models / completions / embeddings
Provider defaults / benchmarks
Command center / builder sessions / community
OpenComputers (hosts, jobs, files, tunnels, agents, clusters)
Admin
Workspace members + invites
Org invites
Snapshots (standalone)
Credits

Where to next

Was this helpful?