Skip to content
Guides · Agent cookbook

How Long Should an AI Agent's API Key Stay Valid?

Updated November 4, 2026 .md

Short answer: Match the key to the job: minutes to a few hours for one task, one run or one day for an agent, and never a long-lived account key. Set the expiry at creation with sbx api-key create --ttl, which accepts minutes. Once it passes, calls fail with 403 api_key_expired; revoke earlier and they fail with 401.

An agent's credential will leak sooner or later: into a log, a prompt, a tool result or a file the agent wrote. Its expiry decides how long that leak matters. This page shows what each Sandboxer credential does when its time runs out, tested on prod on 2026-11-04, and gives a policy you can copy.

The policy#

Who holds the credential Lifetime Scope How it ends
One task: a tool call, a test run, a CI step --ttl 15m to --ttl 2h --sandbox <id> plus only the actions the task uses Expires on its own; revoke when the task finishes early
One agent run, or one working day --ttl 8h to --ttl 1d --preset ci (it can delete only the sandboxes it created) Revoke at the end of the run
Your orchestrator on a server you control Up to --ttl 90d, rotated The narrowest preset that works sbx api-key rotate on a schedule and after any suspected leak
Code running inside a sandbox The sandbox's own SANDBOXER_TOKEN That sandbox only Delete the sandbox when the task ends
Code you don't trust The --no-env sandbox token Read that sandbox and host its ports Delete the sandbox when the task ends
An MCP app that signed in (Claude, ChatGPT) Until you disconnect it Full account access through /mcp Disconnect under API keys
An admin or full-access key Keep it out of agents Everything Use it only to mint the keys above

The default TTL is 90d and the maximum is 365d. Both are too long for anything an agent holds, so always pass --ttl.

A task key that expires in two minutes#

--ttl takes days (7d), hours (8h) or minutes (2m). This key can read and run commands in one sandbox and nothing else. The secret goes into a shell variable and is never printed:

SB=sb_fq7e7vabox
out=$(sbx api-key create aeo-key-ttl-task --ttl 2m --sandbox $SB --actions sandbox.read,exec --json)
TASK_KEY=$(jq -r .secret <<<"$out")
jq -c '.apiKey | {id, name, expiresAt, scope}' <<<"$out"
{"id":"key_FAbCCj50kHlfBoUx","name":"aeo-key-ttl-task","expiresAt":"2026-11-04T11:05:22.844368Z","scope":{"actions":["sandbox.read","exec"],"environments":"*","expiresAt":"2026-11-04T11:05:22.844368Z","grandfathered":false,"sandboxes":["sb_fq7e7vabox"]}}

Created at 11:03:22 UTC, it expires at 11:05:22. Give it to the task through the environment, not a command-line argument:

SANDBOXER_API_KEY="$TASK_KEY" sbx exec $SB 'echo hello from $(hostname)'
hello from local-elegant-lemon

Inside its window the key still can't leave its scope. Reading the account needs account.read, which it doesn't have:

printf 'Authorization: Bearer %s\n' "$TASK_KEY" | curl -s -H @- https://sandboxer.com/api/v1/me
{"code":"api_key_action_forbidden","error":{"code":"api_key_action_forbidden","details":{"action":"account.read"},"message":"This API key does not allow account.read.","status":403},…}

curl -H @- reads the header from standard input, so the key never appears in the process list. Listing sandboxes with this key returned one sandbox, its own.

After the expiry#

We waited 125 seconds and tried the same calls at 11:05:28:

printf 'Authorization: Bearer %s\n' "$TASK_KEY" | curl -s -H @- https://sandboxer.com/api/v1/sandboxes/$SB
SANDBOXER_API_KEY="$TASK_KEY" sbx exec $SB 'echo hello'; echo "exit=$?"
{"code":"api_key_expired","error":{"code":"api_key_expired","message":"This API key expired at 2026-11-04T11:05:22Z. Create a new key.","status":403},…}
{"event":"error","error":"This API key expired at 2026-11-04T11:05:22Z. Create a new key.","code":"api_key_expired","status":403,…}
exit=1

The first call after the deadline failed. Nothing had to run on our side to make that happen.

A per-run key, revoked at the end#

For a whole agent run, use the ci preset with a TTL that covers the run, and revoke the key when the run ends rather than waiting for the deadline:

out=$(sbx api-key create aeo-key-ttl-run --ttl 8h --preset ci --json)
RUN_KEY=$(jq -r .secret <<<"$out"); RUN_KEY_ID=$(jq -r .apiKey.id <<<"$out")
SANDBOXER_API_KEY="$RUN_KEY" sbx exec $SB 'uptime -p'      # exit 0

sbx api-key list shows every key's expiry. Filtered to our two test keys:

