Docs: Sandboxes, short-lived Linux micro-VMs | Maritime

Sandboxes

A sandbox is an isolated Linux machine that ends when you stop using it. Run your code on it. When it has been idle for a few minutes, or when its time limit passes, Maritime ends the machine and its disk. Each one is its own micro-VM on the sandbox engine, with its own kernel.

At a glance

What it is

An isolated Linux micro-VM on the sandbox engine, ended with its disk when it has been idle for a few minutes or at its time limit. Its id is sbx-....

Use it for

Use something else when files must outlive the run: Agent box. Many at once: Swarm. A screen: Linux desktop.

Start it

New sandbox (?type=ephemeral), POST /api/sandboxes/ephemeral, maritime sandboxes create, or ephemeral.createEphemeral in the SDK.

Lifecycle

Starts, runs your commands through the Sandboxes API, and the sandbox engine ends it with its disk after idleMinutes without activity (default 5), or at expiresAt, the time limit. POST /api/sandboxes/ephemeral/{id} restarts the time limit.

Price

$0.0055 per vCPU-hour + $0.00275 per GB-hour while running, per second, at any size (small, 2 vCPU and 4 GB, is $0.022 an hour). Disk is included. With onIdle: "pause", a paused sandbox costs $0.08 per GB-month of disk.

Limits

Idle time 1 to 60 minutes, time limit 5 to 1,440 minutes. Presets small (default), medium, large and xlarge, or exact vcpu 1 to 16, memoryMib 1,024 to 65,536 and diskGib 5 to 500. Counts toward awake at once while running.

When to use it

If the machine should keep its files between runs, use an Agent box instead.

From the dashboard

Open New sandbox (/dashboard/new-sandbox?type=ephemeral), name it, and pick a preset size or set your own vCPU, memory and disk. Under How it ends, pick how long it may stay idle (1, 2, 5, 15 or 60 minutes, default 2) and its time limit (1, 4 or 24 hours, default 24). Then click Create sandbox. For other values, use the API below.

From the API

One call starts a sandbox: POST /api/sandboxes/ephemeral. When it has been idle for idleMinutes, or at its time limit, the sandbox engine ends it, disk included. The key needs the sandboxes scope (or manage).

# start it: it ends, disk and all, after 5 idle minutes or 60 minutes from now
curl -X POST https://api.maritime.sh/api/sandboxes/ephemeral \
  -H "Authorization: Bearer $MARITIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "job-42", "idleMinutes": 5, "timeLimitMinutes": 60, "size": "small"}'
# 201: the Sandbox object plus when it ends
# {"id": "sbx-k3m7q2ab", "name": "job-42", "state": "running", "size": "small",
#  "resources": {"vcpu": 2, "memoryMib": 4096, "diskGib": 12},
#  "dataPlaneUrl": "https://api-sbx-k3m7q2ab.sb.mtm.sh/v1", "secret": "...",
#  ..., "expiresAt": "2026-10-26T18:00:00+00:00", "endsWhenIdleSeconds": 300}

Every body field is optional. Three fields set how the sandbox ends:

The other fields are those of POST /v1/sandboxes: name, from (a stock template such as base or python, a saved snapshot, or an OCI image; default base), size (default small), vcpu, memoryMib, diskGib, screen, network, endUser, forEndUser, env, metadata and failFast. The /v1 timer fields idleTimeoutSeconds, timeLimitSeconds and keepAwake are refused. A create with the name of a live sandbox returns that sandbox with status 200. Send an Idempotency-Key header to retry safely.

lifetimeMinutes is a deprecated alias of timeLimitMinutes, kept for earlier clients. A body with both returns 400 invalid_request.

The answer is the Sandbox object, the same as GET /v1/sandboxes/{id}, plus expiresAt, the time limit's deadline, and endsWhenIdleSeconds, the idle time that ends it. Its id (sbx-...) works with every /v1/sandboxes call and with the data plane. Refusals are the Sandboxes Error object (code, message, hint, docUrl, requestId).

To extend the time limit, call POST /api/sandboxes/ephemeral/{id} with { "timeLimitMinutes": 60 } (5 to 1,440, default 1,440). The time limit restarts from that call. The idle timer does not change. A sandbox without a time limit that ends it returns 400 invalid_request. To end it now, call DELETE /api/sandboxes/ephemeral/{id}; calling it again is safe.

