# How Long Can an AI Agent's Sandbox Run, and How Do I Keep It Alive?

> A Sandboxer sandbox auto-stops one hour after it starts unless you change that. Set a deadline up to 30 days, renew it while the job runs, or turn it off with --no-auto-stop (the trial caps it at 8 hours). A stop keeps disk and memory unless snapshots are off.

Source: https://sandboxer.com/guides/how-long-can-an-agent-sandbox-run. Updated 2026-10-27.

**Short answer:** A Sandboxer sandbox auto-stops one hour after it starts unless you change that. Set a deadline up to 30 days, renew it while the job runs, or turn it off with --no-auto-stop (the trial caps it at 8 hours). A stop keeps disk and memory unless snapshots are off.

This page lists every limit that can end an agent's run, what each one leaves behind, and a tested way to keep a job alive past the default hour without leaving a sandbox running forever. How to start and watch a detached job is in [Run a long job in a cloud sandbox](/guides/run-a-long-job-in-a-cloud-sandbox). How idle pause and wake work is in [Idle auto-pause and wake on use](/guides/idle-auto-pause-and-wake-on-use).

## Every limit that can end a run

| Limit | Default | Range | What happens when it's hit | Comes back by itself? |
| - | - | - | - | - |
| Synchronous command (`sbx exec`) | 30 s in the CLI | Up to 600 s (`--timeout`) | That command ends; the sandbox keeps running | Not applicable |
| Idle pause (`idleStopMinutes`) | 15 (trial), 30, 60 or 120 minutes by plan | `0` (off) to `10080` (7 days) | Stop with memory, reason `idle` | Yes, on the next API call, hosted-URL request or `sbx ssh` |
| Auto-stop (`ttlSeconds`, `archiveAfter`) | 1 hour | 1 s to 30 days, or never | Stop with memory, reason `auto_stop` | No, run `sbx resume` |
| Trial cap | 8 hours | Can't be raised during the trial | Creates or extends past 8 hours, or `--no-auto-stop`, answer `400 trial_auto_stop_required` | Not applicable |
| Balance at zero, auto-refill off | 24-hour grace | | Running sandboxes stop, memory and disk kept | No, top up, then `sbx resume` |
| Snapshots off (`--no-snapshots`) | Snapshots on | | Any stop, including auto-stop, ends the sandbox for good | No, it can't be resumed |
| Zero data retention (account setting) | Off | | A stop deletes the sandbox's data | No |

Two things in that table are easy to miss. Idle pause doesn't fire while a command runs, detached ones included, so a busy agent never pauses. Auto-stop is a hard deadline: a running job doesn't hold it off. And no limit on the list deletes a sandbox you could resume: a stop keeps it, unless snapshots are off or zero data retention is on.

