Hanzo AI

E2B

E2B leases isolated sandboxes for code an agent wrote. Here that is /v1/sandbox, with /v1/exec for the one-shot snippet case.

E2B leases an isolated computer, runs code in it, and gives you its filesystem. /v1/sandbox (19 operations) is the same thing: lease, run, read, write, end. POST /v1/exec is the short path — one snippet, one answer, no lease to manage.

Start here

Mint a key, run one whole program, and take a lease only when the work has to outlive its own call.

# 1. mint a key — sk- belongs on a server, pk- is safe in a browser
curl -sS -X POST https://api.hanzo.ai/v1/account/keys \
  -H "Authorization: Bearer $HANZO_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{"type":"secret"}'

# 2. run a program in a throwaway sandbox — no lease to manage, nothing to clean up
curl -sS -X POST https://api.hanzo.ai/v1/exec \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"lang":"py","code":"print(1 + 1)"}'

# 3. hold the machine instead — dev attaches the project's disk, exec keeps nothing
curl -sS -X POST https://api.hanzo.ai/v1/sandbox/lease \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"class":"dev","project":"demo","ttlSec":900}'

Step 2 answers stdout, stderr, the files the program wrote, and the session_id of the sandbox it leased for you — send that id with the next run and it sees the same filesystem, which is the whole of runCode(). Step 3 is that computer held open under a name you keep: id is the argument run, read, write and end all take, and workdir is what a relative path in them resolves against.

Core capabilities

CapabilityWhat it doesOperations
/v1/sandboxLeases a real computer with its own filesystem, runs commands in it, reads and writes its files, and ends it. Terminal and screen are WebSockets behind a ticket.19
/v1/execRuns one whole program in a throwaway sandbox across thirteen languages, returns what it printed and what it wrote, and keeps the filesystem when you reuse session_id.4
/v1/account/keysMints, lists and revokes the sk- and pk- keys every call above authenticates with. Minting a class again rotates it in one step.3

Nouns

E2BHanzo
Sandbox.create()POST /v1/sandbox/lease
The sandbox id you reconnect withid in the lease answer, passed in every later body
sandbox.commands.run(cmd)POST /v1/sandbox/run
sandbox.files.write(path, bytes)POST /v1/sandbox/write, data base64
sandbox.files.read(path)POST /v1/sandbox/read, data base64, or entries for a directory
sandbox.kill()POST /v1/sandbox/end
timeoutMs / timeoutttlSec on the lease
Templateclassexec, dev, desktop or android — a closed set, not an image you build
Persistent template dataproject on the lease, which names the volume the work persists on
@e2b/code-interpreter runCode()POST /v1/exec with lang and code
Interactive terminal (PTY)POST /v1/sandbox/{id}/terminal/ticket, then the socket at /v1/sandbox/{id}/terminal/ws
Desktop streamPOST /v1/sandbox/{id}/screen/ticket, then /v1/sandbox/{id}/screen/ws
Listing your sandboxesGET /v1/sandbox

dev and desktop require a project; exec does not.

The call

E2B:

from e2b import Sandbox   # E2B_API_KEY in the environment

with Sandbox.create(timeout=60) as sandbox:
    sandbox.files.write("/home/user/main.py", b"print(1 + 1)")
    result = sandbox.commands.run("python /home/user/main.py")
    print(result.stdout)

Hanzo:

# 1. Lease. The answer carries id, class, runtime, status and workdir.
SB=$(curl -sS -X POST https://api.hanzo.ai/v1/sandbox/lease \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"class":"exec","ttlSec":60}' | jq -r .id)

# 2. Write. `data` is base64.
curl -sS -X POST https://api.hanzo.ai/v1/sandbox/write \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"id\":\"$SB\",\"path\":\"main.py\",\"data\":\"$(printf 'print(1 + 1)' | base64 -w0)\"}"

# 3. Run. Answers exitCode, stdout, stderr.
curl -sS -X POST https://api.hanzo.ai/v1/sandbox/run \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"id\":\"$SB\",\"command\":\"python main.py\"}"

# 4. Release it.
curl -sS -X POST https://api.hanzo.ai/v1/sandbox/end \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"id\":\"$SB\"}"

If all you want is one snippet, skip the lease entirely:

curl -X POST https://api.hanzo.ai/v1/exec \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"lang":"py","code":"print(1 + 1)"}'

A non-zero exit is a 200 carrying a failed program. "The tests failed" and "the sandbox is broken" are different facts and they get different status codes.

Pass a session name to run and the command's output is appended to that session's live log as it is produced, so a long agentic run can be watched rather than waited on.

What does not carry

No snapshots and no forking. E2B pauses a sandbox with its full state and boots new ones from that state. Leasing the same id again resumes a lease that is still running, which is reattachment, not restoration. When a lease ends, the sandbox is gone; purge on the end call decides whether the project volume goes with it.

No template build. E2B builds a template from your Dockerfile and caches it. Here class picks from a closed set of four, and the image behind the one you pick is the fleet's. There is no template registry to push to.

No environment variables on the lease. The lease body is class, id, project, runtime and ttlSec — nothing else. Set variables in the command you run.

No lifecycle events, metrics or OTel export. E2B emits sandbox lifecycle webhooks and per-sandbox metrics. GET /v1/sandbox answers from the org's own store rather than the cluster, so a sandbox whose pod has died still appears with the status it was last known to have — deliberate, because a lease you are being charged for should not vanish from the list.

No SSH and no git methods. The terminal is a WebSocket behind a ticket. Git work is a command you run, like any other.

How is this guide?