# restart the time limit: it now ends 30 minutes from now at the latest
curl -X POST https://api.maritime.sh/api/sandboxes/ephemeral/sbx-k3m7q2ab \
  -H "Authorization: Bearer $MARITIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"timeLimitMinutes": 30}'

# end it now
curl -X DELETE https://api.maritime.sh/api/sandboxes/ephemeral/sbx-k3m7q2ab \
  -H "Authorization: Bearer $MARITIME_API_KEY"

List your live sandboxes, newest first. The list also has sandboxes you made with /v1/sandboxes or the E2B-compatible API, but not swarm sandboxes. expiresAt is null for a sandbox without a time limit, and while a sandbox is not running. endsWhenIdleSeconds is null when going idle pauses the sandbox instead of ending it.

curl -H "Authorization: Bearer $MARITIME_API_KEY" \
  https://api.maritime.sh/api/sandboxes/ephemeral
# {"sandboxes": [{"id": "sbx-k3m7q2ab", ..., "expiresAt": "...", "endsWhenIdleSeconds": 300}], "nextCursor": null}

Commands and files

A sandbox you start with these calls is a sandbox of the Sandboxes API, so commands and files run through it: the SDK's sandboxes client, maritime sandbox in the CLI, or the data plane at the sandbox's dataPlaneUrl.

job.ts Copy

import { Maritime } from 'maritime-sdk'

const maritime = new Maritime({ apiKey: process.env.MARITIME_API_KEY })

const box = await maritime.ephemeral.createEphemeral({ idleMinutes: 5, timeLimitMinutes: 30 })
const sbx = await maritime.sandboxes.connect(box)
const { stdout } = await sbx.run('uname -a')
console.log(stdout, 'ends at', box.expiresAt)
await maritime.ephemeral.killEphemeral(box.id) // or let it end when idle

job.py Copy

import os

from maritime import Maritime

client = Maritime(api_key=os.environ["MARITIME_API_KEY"])

box = client.ephemeral.create_ephemeral(idle_minutes=5, time_limit_minutes=30)
sbx = client.sandboxes.connect(box["id"])
print(sbx.run("uname -a").stdout, "ends at", box["expiresAt"])
client.ephemeral.kill_ephemeral(box["id"])  # or let it end when idle

terminal Copy

maritime sandboxes create --name job-42 --idle 5m --time-limit 30m
maritime sandbox exec sbx-k3m7q2ab -- uname -a
maritime sandbox cp ./data.csv sbx-k3m7q2ab:/tmp/data.csv
maritime sandboxes kill sbx-k3m7q2ab

In the CLI, --time-limit sets the time limit (5m to 24h, default 24h) and --idle the idle time (1m to 60m, default 5m); --on-idle pause pauses instead of ending. --lifetime still works as the old name of --time-limit.

Over plain HTTP, send the command to {dataPlaneUrl}/commands with the sandbox's secret in X-Maritime-Token. The answer is the Command object, with exitCode, stdout and stderr, when the process exits.

curl -X POST "$DATA_PLANE_URL/commands" \
  -H "X-Maritime-Token: $SANDBOX_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"cmd": "uname -a"}'

E2B-compatible API

Code written for the stock E2B SDKs (e2b and @e2b/code-interpreter) works against Maritime. Set E2B_DOMAIN to sb.mtm.sh and E2B_API_KEY to a Maritime key with the sandboxes scope. The SDK then calls https://api.sb.mtm.sh, which serves Maritime's /e2b routes; set E2B_API_URL only to point it somewhere else. A sandbox made this way is a Maritime sandbox, billed at the same rates.

export E2B_DOMAIN=sb.mtm.sh
export E2B_API_KEY=$MARITIME_API_KEY
# your existing E2B code runs unchanged, for example:
python -c 'from e2b import Sandbox; print(Sandbox.create().commands.run("uname -a").stdout)'

How it ends

Sizes, limits and billing

Size vCPU Memory Disk Per hour
small (default) 2 4 GB 12 GB $0.022
medium 4 8 GB 50 GB $0.044
large 8 16 GB 125 GB $0.088
xlarge 16 32 GB 250 GB $0.176

The sizes are presets. To set exact resources, send vcpu (1 to 16), memoryMib (1,024 to 65,536, in whole GiB) and diskGib (5 to 500), alone or on top of a size. Each exact field overrides the preset's value. The Sandbox object shows them in resources, and its size is custom when they match no preset. A sandbox with 1 vCPU and 2 GiB of memory costs $0.011 per hour.

Every number is in Limits & errors.