Skip to content

TypeScript SDK

bash
npm install ovrin

Requires Node 18+ (global fetch). Zero runtime dependencies.

Client

ts
import { Ovrin } from "ovrin";

const client = new Ovrin();                        // api key from OVRIN_API_KEY
const client = new Ovrin({ apiKey: "ovrin_..." }); // or explicit
const client = new Ovrin({ baseUrl: "https://api.ovrin.app" });

Errors are typed classes carrying the API's stable machine-readable code alongside the message:

ts
import { AuthenticationError, NotFoundError, OvrinError, QuotaError } from "ovrin";
StatusClass
401AuthenticationError
402QuotaError
404NotFoundError
otherOvrinError

Sandboxes

ts
const sandbox = await client.sandboxes.create({
  template: "codex",
  timeout: 3600,                       // seconds, minimum 60
  env: { OPENAI_API_KEY: key },
  secrets: [{ name: "github-prod", hosts: ["api.github.com"] }],
  payments: true,                      // inject the agent-payments key
  idempotencyKey: "run-42",            // safe retries
});

const result = await sandbox.run('codex "find and fix the failing test"');
console.log(result.stdout);

for await (const event of sandbox.stream("npm test")) {
  if (event.type === "stdout") process.stdout.write(event.text);
  else if (event.type === "stderr") process.stderr.write(event.text);
}

await sandbox.pause();
await sandbox.resume();
await sandbox.renew(new Date(Date.now() + 24 * 3600 * 1000));
await sandbox.kill();

await client.sandboxes.list();
await client.sandboxes.get(sandbox.id);

Files

Binary-safe by construction — text travels as UTF-8, bytes as base64:

ts
await sandbox.files.write("/workspace/run.js", source);
await sandbox.files.writeBytes("/workspace/blob.bin", pngBytes);   // Uint8Array

const text = await sandbox.files.read("/workspace/run.js");
const bytes = await sandbox.files.readBytes("/workspace/logo.png"); // Uint8Array

await sandbox.files.list("/workspace", 1);
await sandbox.files.stat("/workspace/run.js");
await sandbox.files.search("/workspace", "TODO");
await sandbox.files.move("/workspace/a.js", "/workspace/b.js");
await sandbox.files.mkdir("/workspace/pkg");
await sandbox.files.delete("/workspace/b.js");

Stateful code

On a code-interpreter sandbox, variables persist across calls within a context:

ts
let res = await sandbox.runCode("x = 41");
res = await sandbox.runCode("console.log(x + 1)");   // same context
res.context_id;                                      // reuse explicitly

const ctx = await client.sandboxes.createContext(sandbox.id);

Endpoints

Public HTTP URL for a port inside the sandbox:

ts
const { url } = await sandbox.endpoint(8080);

HTTP today; WebSockets need the ingress gateway (roadmap).

Snapshots

ts
await client.sandboxes.snapshot(sandbox.id, "golden");
const restored = await client.sandboxes.restore(snapshotId, "python");
await client.sandboxes.snapshots();
await client.sandboxes.deleteSnapshot(snapshotId);

Memory

See Persistent Memory for scoping semantics.

ts
await client.memory.add("prefers vitest over jest");
const hits = await client.memory.search("test framework", 10);
const all = await client.memory.list({ agentId: "support" });
await client.memory.delete(memoryId);

Secrets

ts
await client.secrets.create("github-prod", "ghp_...");
await client.secrets.list();     // names only — values are never returned
await client.secrets.delete("github-prod");

Keys

Scopes and expiry keep blast radius small; rotation swaps atomically. See API Keys & Scopes.

ts
const key = await client.keys.create({
  name: "ci",
  scope: "sandboxes",                    // all | sandboxes | memory | secrets
  expiresAt: "2026-12-01T00:00:00Z",
});
const fresh = await client.keys.rotate(key.id ?? 1);
await client.keys.revoke(keyId);

Usage & templates

ts
const usage = await client.usage.get();
const templates = await client.templates.list();

Payments

BYO Stripe restricted key; see Agent Payments.

ts
await client.payments.setCredentials("rk_live_...");
await client.payments.credentialsStatus();
await client.payments.clearCredentials();

await client.payments.agentKeyStatus();
await client.payments.createAgentKey();   // the persistent payments-scoped key

const customer = await client.payments.createCustomer("Acme", "billing@acme.com");
await client.payments.createInvoice(customer.id as string);
await client.payments.createPaymentLink("price_1", 1);