omg/docs
Sandbox API

Authentication

Authenticate sandbox routes with an API key or a signed-in user's short-lived JWT.

The Sandbox API authenticates with an API key — a long-lived secret that stands in for your account. You create keys in the dashboard and send them as a Bearer token on every request.

Signed-in omg clients can instead send the short-lived user JWT minted by POST https://auth.omg.dev/token with { "appId": "vibes" }. Both credentials resolve to the owning user on /v1/sandboxes*; API keys are the recommended choice for unattended server integrations.

Key format

A key is an opaque secret: the prefix omg_sk_ followed by 32 random bytes (base64url). The server stores only a SHA-256 hash of the key and shows you the plaintext exactly once, at creation:

omg_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6...

The first 12 characters (e.g. omg_sk_abc12) are the key's non-secret prefix — that's what the dashboard shows in the key list so you can tell keys apart. The full secret is never shown again.

API keys currently carry a single scope: sandbox. They resolve to the better-auth user that owns them and act as a normal user principal — a key can only create and manage sandboxes owned by that user, and a key cannot manage API keys.

Create a key

  1. Open omg.dev/sandbox and sign in (signed-out visitors get a sandbox landing first, then continue into the product).
  2. Go to Keys (or navigate straight to /sandbox/keys).
  3. Click New key, give it a name (required, up to 80 characters), and Create key.
  4. Copy the secret immediately — it's shown exactly once and starts with omg_sk_. If you lose it, revoke the key and make a new one.

Key creation and management happen with your dashboard session — the POST /v1/api-keys endpoint requires a dashboard JWT, not an API key. See the Reference for the raw management shapes.

Limits: at most 10 active keys per account, and at most 5 key creations per hour. Exceeding the creation rate returns 429.

Treat the key like a password. Anyone holding it can create and control sandboxes billed to your account. Store it in a secret manager or an environment variable — never commit it to git or paste it into client-side code.

Use the key

Send the key in the Authorization header as a Bearer token. Every /v1/sandboxes* route accepts it:

curl https://infra.omg.dev/v1/sandboxes \
  -H "Authorization: Bearer $OMG_API_KEY"

In JavaScript:

const res = await fetch("https://infra.omg.dev/v1/sandboxes", {
  headers: { Authorization: `Bearer ${process.env.OMG_API_KEY}` },
})

Everything is owner-scoped: a GET /v1/sandboxes returns only your sandboxes, and you can only control sandboxes you own. Sandboxes you create with an API key are raw programmatic sandboxes (no project/session/app attribution) and list with kind: "api".

Use a user JWT

A browser or forthcoming first-party CLI can exchange an existing omg session cookie for a short-lived user JWT:

POST https://auth.omg.dev/token
Content-Type: application/json
Cookie: <omg session cookie>

{ "appId": "vibes" }

The response is { "token": "<jwt>", "expiresAt": <milliseconds> }. Send the token as the same Bearer header:

curl https://infra.omg.dev/v1/sandboxes \
  -H "Authorization: Bearer $OMG_USER_JWT"

This token has aud=vibes. Infra accepts that audience only on the owner-scoped sandbox surface. It does not authorize /v1/deploys, /v1/models, or /v1/messages; those routes use infra's aud=vibes-infra service-token verifier. First-party local deploys therefore hand their source snapshot to the control-plane endpoint described in Deploy from a local machine, rather than calling /v1/deploys directly.

Revoking a key

Revoke a key any time from Sandboxes → API keys — click the trash icon on the row and confirm (or DELETE /v1/api-keys/{id} with your dashboard session). Revocation is permanent and effective almost immediately: the next request made with that key gets 401 Unauthorized. Revoking one key never affects your others.

Rotate keys the same way: create a new key, deploy it, then revoke the old one once nothing is using it. You can also set an expiresAt when creating a key so it expires on its own.

Errors

StatusMeaning
401 UnauthorizedMissing, unknown, revoked, expired, or malformed key.
403 ForbiddenThe key is valid but doesn't own the target resource.
429 Too Many RequestsKey-creation rate limit (5/hour).

Keeping keys safe

  • Prefer a per-environment key (one for CI, one for production) so you can revoke a single blast radius.
  • Read the key from the environment (process.env.OMG_API_KEY), not a literal in source.
  • Never ship a key to the browser. If your frontend needs a sandbox, mint it from your server and hand the client only what it needs (e.g. a preview URL).