> ## Documentation index
> Fetch the complete index at: https://maritime.sh/llms.txt
> Setup procedure for AI agents (install, sign in, deploy, verify): https://maritime.sh/agents.md
> This page as HTML: https://maritime.sh/docs/ephemeral-sandboxes

# Sandboxes

Sandboxes

An isolated 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** | Code a model wrote, test runs, analysis of a file that must not stay on disk. |
| **Use something else when** | Files must outlive the run: [Agent box](https://maritime.sh/docs/persistent-sandboxes). Many at once: [Swarm](https://maritime.sh/docs/swarms). A screen: [Linux desktop](https://maritime.sh/docs/computers). |
| **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](https://maritime.sh/docs/ephemeral-sandboxes#commands-and-files), 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. |
| **Related** | [Agent boxes](https://maritime.sh/docs/persistent-sandboxes), [Swarms](https://maritime.sh/docs/swarms), [REST API](https://maritime.sh/docs/api#ephemeral-sandboxes). |

## When to use it

- Running code a model wrote, where nothing should outlive the run.
- Tests for a coding agent, one clean machine per run.
- Analysis of an uploaded file that must not stay on disk.

If the machine should keep its files between runs, use an
[Agent box](https://maritime.sh/docs/persistent-sandboxes) instead.

## From the dashboard

Open [New sandbox](https://maritime.sh/dashboard/new-sandbox?type=ephemeral)
(`/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`).

```bash
# 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:

- `idleMinutes`: how long it may stay idle before it ends. 1 to 60, default 5.
- `timeLimitMinutes`: when it ends whatever its activity. 5 to 1,440, default 1,440 (24 hours).
- `onIdle`: `kill`, the default, or `pause`, which pauses an idle sandbox instead of ending it.

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.

```bash
# 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.

```bash
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`.

```typescript
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
```

```python
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
```

```bash
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.

```bash
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.

```bash
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

- The sandbox engine ends the sandbox, disk included, after `idleMinutes` without activity or at
  the time limit, whichever comes first. No separate cleanup job is involved.
- Activity is a data plane call, a foreground command whose caller still waits, an open terminal,
  or a request or connection through a port URL. A command started with `background: true` does
  not count. If the sandbox only runs a background job, it ends after `idleMinutes`. To keep it
  running, wait on the command in the foreground, or raise `idleMinutes`.
- `idleMinutes` is 1 to 60, default 5. `timeLimitMinutes` is 5 to 1,440 (24 hours), default
  1,440. A value outside its range returns 400 `invalid_request`.
- The time limit counts running time only, from the create or the last resume. Extending it
  restarts it from now.
- A sandbox the idle timer ended has `endedReason: "idle"`. One the time limit ended has
  `endedReason: "timeout"`.
- `GET /v1/sandboxes/{id}/usage` returns `idleSeconds`, the seconds since the last activity,
  with the CPU, memory and disk in use. See the
  [API reference](https://maritime.sh/docs/api#sandboxes-usage).
- You can end it earlier with `DELETE /api/sandboxes/ephemeral/{id}` or
  `maritime sandboxes kill <id>`.
- A wrong id, or another account's sandbox, returns 404 `sandbox_not_found`.

## 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.

- It is billed per second while running, with no minimum: $0.0055 per vCPU-hour plus $0.00275 per
  GB-hour of memory. Disk is included. It draws from your plan's usage credit and counts
  toward the free trial's $20. See [Billing & plans](https://maritime.sh/docs/billing#rates).
- While it runs, it counts toward your plan's machines awake at once.
- Without a plan or the free trial, a create returns 402 `plan_required`, whose `checkoutUrl` is
  the billing page. At the awake limit it returns 429 `concurrency_limit`.

Every number is in [Limits & errors](https://maritime.sh/docs/limits).

## Related

- [Agent boxes](https://maritime.sh/docs/persistent-sandboxes)
- [Swarms](https://maritime.sh/docs/swarms)
- [Images](https://maritime.sh/docs/images)
- [Sandbox webhooks](https://maritime.sh/docs/sdk/webhooks#sandbox-events)