Sources: [Long-running tasks](/docs/long-running), [Billing](/docs/billing#running-out), [Limits and errors](/docs/limits).

## The edges of the deadline, tested

We ran these on a `small` sandbox on prod on October 27, 2026. A new sandbox gets `ttlSeconds: 3600` and a deadline one hour out:

```json
{"state":"ready","ttlSeconds":3600,"archiveAfter":"2026-10-27T16:52:05.717483Z","idleStopMinutes":30,"createdAt":"2026-10-27T15:52:05.717563Z"}
```

The CLI refuses a TTL over 30 days:

```bash
sbx extend $id --ttl 2592001
```

```json
{"event":"error","error":"--ttl must be between 1 and 2592000 seconds","code":"usage"}
```

The REST API doesn't refuse it. It caps it. We sent `"ttlSeconds": 99999999` with `PATCH /api/v1/sandboxes/{id}` at 15:52:19 and got 30 days back:

```json
{"ttlSeconds":2592000,"archiveAfter":"2026-11-26T15:52:19.99896Z"}
```

`0` isn't "never" on the REST API. It's an error, and `null` is the value that turns auto-stop off:

```json
{"code":"invalid_ttl","message":"ttlSeconds must be between 1 and 2592000, or null.","status":400}
```

`sbx extend $id --no-auto-stop` sends `null`. After it, `sbx info` showed `{"ttlSeconds":null,"archiveAfter":null}`. The idle limit has its own ceiling: `sbx idle $id 10081` answered `minutes must be a whole number from 0 to 10080`, and `10080` was accepted.

## The agent inside can't extend its own deadline

An agent running inside the sandbox has `SANDBOXER_TOKEN`, a key limited to that sandbox. We tried to extend the deadline with it from inside:

```bash
sbx exec $id 'printf "header = \"Authorization: Bearer %s\"\n" "$SANDBOXER_TOKEN" |
  curl -sS -K - -X PATCH "$SANDBOXER_API_URL/sandboxes/$SANDBOXER_ID" \
    -H "Content-Type: application/json" -d "{\"ttlSeconds\": 600}"'
```

```json
{"code":"api_key_action_forbidden","error":{"code":"api_key_action_forbidden","details":{"action":"sandbox.update"},"message":"This API key does not allow sandbox.update.","status":403}, …}
```

That's by design: the in-sandbox token can run commands, read and write files and host ports, but it can't change the sandbox's settings or stop it ([API keys](/docs/api-keys#the-in-sandbox-key)). A looping agent can't keep itself alive. The deadline belongs to whatever started the sandbox: your orchestrator, your CI job or you.

## Keep a long job alive with a lease

You have three ways to cover a job longer than an hour:

| Approach | How | If your orchestrator dies | Use when |
| - | - | - | - |
| Fixed deadline | `sbx new --ttl 28800` | Stops at the deadline | You know roughly how long the job takes |
| Lease | Renew a short TTL while the job runs (below) | Stops within one TTL | The length is unknown, and a forgotten sandbox must not keep billing |
| No deadline | `sbx new --no-auto-stop` | Runs until someone stops it | A long-lived worker or service; pair it with idle pause |

A lease is a short TTL that your orchestrator keeps pushing forward while the job is alive. When the job ends, or the orchestrator crashes, renewals stop and the sandbox auto-stops on its own. This is the script we ran. It runs where your API key lives, not in the sandbox:

```bash
#!/bin/bash
# lease.sh ID PID TTL EVERY
# While process PID runs in sandbox ID, keep its auto-stop TTL seconds ahead,
# renewing every EVERY seconds. Stop renewing when the job ends, or when this
# script dies, and the sandbox auto-stops on its own within TTL seconds.
id=$1 pid=$2 ttl=$3 every=$4
while :; do
  status=$(sbx exec "$id" --status "$pid" --json | jq -r '.status // "unknown"')
  case $status in exited|killed|lost) break ;; esac
  sbx extend "$id" --ttl "$ttl" --json |
    jq -r --arg s "$status" '"\(now | todate) job \($s), auto-stop at \(.sandbox.archiveAfter)"'
  sleep "$every"
done
echo "$(date -u +%FT%TZ) job $status, lease released"
```

An `unknown` status (a failed API call) counts as alive, so one network error doesn't drop the lease.

We started a 66-minute job, longer than the default hour, on the sandbox above, set its TTL to 10 minutes, and held a lease that renewed every 4 minutes:

```bash
sbx extend $id --ttl 600
pid=$(sbx exec $id --detach 'for i in $(seq 1 66); do echo "minute $i/66 $(date -u +%T)"; sleep 60; done; echo "job finished"' | jq -r .processId)
./lease.sh $id $pid 600 240
```

```text
2026-10-27T15:53:21Z job running, auto-stop at 2026-10-27T16:03:21.695251Z
2026-10-27T15:57:22Z job running, auto-stop at 2026-10-27T16:07:22.000686Z
…
2026-10-27T16:49:25Z job running, auto-stop at 2026-10-27T16:59:25.978264Z
2026-10-27T16:53:26Z job running, auto-stop at 2026-10-27T17:03:26.289082Z
2026-10-27T16:57:26Z job running, auto-stop at 2026-10-27T17:07:26.596142Z
2026-10-27T17:01:26Z job exited, lease released
```

The deadline was never more than 10 minutes away, yet the job ran past the 16:52 default it was created with:

```json
{"status":"exited","exitCode":0,"startedAt":"2026-10-27T15:53:17.18676567Z","finishedAt":"2026-10-27T16:59:17.313608726Z", …}
```

With no more renewals, the sandbox stopped itself 4 seconds after the last deadline:

```json
{"state":"archived","stop":{"endedAt":"2026-10-27T17:07:30.47246Z","reason":"auto_stop","status":"completed"}}
```

The job's output stayed readable while the sandbox was stopped, through command history:

```bash
sbx history $id cmd_1sax2d0pucdo | tail -2
```

```text
minute 66/66 16:58:17
job finished
```

The whole run, 75 minutes of `small` time from create to auto-stop, came to 2,262 billable seconds of `default` time, which `sbx usage $id` priced at $0.02262.

Tune the two numbers to your job. The sandbox can run up to `TTL + EVERY` past the job's end; ours ran 8 minutes after the job finished. Add `sbx stop $id` after the loop if you want it to stop right away. Keep `EVERY` well under `TTL` so one missed renewal doesn't stop a live job. If a renewal is missed anyway, the stop keeps memory, and `sbx resume` usually brings the job back where it froze: see [what happens to a job if the sandbox stops](/guides/run-a-long-job-in-a-cloud-sandbox).

## When snapshots are off, the deadline is the end

A sandbox created with `--no-snapshots` keeps nothing, so its auto-stop is final. We created one with a 60-second TTL. Its `idleStopMinutes` came back as `0`, because an idle pause would discard it:

```json
{"id":"sb_lye4sci5f1","snapshots":false,"ttlSeconds":60,"idleStopMinutes":0,"archiveAfter":"2026-10-27T17:08:55.796031Z"}
```

It stopped with `"reason":"auto_stop"` about 35 seconds after its deadline. Then:

```bash
sbx resume $id
```

```json
{"event":"error","error":"This sandbox was created with snapshots off and cannot be resumed.","code":"snapshots_disabled","status":409}
```

Use snapshots off only for work whose results leave the VM before the deadline. Give such a sandbox a TTL with room to spare. The stop isn't exact to the second: ours came 4 and 35 seconds after the deadline.

## What keeping one up for a day costs

Billing is per second while a sandbox runs. A stopped one costs no compute, and its disk and memory image count toward your plan's included storage (50 GB on the $20 plan). From the [pricing](/pricing) rates:

| Size | Per hour | 24 hours | 7 days around the clock | 730 hours (a month) |
| - | - | - | - | - |
| `small` (2 vCPU, 4 GB) | $0.018 | $0.43 | $3.02 | $13.14 |
| `default` (4 vCPU, 8 GB) | $0.036 | $0.86 | $6.05 | $26.28 |
| `large` (8 vCPU, 16 GB) | $0.072 | $1.73 | $12.10 | $52.56 |
| `xlarge` (16 vCPU, 32 GB) | $0.20 | $4.80 | $33.60 | $146.00 |

A `small` sandbox running all month fits inside the $20 plan's included time. With a lease or idle pause, you pay only for the hours the job actually runs, plus the slack you choose.

## FAQ

### What's the longest a sandbox can run?

As long as you keep it running. One deadline can be at most 30 days ahead, and `sbx extend` can push it again at any time. `--no-auto-stop` removes it, except on the trial, where every sandbox must stop within 8 hours.

### Does a sandbox get deleted when it auto-stops?

No. It's stopped with its disk and memory, and `sbx resume` brings it back. The exceptions are sandboxes created with `--no-snapshots`, which can't be resumed, and accounts with zero data retention turned on, where a stop deletes the data.

### Can my agent keep its own sandbox alive?

Not with the in-sandbox `SANDBOXER_TOKEN`. Extending answers `403 api_key_action_forbidden`. Renew the deadline from the process that created the sandbox, as in the lease above.

### Does a running job stop the sandbox from pausing?

It stops idle pause, because a running command counts as activity. It doesn't hold off auto-stop. Set a TTL longer than the job, or renew it while the job runs.

### What if my balance runs out mid-job?

New creates and resumes are refused, but running sandboxes get a 24-hour grace period. After that they stop with memory and disk kept, and resume once you top up or turn on auto-refill.

## Related

- [Run a long job in a cloud sandbox and check on it later](/guides/run-a-long-job-in-a-cloud-sandbox)
- [Idle auto-pause and wake on use](/guides/idle-auto-pause-and-wake-on-use)
- [Persistent or ephemeral sandboxes for agents](/guides/persistent-or-ephemeral-sandboxes-for-agents)
- [Long-running tasks](/docs/long-running)