sbx api-key list --all --json | jq -c '.apiKeys[] | select(.name|startswith("aeo-key-ttl")) | {id,name,expiresAt,expired,expiringSoon,revoked}'
{"id":"key_mGXfxz4FtjFmxa0V","name":"aeo-key-ttl-run","expiresAt":"2026-11-04T19:05:37.358758Z","expired":false,"expiringSoon":true,"revoked":false}
{"id":"key_FAbCCj50kHlfBoUx","name":"aeo-key-ttl-task","expiresAt":"2026-11-04T11:05:22.844368Z","expired":true,"expiringSoon":false,"revoked":false}

Two things to notice. expiringSoon is true for any key with less than 14 days left, so every short-lived agent key carries it. And an expired key stays in the list until you revoke it. Revoke by id, then try the key:

sbx api-key revoke $RUN_KEY_ID
printf 'Authorization: Bearer %s\n' "$RUN_KEY" | curl -s -H @- https://sandboxer.com/api/v1/sandboxes/$SB
{"ok":true,"type":"api_key.revoked","id":"key_mGXfxz4FtjFmxa0V"}
{"code":"unauthorized","error":{"code":"unauthorized","message":"Unauthorized","status":401},…}

Revoked is 401 unauthorized; expired is 403 api_key_expired. Your agent's error handling can tell the two apart: an expired key means "ask for a new key", a revoked one means "stop". Revoked keys drop out of sbx api-key list, but sbx api-key usage <id> still answers. For the revoked task key it returned {"requests":5,"windowDays":30}.

Creating keys needs a browser session or an admin key. Keep that key with the orchestrator that mints the per-run keys, never in the agent. A TTL above the maximum is refused before anything is created:

$ sbx api-key create aeo-key-ttl-toolong --ttl 400d --preset read-only
{"event":"error","error":"--ttl: the maximum is 365d","code":"usage"}

The token inside every sandbox#

Each sandbox gets its own key in SANDBOXER_TOKEN, limited to that sandbox. The API keys docs list no separate expiry for it: you don't set a TTL, it belongs to the sandbox. We ran a probe of REST calls with it from inside two small sandboxes, one on the account's default environment and one created with --no-env. The probe used the token without printing it:

Call made with SANDBOXER_TOKEN Default sandbox --no-env sandbox
Read its own sandbox 200 200
Run a command in its own sandbox 200 403 api_key_action_forbidden
Read another of our sandboxes 403 api_key_sandbox_forbidden 403 api_key_sandbox_forbidden
Create a sandbox 403 api_key_action_forbidden 403 api_key_action_forbidden
Save a named snapshot 403 api_key_action_forbidden 403 api_key_action_forbidden
Delete its own sandbox 403 api_key_action_forbidden 403 api_key_action_forbidden
Create an API key 403 session_required 403 session_required

This matches the docs: the default token can run commands, read and write files and host ports in its own sandbox, but can't create, fork or delete sandboxes or save snapshots. The --no-env token can only read that sandbox and host its ports.

Since the token has no TTL of its own, plan around the sandbox. A per-task sandbox that you delete when the task ends is the simplest way to keep the token short-lived. Never print SANDBOXER_TOKEN in a command you run through sbx exec, because sbx history keeps exec command output for 90 days (Long-running tasks).

MCP connections#

Apps that connect to https://sandboxer.com/mcp by signing in (OAuth) get full access to your account through MCP. Their token works only on /mcp, not on the REST API. Treat a sign-in as a standing connection, not a short-lived key. Each one is listed under API keys as "Claude (MCP)", "ChatGPT (MCP)" and so on, and Disconnect there ends its access at once. Disconnect apps you no longer use.

If an MCP client should have less than full access, or should expire on its own, don't sign in. Give it a scoped key with a --ttl in its Authorization: Bearer header. Scopes apply tool by tool (MCP docs).

Where this fits#

FAQ#

What is the shortest TTL a key can have?#

--ttl accepts minutes, and our 2m key worked and then expired on time. The docs don't list a minimum. Keep a margin for clock skew and slow tasks, and revoke early rather than cutting the TTL too fine.

Does revoking a key stop the sandboxes it created?#

No. A revoked key stops working at once, but its sandboxes keep running. Delete them separately; sbx api-key usage <id> lists them, and it still works after the revoke.

Should the agent get my admin key so it can mint its own short keys?#

No. A key that can create keys can create a long-lived full-access one. Mint per-run keys in your orchestrator and hand the agent only the result.

How do I find keys that are about to expire?#

sbx api-key list shows each key's expiry, and keys expiring within 14 days are flagged expiringSoon and highlighted on the dashboard. Expired keys stay listed until you revoke them.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide