omg/docs
Sandbox API

Integrate as a platform

Run omg sandboxes for your own users from your backend, with your own sign-in.

This guide is for a product that gives its own users a cloud sandbox. For example: an app that moves a user's coding agent into the cloud and lets them control it from a phone.

Your users sign in to your product. They do not need omg accounts. Your backend holds one omg API key and creates, wakes, and puts to sleep one sandbox for each of your users.

Your app ──your sign-in──▶ Your backend ──omg_sk_ key──▶ infra.omg.dev
                           (user → sandbox id)                │
                                                              ▼
                                            sandbox (your agent and your code)
                                                              │ outbound
Your app ◀────────── your relay or API ◀─────────────────────┘
You ownomg owns
Your users, their sign-in, and their sessionsThe VM, its files, and its isolation
Which user has which sandboxSleep, wake, snapshots, and forks
When a sandbox should stay awake or sleepThe 2-hour safety rule and cleanup
How your app talks to code in the sandboxOutbound internet from the sandbox

1. One account, one key, on your server

  1. Make an omg account for your product. Sandbox creation needs a paid Computer plan. The plan sets the machine size for every sandbox.
  2. Create an API key. See Authentication.
  3. Keep the key on your backend only. Never put it in your app, a browser, or a sandbox.

The key can reach every sandbox on the account. All of your users' sandboxes are on this one account. Your backend must check which of your users is calling before it acts on a sandbox.

import { SandboxClient } from "@omg-dev/sandbox"

const omg = new SandboxClient({
  baseUrl: "https://infra.omg.dev",
  token: process.env.OMG_API_KEY!,
})

2. Map your users to sandboxes

Store the sandbox id with your user record. omg does not store your user ids.

// first time a user needs a sandbox: fork your base machine (step 3)
const sandbox = await omg.fork(baseSnapshotId, {
  idempotencyKey: `user-${user.id}-v1`,
})
await db.users.update(user.id, { sandboxId: sandbox.id })

// later
const sandbox = omg.sandbox(user.sandboxId)

The idempotencyKey makes a retry safe. If the response is lost and you retry with the same key, you get the same sandbox back.

3. Start every user from the same base

Choose one:

  • The omg agent preset. { "template": "omg" } comes with Claude Code, Codex, opencode, and the omg web UI. See Templates.
  • Your own base machine. Create one sandbox, install your agent and plugin, take a snapshot, then fork that snapshot for each new user. A fork boots in seconds with everything installed.
# once: snapshot your base sandbox
curl -X POST https://infra.omg.dev/v1/sandboxes/$BASE_ID/snapshot \
  -H "Authorization: Bearer $OMG_API_KEY"

# for each new user: fork it
curl -X POST https://infra.omg.dev/v1/sandboxes/fork \
  -H "Authorization: Bearer $OMG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "snapshotId": "'$SNAPSHOT_ID'", "skipAppProcesses": true, "idempotencyKey": "user-123-v1" }'

A snapshot that no sandbox depends on is deleted after 7 days. Rebuild your base snapshot at least once a week, and point new forks at the new id.

4. Sleep and wake

A sandbox sleeps 2 hours after it starts unless something renews its keep-awake lease. Read Lifecycle and keep-awake for the full rules. A typical session:

const sandbox = omg.sandbox(user.sandboxId)

// user opens your app
const info = await omg.get(sandbox.id)
if (info.status === "hibernated") await sandbox.wake()

// while the agent works: renew every few minutes
await sandbox.keepAlive(900)

// work is done and the user has left
await sandbox.hibernate()

If the code that knows "I am still busy" runs inside the sandbox, let it renew the lease itself with no key:

curl -X POST http://169.254.0.1:9090/v1/sandbox/keepalive -d '{"seconds":900}'

After a wake, open connections are gone. Your code in the sandbox must reconnect to your relay or API.

5. Talk to the code in the sandbox

  • Outbound connections work. Code in the sandbox can reach the public internet. The usual pattern is for your agent or plugin to connect out to your relay.
  • Commands and files. Your backend can call exec, write files, and read files. See the Reference.
  • Shell. The shell WebSocket needs your API key. Connect from your backend and forward the stream to your user. Do not give the key to your app.
  • Preview URLs open only for you. A preview URL opens only for the omg account owner, so your users cannot open it. Use an outbound connection instead.

6. Your users' secrets

Pass a user's own credentials (for example their model provider login) into their sandbox only, with env on exec or by writing a file. Values in env on create are stored as plain text with the sandbox. Do not reuse one user's secret in another user's sandbox.

Limits today

TopicToday
API keysUp to 10 active keys per account. Each key reaches every sandbox on the account.
Per-user limitsNone. Enforce limits for your own users in your backend.
LabelsSandboxes have no field for your user id. Keep the mapping in your database.
EventsNo self-serve webhooks. Poll GET /v1/sandboxes.
BillingUsage is recorded per omg account. It is not split by your users.
Sleep2 hours after start without a lease. A sleeping sandbox is deleted after 14 days.
SnapshotsDeleted after 7 days when no sandbox depends on them.

Checklist

  • The API key exists only in your backend's secret store.
  • Your backend checks the caller owns the sandbox id before each call.
  • Creates and forks send an idempotencyKey.
  • Busy sandboxes renew their lease. Idle ones hibernate.
  • Your code in the sandbox reconnects after a wake.
  • You rebuild your base snapshot every week.
  • Users who leave have their sandbox deleted.