# E2B Documentation Source: https://e2b.mintlify.app/docs ## What is E2B? E2B provides isolated sandboxes that let agents safely execute code, process data, and run tools. Our SDKs make it easy to start and manage these environments. Start a sandbox and run code in a few lines: ```bash JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} npm i e2b ``` ```bash Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} pip install e2b ``` ```javascript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create() // Needs E2B_API_KEY environment variable const result = await sandbox.commands.run('echo "Hello from E2B Sandbox!"') console.log(result.stdout) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from e2b import Sandbox sandbox = Sandbox.create() # Needs E2B_API_KEY environment variable result = sandbox.commands.run('echo "Hello from E2B Sandbox!"') print(result.stdout) ``` ## E2B building blocks A quick overview of the core building blocks you'll interact with when using E2B. * [**Sandbox**](/docs/sandbox) — A fast, secure Linux VM created on demand for your agent * [**Template**](/docs/template/quickstart) — Defines what environment a sandbox starts with ## How to use the docs The documentation is split into three main sections: * [**Quickstart**](#quickstart) — Step-by-step tutorials that walk you through creating your first E2B sandboxes. * [**Examples**](#examples) — In-depth tutorials focused on specific use cases. Pick the topics that match what you're building. * [**SDK Reference**](https://e2b.dev/docs/sdk-reference) — A complete technical reference for every SDK method, parameter, and configuration option. ## Quickstart ## Examples Build AI agents that see, understand, and control virtual Linux desktops using E2B Desktop sandboxes. Use E2B sandboxes in your GitHub Actions workflows to run testing, validation, and AI code reviews. # Amp Source: https://e2b.mintlify.app/docs/agents/amp Run Amp in a secure E2B sandbox with full filesystem, terminal, and git access. [Amp](https://ampcode.com) is a coding agent with multi-model architecture and built-in code intelligence. E2B provides a pre-built `amp` template with Amp already installed. ## CLI Create a sandbox with the [E2B CLI](/docs/cli). ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} e2b sbx create amp ``` Once inside the sandbox, start Amp. ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} amp ``` ## Run headless Use `-x` for non-interactive mode and `--dangerously-allow-all` to auto-approve all tool calls (safe inside E2B sandboxes). Amp uses its own API key from [ampcode.com/settings](https://ampcode.com/settings). ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('amp', { envs: { AMP_API_KEY: process.env.AMP_API_KEY }, }) const result = await sandbox.commands.run( `amp --dangerously-allow-all -x "Create a hello world HTTP server in Go"` ) console.log(result.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("amp", envs={ "AMP_API_KEY": os.environ["AMP_API_KEY"], }) result = sandbox.commands.run( 'amp --dangerously-allow-all -x "Create a hello world HTTP server in Go"', ) print(result.stdout) sandbox.kill() ``` ### Example: work on a cloned repository ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('amp', { envs: { AMP_API_KEY: process.env.AMP_API_KEY }, timeoutMs: 600_000, }) await sandbox.git.clone('https://github.com/your-org/your-repo.git', { path: '/home/user/repo', username: 'x-access-token', password: process.env.GITHUB_TOKEN, depth: 1, }) const result = await sandbox.commands.run( `cd /home/user/repo && amp --dangerously-allow-all -x "Add error handling to all API endpoints"`, { onStdout: (data) => process.stdout.write(data) } ) const diff = await sandbox.commands.run('cd /home/user/repo && git diff') console.log(diff.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("amp", envs={ "AMP_API_KEY": os.environ["AMP_API_KEY"], }, timeout=600) sandbox.git.clone("https://github.com/your-org/your-repo.git", path="/home/user/repo", username="x-access-token", password=os.environ["GITHUB_TOKEN"], depth=1, ) result = sandbox.commands.run( 'cd /home/user/repo && amp --dangerously-allow-all -x "Add error handling to all API endpoints"', on_stdout=lambda data: print(data, end=""), ) diff = sandbox.commands.run("cd /home/user/repo && git diff") print(diff.stdout) sandbox.kill() ``` ## Streaming JSON Use `--stream-json` to get a real-time JSONL event stream with rich metadata — including tool calls, token usage, thinking blocks, and permission decisions. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('amp', { envs: { AMP_API_KEY: process.env.AMP_API_KEY }, }) const result = await sandbox.commands.run( `cd /home/user/repo && amp --dangerously-allow-all --stream-json -x "Find and fix all TODO comments"`, { onStdout: (data) => { for (const line of data.split('\n').filter(Boolean)) { const event = JSON.parse(line) if (event.type === 'assistant') { console.log(`[assistant] tokens: ${event.message.usage?.output_tokens}`) } else if (event.type === 'result') { console.log(`[done] ${event.message.subtype} in ${event.message.duration_ms}ms`) } } }, } ) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import json from e2b import Sandbox sandbox = Sandbox.create("amp", envs={ "AMP_API_KEY": os.environ["AMP_API_KEY"], }) def handle_event(data): for line in data.strip().split("\n"): if line: event = json.loads(line) if event["type"] == "assistant": usage = event.get("message", {}).get("usage", {}) print(f"[assistant] tokens: {usage.get('output_tokens')}") elif event["type"] == "result": msg = event["message"] print(f"[done] {msg['subtype']} in {msg['duration_ms']}ms") result = sandbox.commands.run( 'cd /home/user/repo && amp --dangerously-allow-all --stream-json -x "Find and fix all TODO comments"', on_stdout=handle_event, ) sandbox.kill() ``` ## Thread management Amp persists conversations as threads that can be resumed or continued with follow-up tasks. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('amp', { envs: { AMP_API_KEY: process.env.AMP_API_KEY }, timeoutMs: 600_000, }) // Start a new thread const initial = await sandbox.commands.run( `cd /home/user/repo && amp --dangerously-allow-all -x "Analyze the codebase and create a refactoring plan"`, { onStdout: (data) => process.stdout.write(data) } ) // List threads and get the most recent thread ID const threads = await sandbox.commands.run('amp threads list --json') const threadId = JSON.parse(threads.stdout)[0].id // Continue the thread with a follow-up task const followUp = await sandbox.commands.run( `cd /home/user/repo && amp threads continue ${threadId} --dangerously-allow-all -x "Now implement step 1 of the plan"`, { onStdout: (data) => process.stdout.write(data) } ) const diff = await sandbox.commands.run('cd /home/user/repo && git diff') console.log(diff.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import json from e2b import Sandbox sandbox = Sandbox.create("amp", envs={ "AMP_API_KEY": os.environ["AMP_API_KEY"], }, timeout=600) # Start a new thread initial = sandbox.commands.run( 'cd /home/user/repo && amp --dangerously-allow-all -x "Analyze the codebase and create a refactoring plan"', on_stdout=lambda data: print(data, end=""), ) # List threads and get the most recent thread ID threads = sandbox.commands.run("amp threads list --json") thread_id = json.loads(threads.stdout)[0]["id"] # Continue the thread with a follow-up task follow_up = sandbox.commands.run( f'cd /home/user/repo && amp threads continue {thread_id} --dangerously-allow-all -x "Now implement step 1 of the plan"', on_stdout=lambda data: print(data, end=""), ) diff = sandbox.commands.run("cd /home/user/repo && git diff") print(diff.stdout) sandbox.kill() ``` ## Build a custom template If you need to customize the environment (e.g. pre-install dependencies, add config files), build your own template on top of the pre-built `amp` template. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // template.ts import { Template } from 'e2b' export const template = Template() .fromTemplate('amp') ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # template.py from e2b import Template template = ( Template() .from_template("amp") ) ``` ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // build.ts import { Template, defaultBuildLogger } from 'e2b' import { template as ampTemplate } from './template' await Template.build(ampTemplate, 'my-amp', { cpuCount: 2, memoryMB: 2048, onBuildLogs: defaultBuildLogger(), }) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # build.py from e2b import Template, default_build_logger from template import template as amp_template Template.build(amp_template, "my-amp", cpu_count=2, memory_mb=2048, on_build_logs=default_build_logger(), ) ``` Run the build script to create the template. ```bash JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} npx tsx build.ts ``` ```bash Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} python build.py ``` ## Related guides Auto-pause, resume, and manage sandbox lifecycle Clone repos, manage branches, and push changes Connect to the sandbox via SSH for interactive sessions # Claude Code Source: https://e2b.mintlify.app/docs/agents/claude-code Run Claude Code in a secure E2B sandbox with full filesystem, terminal, and git access. [Claude Code](https://docs.anthropic.com/en/docs/claude-code) is Anthropic's agentic coding tool. E2B provides a pre-built `claude` template with Claude Code already installed. ## CLI Create a sandbox with the [E2B CLI](/docs/cli). ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} e2b sbx create claude ``` Once inside the sandbox, start Claude Code. ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} claude ``` ## Run headless Use `-p` for non-interactive mode and `--dangerously-skip-permissions` to auto-approve all tool calls (safe inside E2B sandboxes). ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('claude', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, }) const result = await sandbox.commands.run( `claude --dangerously-skip-permissions -p "Create a hello world HTTP server in Go"` ) console.log(result.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("claude", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }) result = sandbox.commands.run( 'claude --dangerously-skip-permissions -p "Create a hello world HTTP server in Go"', ) print(result.stdout) sandbox.kill() ``` ### Example: work on a cloned repository ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('claude', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, timeoutMs: 600_000, }) await sandbox.git.clone('https://github.com/your-org/your-repo.git', { path: '/home/user/repo', username: 'x-access-token', password: process.env.GITHUB_TOKEN, depth: 1, }) const result = await sandbox.commands.run( `cd /home/user/repo && claude --dangerously-skip-permissions -p "Add error handling to all API endpoints"`, { onStdout: (data) => process.stdout.write(data) } ) const diff = await sandbox.commands.run('cd /home/user/repo && git diff') console.log(diff.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("claude", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }, timeout=600) sandbox.git.clone("https://github.com/your-org/your-repo.git", path="/home/user/repo", username="x-access-token", password=os.environ["GITHUB_TOKEN"], depth=1, ) result = sandbox.commands.run( 'cd /home/user/repo && claude --dangerously-skip-permissions -p "Add error handling to all API endpoints"', on_stdout=lambda data: print(data, end=""), ) diff = sandbox.commands.run("cd /home/user/repo && git diff") print(diff.stdout) sandbox.kill() ``` ## Structured output Use `--output-format json` to get machine-readable responses — useful for building pipelines or extracting specific results. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('claude', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, }) const result = await sandbox.commands.run( `claude --dangerously-skip-permissions --output-format json -p "Review this codebase and list all security issues as JSON"` ) const response = JSON.parse(result.stdout) console.log(response) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import json from e2b import Sandbox sandbox = Sandbox.create("claude", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }) result = sandbox.commands.run( 'claude --dangerously-skip-permissions --output-format json -p "Review this codebase and list all security issues as JSON"', ) response = json.loads(result.stdout) print(response) sandbox.kill() ``` ## Streaming output Use `--output-format stream-json` to get a real-time JSONL event stream — including tool calls, token usage, and result metadata. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('claude', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, }) const result = await sandbox.commands.run( `cd /home/user/repo && claude --dangerously-skip-permissions --output-format stream-json -p "Find and fix all TODO comments"`, { onStdout: (data) => { for (const line of data.split('\n').filter(Boolean)) { const event = JSON.parse(line) if (event.type === 'assistant') { console.log(`[assistant] tokens: ${event.message.usage?.output_tokens}`) } else if (event.type === 'result') { console.log(`[done] ${event.subtype} in ${event.duration_ms}ms`) } } }, } ) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import json from e2b import Sandbox sandbox = Sandbox.create("claude", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }) def handle_event(data): for line in data.strip().split("\n"): if line: event = json.loads(line) if event["type"] == "assistant": usage = event.get("message", {}).get("usage", {}) print(f"[assistant] tokens: {usage.get('output_tokens')}") elif event["type"] == "result": print(f"[done] {event['subtype']} in {event['duration_ms']}ms") result = sandbox.commands.run( 'cd /home/user/repo && claude --dangerously-skip-permissions --output-format stream-json -p "Find and fix all TODO comments"', on_stdout=handle_event, ) sandbox.kill() ``` ## Resume a session Claude Code persists conversations that can be resumed with follow-up tasks using `--resume`. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('claude', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, timeoutMs: 600_000, }) // Start a new session const initial = await sandbox.commands.run( `cd /home/user/repo && claude --dangerously-skip-permissions --output-format json -p "Analyze the codebase and create a refactoring plan"` ) // Extract session ID from the JSON response const response = JSON.parse(initial.stdout) const sessionId = response.session_id // Continue with a follow-up task const followUp = await sandbox.commands.run( `cd /home/user/repo && claude --dangerously-skip-permissions --resume ${sessionId} -p "Now implement step 1 of the plan"`, { onStdout: (data) => process.stdout.write(data) } ) const diff = await sandbox.commands.run('cd /home/user/repo && git diff') console.log(diff.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import json from e2b import Sandbox sandbox = Sandbox.create("claude", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }, timeout=600) # Start a new session initial = sandbox.commands.run( 'cd /home/user/repo && claude --dangerously-skip-permissions --output-format json -p "Analyze the codebase and create a refactoring plan"', ) # Extract session ID from the JSON response response = json.loads(initial.stdout) session_id = response["session_id"] # Continue with a follow-up task follow_up = sandbox.commands.run( f'cd /home/user/repo && claude --dangerously-skip-permissions --resume {session_id} -p "Now implement step 1 of the plan"', on_stdout=lambda data: print(data, end=""), ) diff = sandbox.commands.run("cd /home/user/repo && git diff") print(diff.stdout) sandbox.kill() ``` ## Custom system prompt Write a `CLAUDE.md` file into the sandbox for project context or use `--system-prompt` to provide task-specific instructions. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('claude', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, }) // Write project context await sandbox.files.write('/home/user/repo/CLAUDE.md', ` You are working on a Go microservice. Always use structured logging with slog. Follow the project's error handling conventions in pkg/errors. `) const result = await sandbox.commands.run( `cd /home/user/repo && claude --dangerously-skip-permissions -p "Add a /healthz endpoint"` ) console.log(result.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("claude", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }) # Write project context sandbox.files.write("/home/user/repo/CLAUDE.md", """ You are working on a Go microservice. Always use structured logging with slog. Follow the project's error handling conventions in pkg/errors. """) result = sandbox.commands.run( 'cd /home/user/repo && claude --dangerously-skip-permissions -p "Add a /healthz endpoint"', ) print(result.stdout) sandbox.kill() ``` ## Connect MCP tools Claude Code has built-in support for [MCP](https://modelcontextprotocol.io/). E2B provides an [MCP gateway](/docs/mcp) that gives Claude access to 200+ tools from the [Docker MCP Catalog](https://hub.docker.com/mcp). ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('claude', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, mcp: { browserbase: { apiKey: process.env.BROWSERBASE_API_KEY, projectId: process.env.BROWSERBASE_PROJECT_ID, }, }, }) const mcpUrl = sandbox.getMcpUrl() const mcpToken = await sandbox.getMcpToken() await sandbox.commands.run( `claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"` ) const result = await sandbox.commands.run( `claude --dangerously-skip-permissions -p "Use browserbase to research E2B and summarize your findings"`, { onStdout: console.log } ) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("claude", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }, mcp={ "browserbase": { "apiKey": os.environ["BROWSERBASE_API_KEY"], "projectId": os.environ["BROWSERBASE_PROJECT_ID"], }, }) mcp_url = sandbox.get_mcp_url() mcp_token = sandbox.get_mcp_token() sandbox.commands.run( f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"', ) result = sandbox.commands.run( 'claude --dangerously-skip-permissions -p "Use browserbase to research E2B and summarize your findings"', on_stdout=lambda data: print(data, end=""), ) sandbox.kill() ``` ## Build a custom template If you need to customize the environment (e.g. pre-install dependencies, add config files), build your own template on top of the pre-built `claude` template. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // template.ts import { Template } from 'e2b' export const template = Template() .fromTemplate('claude') ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # template.py from e2b import Template template = ( Template() .from_template("claude") ) ``` ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // build.ts import { Template, defaultBuildLogger } from 'e2b' import { template as claudeCodeTemplate } from './template' await Template.build(claudeCodeTemplate, 'my-claude', { cpuCount: 2, memoryMB: 2048, onBuildLogs: defaultBuildLogger(), }) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # build.py from e2b import Template, default_build_logger from template import template as claude_code_template Template.build(claude_code_template, "my-claude", cpu_count=2, memory_mb=2048, on_build_logs=default_build_logger(), ) ``` Run the build script to create the template. ```bash JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} npx tsx build.ts ``` ```bash Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} python build.py ``` ## Related guides Connect Claude Code to 200+ MCP tools Auto-pause, resume, and manage sandbox lifecycle Clone repos, manage branches, and push changes # Codex Source: https://e2b.mintlify.app/docs/agents/codex Run OpenAI Codex in a secure E2B sandbox with full filesystem, terminal, and git access. [Codex](https://github.com/openai/codex) is OpenAI's open-source coding agent. E2B provides a pre-built `codex` template with Codex already installed. ## CLI Create a sandbox with the [E2B CLI](/docs/cli). ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} e2b sbx create codex ``` Once inside the sandbox, start Codex. ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} codex ``` ## Run headless Use `codex exec` for non-interactive mode and `--full-auto` to auto-approve tool calls (safe inside E2B sandboxes). Pass `--skip-git-repo-check` to bypass git directory ownership checks inside the sandbox. Pass `CODEX_API_KEY` as an environment variable. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('codex', { envs: { CODEX_API_KEY: process.env.CODEX_API_KEY }, }) const result = await sandbox.commands.run( `codex exec --full-auto --skip-git-repo-check "Create a hello world HTTP server in Go"` ) console.log(result.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("codex", envs={ "CODEX_API_KEY": os.environ["CODEX_API_KEY"], }) result = sandbox.commands.run( 'codex exec --full-auto --skip-git-repo-check "Create a hello world HTTP server in Go"', ) print(result.stdout) sandbox.kill() ``` ### Example: work on a cloned repository Use `-C` to set Codex's working directory to a cloned repo. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('codex', { envs: { CODEX_API_KEY: process.env.CODEX_API_KEY }, timeoutMs: 600_000, }) await sandbox.git.clone('https://github.com/your-org/your-repo.git', { path: '/home/user/repo', username: 'x-access-token', password: process.env.GITHUB_TOKEN, depth: 1, }) const result = await sandbox.commands.run( `codex exec --full-auto --skip-git-repo-check -C /home/user/repo "Add error handling to all API endpoints"`, { onStdout: (data) => process.stdout.write(data) } ) const diff = await sandbox.commands.run('cd /home/user/repo && git diff') console.log(diff.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("codex", envs={ "CODEX_API_KEY": os.environ["CODEX_API_KEY"], }, timeout=600) sandbox.git.clone("https://github.com/your-org/your-repo.git", path="/home/user/repo", username="x-access-token", password=os.environ["GITHUB_TOKEN"], depth=1, ) result = sandbox.commands.run( 'codex exec --full-auto --skip-git-repo-check -C /home/user/repo "Add error handling to all API endpoints"', on_stdout=lambda data: print(data, end=""), ) diff = sandbox.commands.run("cd /home/user/repo && git diff") print(diff.stdout) sandbox.kill() ``` ## Schema-validated output Use `--output-schema` to constrain the agent's final response to a JSON Schema. This ensures the output conforms to a specific structure — useful for building reliable pipelines. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('codex', { envs: { CODEX_API_KEY: process.env.CODEX_API_KEY }, }) await sandbox.files.write('/home/user/schema.json', JSON.stringify({ type: 'object', properties: { issues: { type: 'array', items: { type: 'object', properties: { file: { type: 'string' }, line: { type: 'number' }, severity: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] }, description: { type: 'string' }, }, required: ['file', 'severity', 'description'], }, }, }, required: ['issues'], })) const result = await sandbox.commands.run( `codex exec --full-auto --skip-git-repo-check --output-schema /home/user/schema.json -C /home/user/repo "Review this codebase for security issues"` ) const response = JSON.parse(result.stdout) console.log(response.issues) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import json from e2b import Sandbox sandbox = Sandbox.create("codex", envs={ "CODEX_API_KEY": os.environ["CODEX_API_KEY"], }) sandbox.files.write("/home/user/schema.json", json.dumps({ "type": "object", "properties": { "issues": { "type": "array", "items": { "type": "object", "properties": { "file": {"type": "string"}, "line": {"type": "number"}, "severity": {"type": "string", "enum": ["low", "medium", "high", "critical"]}, "description": {"type": "string"}, }, "required": ["file", "severity", "description"], }, }, }, "required": ["issues"], })) result = sandbox.commands.run( 'codex exec --full-auto --skip-git-repo-check --output-schema /home/user/schema.json -C /home/user/repo "Review this codebase for security issues"', ) response = json.loads(result.stdout) print(response["issues"]) sandbox.kill() ``` ## Streaming events Use `--json` to get a JSONL event stream. Each line is a JSON object representing an agent event (tool calls, file changes, messages). Progress goes to stderr; events go to stdout. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('codex', { envs: { CODEX_API_KEY: process.env.CODEX_API_KEY }, }) const result = await sandbox.commands.run( `codex exec --full-auto --skip-git-repo-check --json -C /home/user/repo "Refactor the utils module into separate files"`, { onStdout: (data) => { for (const line of data.split('\n').filter(Boolean)) { const event = JSON.parse(line) console.log(`[${event.type}]`, event) } }, } ) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import json from e2b import Sandbox sandbox = Sandbox.create("codex", envs={ "CODEX_API_KEY": os.environ["CODEX_API_KEY"], }) def handle_event(data): for line in data.strip().split("\n"): if line: event = json.loads(line) print(f"[{event['type']}]", event) result = sandbox.commands.run( 'codex exec --full-auto --skip-git-repo-check --json -C /home/user/repo "Refactor the utils module into separate files"', on_stdout=handle_event, ) sandbox.kill() ``` ## Image input Pass screenshots or design mockups with `--image` to give Codex visual context alongside the prompt. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import fs from 'fs' import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('codex', { envs: { CODEX_API_KEY: process.env.CODEX_API_KEY }, timeoutMs: 600_000, }) // Upload a design mockup to the sandbox await sandbox.files.write( '/home/user/mockup.png', fs.readFileSync('./mockup.png') ) const result = await sandbox.commands.run( `codex exec --full-auto --skip-git-repo-check --image /home/user/mockup.png -C /home/user/repo "Implement this UI design as a React component"`, { onStdout: (data) => process.stdout.write(data) } ) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("codex", envs={ "CODEX_API_KEY": os.environ["CODEX_API_KEY"], }, timeout=600) # Upload a design mockup to the sandbox with open("./mockup.png", "rb") as f: sandbox.files.write("/home/user/mockup.png", f) result = sandbox.commands.run( 'codex exec --full-auto --skip-git-repo-check --image /home/user/mockup.png -C /home/user/repo "Implement this UI design as a React component"', on_stdout=lambda data: print(data, end=""), ) sandbox.kill() ``` ## Build a custom template If you need to customize the environment (e.g. pre-install dependencies, add config files), build your own template on top of the pre-built `codex` template. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // template.ts import { Template } from 'e2b' export const template = Template() .fromTemplate('codex') ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # template.py from e2b import Template template = ( Template() .from_template("codex") ) ``` ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // build.ts import { Template, defaultBuildLogger } from 'e2b' import { template as codexTemplate } from './template' await Template.build(codexTemplate, 'my-codex', { cpuCount: 2, memoryMB: 2048, onBuildLogs: defaultBuildLogger(), }) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # build.py from e2b import Template, default_build_logger from template import template as codex_template Template.build(codex_template, "my-codex", cpu_count=2, memory_mb=2048, on_build_logs=default_build_logger(), ) ``` Run the build script to create the template. ```bash JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} npx tsx build.ts ``` ```bash Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} python build.py ``` ## Related guides Auto-pause, resume, and manage sandbox lifecycle Clone repos, manage branches, and push changes Connect to the sandbox via SSH for interactive sessions # OpenAI Agents SDK Source: https://e2b.mintlify.app/docs/agents/openai-agents-sdk Use E2B sandboxes with the OpenAI Agents SDK. The [OpenAI Agents SDK](https://github.com/openai/openai-agents-python) is a framework for building agentic workflows. E2B provides a native integration that lets you run `SandboxAgent` instances inside isolated E2B sandboxes — giving your agents full filesystem, terminal, and network access in a secure environment. To use E2B as the sandbox backend: 1. Create a sandbox session with `E2BSandboxClient`. 2. Build a `SandboxAgent` with your instructions and model. 3. Run the agent and pass the sandbox session through `RunConfig`. ## Install the dependencies Install the [OpenAI Agents SDK](https://pypi.org/project/openai-agents/) with the E2B extra to pull in the sandbox integration. ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} pip install openai-agents[e2b] ``` You will also need API keys for OpenAI and E2B. ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} export OPENAI_API_KEY="..." export E2B_API_KEY="..." ``` ## Basic example Create an `E2BSandboxClient`, start a session, and run a `SandboxAgent` inside it. The agent gets full access to the sandbox environment — it can run commands, read and write files, and inspect the workspace. ### Create a session Initialize the `E2BSandboxClient` and create a sandbox session. The `pause_on_exit` option keeps the sandbox available after the script finishes so you can inspect its state. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents.extensions.sandbox import ( E2BSandboxClient, E2BSandboxClientOptions, E2BSandboxType, ) client = E2BSandboxClient() session = await client.create( options=E2BSandboxClientOptions( sandbox_type=E2BSandboxType.E2B, timeout=900, pause_on_exit=True, ) ) ``` ### Build and run the agent Define a `SandboxAgent` with a name, model, and instructions, then run it against the sandbox session using `Runner.run`. The result contains the agent's final output. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import ModelSettings, Runner from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig agent = SandboxAgent( name="Workspace Inspector", model="gpt-5.4", instructions=( "Inspect the workspace, explain what files exist, and summarize the project." ), model_settings=ModelSettings(tool_choice="required"), ) result = await Runner.run( agent, "Look around the workspace and summarize what you find.", run_config=RunConfig(sandbox=SandboxRunConfig(session=session)), ) print(result.final_output) ``` ### Shut down Always shut down the session when you're done to release sandbox resources. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} await session.shutdown() ``` ### Full example The complete script that ties the steps above together. ```python expandable theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import asyncio from agents import ModelSettings, Runner from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig from agents.extensions.sandbox import ( E2BSandboxClient, E2BSandboxClientOptions, E2BSandboxType, ) async def main() -> None: client = E2BSandboxClient() session = await client.create( options=E2BSandboxClientOptions( sandbox_type=E2BSandboxType.E2B, timeout=900, pause_on_exit=True, ) ) try: agent = SandboxAgent( name="Workspace Inspector", model="gpt-5.4", instructions=( "Inspect the workspace, explain what files exist, and summarize the project." ), model_settings=ModelSettings(tool_choice="required"), ) result = await Runner.run( agent, "Look around the workspace and summarize what you find.", run_config=RunConfig(sandbox=SandboxRunConfig(session=session)), ) print(result.final_output) finally: await session.shutdown() asyncio.run(main()) ``` *** ## Build an app with multiple versions A common pattern is to start from the same starter app and create multiple versions in separate sandboxes — useful when comparing a first pass with a polished revision, or generating live preview URLs for each version. Based on the [`homepage_vite_basic_updated.ipynb`](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/e2b_demos/homepage_vite_basic_updated.ipynb) notebook from the Agents SDK repo. ### Define a manifest A `Manifest` describes the starter files your agent will work with. Each entry is a `File` with its content encoded as bytes. This lets you seed multiple sandboxes from the same baseline — useful when comparing different versions of an app. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents.sandbox import Manifest from agents.sandbox.entries import File def build_manifest() -> Manifest: return Manifest( entries={ "package.json": File(content=PACKAGE_JSON.encode()), "index.html": File(content=INDEX_HTML.encode()), "vite.config.js": File(content=VITE_CONFIG_JS.encode()), "src/main.tsx": File(content=MAIN_TSX.encode()), "src/App.tsx": File(content=APP_TSX.encode()), } ) ``` ### Create a sandbox session Create a sandbox session with the manifest, exposed ports for live previews, and internet access so the agent can install npm packages. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents.extensions.sandbox import ( E2BSandboxClient, E2BSandboxClientOptions, E2BSandboxType, ) session = await E2BSandboxClient().create( manifest=build_manifest(), options=E2BSandboxClientOptions( sandbox_type=E2BSandboxType.E2B, timeout=1800, exposed_ports=(4173,), allow_internet_access=True, pause_on_exit=True, ), ) await session.start() ``` ### Run the agent Build a `SandboxAgent` with capabilities like `ApplyPatch` and `Shell`, then run it against the sandbox session. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import ModelSettings, Runner from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig from agents.sandbox.capabilities import ApplyPatch, Shell agent = SandboxAgent( name="E2B Vite Builder", model="gpt-5.4-mini", instructions="Update the Vite app in the sandbox workspace and return a concise summary.", default_manifest=build_manifest(), capabilities=[ApplyPatch(), Shell()], model_settings=ModelSettings(tool_choice="required"), ) result = await Runner.run( agent, "Make the basic version now.", run_config=RunConfig(sandbox=SandboxRunConfig(session=session)), ) ``` ### Start a preview server After the agent finishes, install dependencies, start the Vite dev server, and resolve the exposed port to get a live preview URL. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} await session.exec( "sh", "-lc", ( "npm install >/tmp/e2b-demo-npm-install.log 2>&1 && " "nohup npm run dev -- --host 0.0.0.0 --port 4173 " ">/tmp/e2b-demo-vite.log 2>&1 &" ), shell=False, timeout=120, ) preview_url = (await session.resolve_exposed_port(4173)).url_for("http") ``` ### Full example The complete `run_version()` helper ties all the steps above together. Call it once per version to get isolated sandboxes with their own preview URLs. Based on the [`homepage_vite_basic_updated.ipynb`](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/e2b_demos/homepage_vite_basic_updated.ipynb) notebook from the Agents SDK repo. ```python expandable theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import ModelSettings, Runner from agents.run import RunConfig from agents.sandbox import Manifest, SandboxAgent, SandboxRunConfig from agents.sandbox.capabilities import ApplyPatch, Shell from agents.sandbox.entries import File from agents.extensions.sandbox import ( E2BSandboxClient, E2BSandboxClientOptions, E2BSandboxType, ) def build_manifest() -> Manifest: return Manifest( entries={ "package.json": File(content=PACKAGE_JSON.encode()), "index.html": File(content=INDEX_HTML.encode()), "vite.config.js": File(content=VITE_CONFIG_JS.encode()), "src/main.tsx": File(content=MAIN_TSX.encode()), "src/App.tsx": File(content=APP_TSX.encode()), } ) async def run_version(version_name: str, version_prompt: str) -> dict[str, str]: session = await E2BSandboxClient().create( manifest=build_manifest(), options=E2BSandboxClientOptions( sandbox_type=E2BSandboxType.E2B, timeout=1800, exposed_ports=(4173,), allow_internet_access=True, pause_on_exit=True, ), ) await session.start() agent = SandboxAgent( name=f"E2B Vite {version_name.title()} Builder", model="gpt-5.4-mini", instructions=( "Update the Vite app in the sandbox workspace and return a concise summary." ), developer_instructions=( f"Version goal: {version_prompt}\n" "Start from the tiny Vite starter. You may create src/styles.css if you want." ), default_manifest=build_manifest(), capabilities=[ApplyPatch(), Shell()], model_settings=ModelSettings(tool_choice="required"), ) result = await Runner.run( agent, f"Make the {version_name} version now.", run_config=RunConfig(sandbox=SandboxRunConfig(session=session)), ) await session.exec( "sh", "-lc", ( "npm install >/tmp/e2b-demo-npm-install.log 2>&1 && " "nohup npm run dev -- --host 0.0.0.0 --port 4173 " ">/tmp/e2b-demo-vite.log 2>&1 &" ), shell=False, timeout=120, ) preview_url = (await session.resolve_exposed_port(4173)).url_for("http") return { "summary": str(result.final_output), "preview_url": preview_url, } ``` *** ## MCP-powered research agents You can create sandboxes with [MCP](https://modelcontextprotocol.io/) servers enabled, then connect the Agents SDK to the sandbox's MCP gateway. This gives you an agent that can discover sources with search-oriented MCP servers, verify pages in a browser, and keep all of that execution inside the sandbox. The Agents SDK repo includes a concrete example in [`deep_research_mcp.py`](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/e2b_demos/deep_research_mcp.py). ### Configure MCP servers Pass MCP server configurations when creating the sandbox session. This example enables [Browserbase](https://www.browserbase.com/) for browser automation and [Exa](https://exa.ai/) for search. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} session = await client.create( options=E2BSandboxClientOptions( sandbox_type=E2BSandboxType.E2B, timeout=900, pause_on_exit=True, mcp={ "browserbase": { "apiKey": os.environ["BROWSERBASE_API_KEY"], "geminiApiKey": os.environ["GEMINI_API_KEY"], "projectId": os.environ["BROWSERBASE_PROJECT_ID"], }, "exa": { "apiKey": os.environ["EXA_API_KEY"], }, }, ), ) ``` ### Connect to the MCP gateway Use `MCPServerStreamableHttp` to connect to the sandbox's MCP gateway. This gives the agent access to all the MCP servers you configured above. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents.mcp import MCPServerStreamableHttp async with MCPServerStreamableHttp( name="E2B MCP Gateway", params={ "url": mcp_url, "headers": {"Authorization": f"Bearer {mcp_token}"}, "timeout": 30, "sse_read_timeout": 300, }, ) as server: ... ``` ### Run the agent Pass the MCP server to the `SandboxAgent` via `mcp_servers`. The agent can now discover and call tools from all configured MCP servers. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import ModelSettings, Runner from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig agent = SandboxAgent( name="Deep Research Assistant", model="gpt-5.4", instructions=( "Use Exa to discover strong sources and Browserbase to verify important claims." ), mcp_servers=[server], model_settings=ModelSettings(tool_choice="required"), ) result = await Runner.run( agent, "Research browser automation infrastructure for AI agents.", run_config=RunConfig(sandbox=SandboxRunConfig(session=session)), ) ``` ### Full example The complete script combining session creation, MCP gateway connection, and agent execution. ```python expandable theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import ModelSettings, Runner from agents.mcp import MCPServerStreamableHttp from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig session = await client.create( options=E2BSandboxClientOptions( sandbox_type=E2BSandboxType.E2B, timeout=900, pause_on_exit=True, mcp={ "browserbase": { "apiKey": os.environ["BROWSERBASE_API_KEY"], "geminiApiKey": os.environ["GEMINI_API_KEY"], "projectId": os.environ["BROWSERBASE_PROJECT_ID"], }, "exa": { "apiKey": os.environ["EXA_API_KEY"], }, }, ), ) async with MCPServerStreamableHttp( name="E2B MCP Gateway", params={ "url": mcp_url, "headers": {"Authorization": f"Bearer {mcp_token}"}, "timeout": 30, "sse_read_timeout": 300, }, ) as server: agent = SandboxAgent( name="Deep Research Assistant", model="gpt-5.4", instructions=( "Use Exa to discover strong sources and Browserbase to verify important claims." ), mcp_servers=[server], model_settings=ModelSettings(tool_choice="required"), ) result = await Runner.run( agent, "Research browser automation infrastructure for AI agents.", run_config=RunConfig(sandbox=SandboxRunConfig(session=session)), ) ``` *** ## Parallel sandbox workers Use one coordinator agent to launch multiple specialized review or analysis lanes across separate sandboxes. Each lane runs in its own isolated environment, and the coordinator synthesizes the results into a single summary. The Agents SDK repo includes a concrete example in [`fullstack_code_review_parallel.py`](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/e2b_demos/fullstack_code_review_parallel.py). That example uses separate E2B-backed lanes for frontend review, backend review, and git tree review. ### Define the agents Create specialized `SandboxAgent` instances for each review lane, plus a regular `Agent` as the coordinator that will synthesize the results. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import Agent from agents.sandbox import SandboxAgent frontend_agent = SandboxAgent( name="Frontend Reviewer", model="gpt-5.4", instructions="Review the rendered frontend and identify UX and code risks.", ) backend_agent = SandboxAgent( name="Backend Reviewer", model="gpt-5.4", instructions="Review the API implementation and identify validation and auth risks.", ) coordinator = Agent( name="Review Coordinator", model="gpt-5.4", instructions=( "Run the available review lanes, compare their evidence, and produce a single summary." ), ) ``` ### Run the lanes Run each review agent against its own sandbox session. The lanes are independent and can run concurrently. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import Runner from agents.run import RunConfig from agents.sandbox import SandboxRunConfig frontend_result = await Runner.run( frontend_agent, "Review the frontend workspace.", run_config=RunConfig(sandbox=SandboxRunConfig(session=frontend_session)), ) backend_result = await Runner.run( backend_agent, "Review the backend workspace.", run_config=RunConfig(sandbox=SandboxRunConfig(session=backend_session)), ) ``` ### Synthesize the results Feed the findings from each lane into the coordinator agent to produce a single summary. ```python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} final_result = await Runner.run( coordinator, f"Frontend findings: {frontend_result.final_output}\n\n" f"Backend findings: {backend_result.final_output}", ) ``` ### Full example The complete script defining agents, running parallel review lanes, and synthesizing results. ```python expandable theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from agents import Agent, Runner from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig frontend_agent = SandboxAgent( name="Frontend Reviewer", model="gpt-5.4", instructions="Review the rendered frontend and identify UX and code risks.", ) backend_agent = SandboxAgent( name="Backend Reviewer", model="gpt-5.4", instructions="Review the API implementation and identify validation and auth risks.", ) coordinator = Agent( name="Review Coordinator", model="gpt-5.4", instructions=( "Run the available review lanes, compare their evidence, and produce a single summary." ), ) frontend_result = await Runner.run( frontend_agent, "Review the frontend workspace.", run_config=RunConfig(sandbox=SandboxRunConfig(session=frontend_session)), ) backend_result = await Runner.run( backend_agent, "Review the backend workspace.", run_config=RunConfig(sandbox=SandboxRunConfig(session=backend_session)), ) final_result = await Runner.run( coordinator, f"Frontend findings: {frontend_result.final_output}\n\n" f"Backend findings: {backend_result.final_output}", ) ``` ## Reference examples The OpenAI Agents SDK repository includes several complete examples demonstrating E2B sandbox integration. Build and iterate on a Vite app across isolated sandboxes Research agent with Browserbase and Exa via MCP Multi-lane code review with a coordinator agent Getting started notebook for E2B sandbox integration # Deploy OpenClaw Source: https://e2b.mintlify.app/docs/agents/openclaw/openclaw-gateway Start the OpenClaw gateway in an E2B sandbox and connect your browser. ## Quick start This launches your OpenClaw [gateway](https://docs.openclaw.ai/gateway) site (web UI for chatting with agents). ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const TOKEN = process.env.OPENCLAW_APP_TOKEN || 'my-gateway-token' const PORT = 18789 // 1. Create sandbox const sandbox = await Sandbox.create('openclaw', { envs: { OPENAI_API_KEY: process.env.OPENAI_API_KEY }, timeoutMs: 3600_000, }) // 2. Set the default model await sandbox.commands.run('openclaw config set agents.defaults.model.primary openai/gpt-5.2') // 3. Set insecure control UI flags and start the gateway with token auth await sandbox.commands.run( `bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth true && ` + `openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true && ` + `openclaw gateway --allow-unconfigured --bind lan --auth token --token ${TOKEN} --port ${PORT}'`, { background: true } ) // 4. Wait for the gateway to start listening for (let i = 0; i < 45; i++) { const probe = await sandbox.commands.run( `bash -lc 'ss -ltn | grep -q ":${PORT} " && echo ready || echo waiting'` ) if (probe.stdout.trim() === 'ready') break await new Promise((r) => setTimeout(r, 1000)) } const url = `https://${sandbox.getHost(PORT)}/?token=${TOKEN}` console.log(`Gateway: ${url}`) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os, time from e2b import Sandbox TOKEN = os.environ.get("OPENCLAW_APP_TOKEN", "my-gateway-token") PORT = 18789 # 1. Create sandbox sandbox = Sandbox.create("openclaw", envs={ "OPENAI_API_KEY": os.environ["OPENAI_API_KEY"], }, timeout=3600) # 2. Set the default model sandbox.commands.run("openclaw config set agents.defaults.model.primary openai/gpt-5.2") # 3. Set insecure control UI flags and start the gateway with token auth sandbox.commands.run( f"bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth true && " f"openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true && " f"openclaw gateway --allow-unconfigured --bind lan --auth token --token {TOKEN} --port {PORT}'", background=True, ) # 4. Wait for the gateway to start listening for _ in range(45): probe = sandbox.commands.run( f'bash -lc \'ss -ltn | grep -q ":{PORT} " && echo ready || echo waiting\'' ) if probe.stdout.strip() == "ready": break time.sleep(1) url = f"https://{sandbox.get_host(PORT)}/?token={TOKEN}" print(f"Gateway: {url}") ``` Visit the printed `Gateway` URL in your browser. If you run in secure mode (set `gateway.controlUi.dangerouslyDisableDeviceAuth false`), run this after opening the URL to poll pending pairing requests and approve the first one. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // 5. Poll for the browser's pending device request and approve it for (let i = 0; i < 30; i++) { try { const res = await sandbox.commands.run( `openclaw devices list --json --url ws://127.0.0.1:${PORT} --token ${TOKEN}` ) const data = JSON.parse(res.stdout) if (data.pending?.length) { const rid = data.pending[0].requestId await sandbox.commands.run( `openclaw devices approve ${rid} --token ${TOKEN} --url ws://127.0.0.1:${PORT}` ) console.log(`Device approved: ${rid}`) break } } catch {} await new Promise((r) => setTimeout(r, 2000)) } ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import json # 5. Poll for the browser's pending device request and approve it for _ in range(30): try: res = sandbox.commands.run( f"openclaw devices list --json --url ws://127.0.0.1:{PORT} --token {TOKEN}" ) data = json.loads(res.stdout) if data.get("pending"): rid = data["pending"][0]["requestId"] sandbox.commands.run( f"openclaw devices approve {rid} --token {TOKEN} --url ws://127.0.0.1:{PORT}" ) print(f"Device approved: {rid}") break except Exception: pass time.sleep(2) ``` Once approved, the browser connects and the gateway UI loads. ## How it works | Step | What happens | | ---------------------------- | ---------------------------------------------------------------------------- | | `--bind lan` | Gateway listens on `0.0.0.0` so E2B can proxy it | | `--auth token` | Requires `?token=` on the URL for HTTP and WebSocket auth | | Browser opens URL | Gateway serves the UI, browser opens a WebSocket | | `code=1008 pairing required` | Gateway closes the WebSocket until the device is approved (secure mode only) | | `devices approve` | Approves the browser's device fingerprint (secure mode only) | | Browser reconnects | WebSocket connects successfully, UI is live | ## Gateway flags reference | Flag | Purpose | | ---------------------- | -------------------------------------------------- | | `--allow-unconfigured` | Start without a full config file | | `--bind lan` | Bind to `0.0.0.0` (required for E2B port proxying) | | `--auth token` | Enable token-based authentication | | `--token ` | The auth token (passed as `?token=` in the URL) | | `--port ` | Gateway listen port (default: `18789`) | ## How to restart the gateway Use this when the gateway is already running and you want a clean restart (for example, after changing model or env settings). We can't use the `openclaw gateway restart` command here. Some SDK environments cannot target a specific Unix user in `commands.run`. The commands below use the default command user context. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} const TOKEN = process.env.OPENCLAW_APP_TOKEN || 'my-gateway-token' const PORT = 18789 // 1) Kill existing gateway processes if present await sandbox.commands.run( `bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do for pid in $(pgrep -f "$p" || true); do kill "$pid" >/dev/null 2>&1 || true; done; done'` ) await new Promise((r) => setTimeout(r, 1000)) // 2) Start gateway again await sandbox.commands.run( `openclaw gateway --allow-unconfigured --bind lan --auth token --token ${TOKEN} --port ${PORT}`, { background: true } ) // 3) Wait for listening socket for (let i = 0; i < 45; i++) { const probe = await sandbox.commands.run( `bash -lc 'ss -ltn | grep -q ":${PORT} " && echo ready || echo waiting'` ) if (probe.stdout.trim() === 'ready') break await new Promise((r) => setTimeout(r, 1000)) } ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os, time TOKEN = os.environ.get("OPENCLAW_APP_TOKEN", "my-gateway-token") PORT = 18789 # 1) Kill existing gateway processes if present sandbox.commands.run( """bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do for pid in $(pgrep -f "$p" || true); do kill "$pid" >/dev/null 2>&1 || true done done'""" ) time.sleep(1) # 2) Start gateway again sandbox.commands.run( f"openclaw gateway --allow-unconfigured --bind lan --auth token --token {TOKEN} --port {PORT}", background=True, ) # 3) Wait for listening socket for _ in range(45): probe = sandbox.commands.run( f'bash -lc \'ss -ltn | grep -q ":{PORT} " && echo ready || echo waiting\'' ) if probe.stdout.strip() == "ready": break time.sleep(1) ``` ## Turn insecure flags off (recommended after testing) Use this to restore secure device authentication after initial testing. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} const TOKEN = process.env.OPENCLAW_APP_TOKEN || 'my-gateway-token' const PORT = 18789 await sandbox.commands.run( `bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth false && ` + `openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth false'` ) await sandbox.commands.run( `bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do for pid in $(pgrep -f "$p" || true); do kill "$pid" >/dev/null 2>&1 || true; done; done'` ) await sandbox.commands.run( `openclaw gateway --allow-unconfigured --bind lan --auth token --token ${TOKEN} --port ${PORT}`, { background: true } ) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os TOKEN = os.environ.get("OPENCLAW_APP_TOKEN", "my-gateway-token") PORT = 18789 sandbox.commands.run( "bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth false && " "openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth false'" ) sandbox.commands.run( """bash -lc 'for p in "[o]penclaw gateway" "[o]penclaw-gateway"; do for pid in $(pgrep -f "$p" || true); do kill "$pid" >/dev/null 2>&1 || true done done'""" ) sandbox.commands.run( f"openclaw gateway --allow-unconfigured --bind lan --auth token --token {TOKEN} --port {PORT}", background=True, ) ``` ## Related Connect OpenClaw to Telegram and approve pairing # OpenClaw Telegram Source: https://e2b.mintlify.app/docs/agents/openclaw/openclaw-telegram Connect OpenClaw to Telegram in an E2B sandbox, approve pairing, and chat through your bot. OpenClaw supports Telegram as a chat channel. In E2B you can run OpenClaw in a sandbox, attach your bot token, and approve user pairing from the terminal. This guide covers the working flow we used: 1. Start OpenClaw in a sandbox. 2. Enable the Telegram plugin. 3. Add Telegram channel credentials. 4. Start the channel runtime in background. 5. Approve Telegram pairing. ## Prerequisites * A Telegram bot token from [@BotFather](https://t.me/BotFather). There's instructions to follow there, it runs /newbot for you and walks you through naming and creating your bot. * An OpenAI API key for the OpenClaw model. * E2B API key configured locally. ## Quick start ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const GATEWAY_PORT = 18789 const GATEWAY_TOKEN = process.env.OPENCLAW_APP_TOKEN || 'my-openclaw-token' const sandbox = await Sandbox.create('openclaw', { envs: { OPENAI_API_KEY: process.env.OPENAI_API_KEY, TELEGRAM_BOT_TOKEN: process.env.TELEGRAM_BOT_TOKEN, }, timeoutMs: 3600_000, }) await sandbox.commands.run('openclaw config set agents.defaults.model.primary openai/gpt-5.2') // Enable the Telegram plugin (required before adding the channel) await sandbox.commands.run('openclaw config set plugins.entries.telegram.enabled true') await sandbox.commands.run('openclaw channels add --channel telegram --token "$TELEGRAM_BOT_TOKEN"') await sandbox.commands.run( `bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth true && ` + `openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true && ` + `openclaw gateway --allow-unconfigured --bind lan --auth token --token ${GATEWAY_TOKEN} --port ${GATEWAY_PORT}'`, { background: true } ) for (let i = 0; i < 45; i++) { const probe = await sandbox.commands.run( `bash -lc 'ss -ltn | grep -q ":${GATEWAY_PORT} " && echo ready || echo waiting'` ) if (probe.stdout.trim() === 'ready') break await new Promise((r) => setTimeout(r, 1000)) } ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import time from e2b import Sandbox GATEWAY_PORT = 18789 GATEWAY_TOKEN = os.environ.get("OPENCLAW_APP_TOKEN", "my-openclaw-token") sandbox = Sandbox.create("openclaw", envs={ "OPENAI_API_KEY": os.environ["OPENAI_API_KEY"], "TELEGRAM_BOT_TOKEN": os.environ["TELEGRAM_BOT_TOKEN"], }, timeout=3600) sandbox.commands.run("openclaw config set agents.defaults.model.primary openai/gpt-5.2") # Enable the Telegram plugin (required before adding the channel) sandbox.commands.run("openclaw config set plugins.entries.telegram.enabled true") sandbox.commands.run('openclaw channels add --channel telegram --token "$TELEGRAM_BOT_TOKEN"') sandbox.commands.run( f"bash -lc 'openclaw config set gateway.controlUi.allowInsecureAuth true && " f"openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true && " f"openclaw gateway --allow-unconfigured --bind lan --auth token --token {GATEWAY_TOKEN} --port {GATEWAY_PORT}'", background=True, ) for _ in range(45): probe = sandbox.commands.run( f"bash -lc 'ss -ltn | grep -q \":{GATEWAY_PORT} \" && echo ready || echo waiting'" ) if probe.stdout.strip() == "ready": break time.sleep(1) ``` For Telegram setup, you do **not** need to open the gateway URL in a browser. The gateway process is used here as a long-running channel runtime. ## Pair your Telegram user 1. Open your bot in Telegram and send a message (for example: `hi`). 2. Telegram will return a pairing prompt similar to: ```text theme={"theme":{"light":"github-light","dark":"github-dark-default"}} OpenClaw: access not configured. Your Telegram user id: ... Pairing code: XXXXXXXX Ask the bot owner to approve with: openclaw pairing approve telegram XXXXXXXX ``` 3. Approve that pairing code via `sandbox.commands.run(...)`: ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} const PAIRING_CODE = 'XXXXXXXX' // from Telegram await sandbox.commands.run( `openclaw pairing approve --channel telegram ${PAIRING_CODE}` ) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} PAIRING_CODE = "XXXXXXXX" # from Telegram sandbox.commands.run( f"openclaw pairing approve --channel telegram {PAIRING_CODE}" ) ``` `openclaw pairing approve telegram ` also works if you prefer that form. ## Verify channel status ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} const channels = await sandbox.commands.run('openclaw channels list --json') const status = await sandbox.commands.run('openclaw channels status --json --probe') const pairing = await sandbox.commands.run('openclaw pairing list --json --channel telegram') console.log(JSON.parse(channels.stdout)) console.log(JSON.parse(status.stdout)) console.log(JSON.parse(pairing.stdout)) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import json channels = sandbox.commands.run("openclaw channels list --json") status = sandbox.commands.run("openclaw channels status --json --probe") pairing = sandbox.commands.run("openclaw pairing list --json --channel telegram") print(json.loads(channels.stdout)) print(json.loads(status.stdout)) print(json.loads(pairing.stdout)) ``` If you need logs from channel handlers: ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} const logs = await sandbox.commands.run( 'openclaw channels logs --channel telegram --lines 200' ) console.log(logs.stdout) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} logs = sandbox.commands.run( "openclaw channels logs --channel telegram --lines 200" ) print(logs.stdout) ``` ## Troubleshooting * `Unknown channel: telegram` * The Telegram plugin is not enabled. Run `openclaw config set plugins.entries.telegram.enabled true` before adding the channel. * `OpenClaw: access not configured` * Pairing has not been approved yet. Run `openclaw pairing approve ...`. * `No API key found for provider ...` * This guide uses `openai/gpt-5.2`. Set `OPENAI_API_KEY` in sandbox envs. * No pending pairing requests from `pairing list` * Send a fresh message to the bot first, then retry `pairing list --channel telegram`. ## Related Run OpenClaw's web gateway with token auth # OpenCode Source: https://e2b.mintlify.app/docs/agents/opencode Run OpenCode in a secure E2B sandbox with full filesystem, terminal, and git access. [OpenCode](https://opencode.ai) is an open-source coding agent that supports multiple LLM providers. E2B provides a pre-built `opencode` template with OpenCode already installed. ## CLI Create a sandbox with the [E2B CLI](/docs/cli). ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} e2b sbx create opencode ``` Once inside the sandbox, start OpenCode. ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} opencode ``` ## Run headless Use `opencode run` for non-interactive mode. Pass your LLM provider's API key as an environment variable — OpenCode supports `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, and [others](https://opencode.ai/docs/config/). ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('opencode', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, }) const result = await sandbox.commands.run( `opencode run "Create a hello world HTTP server in Go"` ) console.log(result.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("opencode", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }) result = sandbox.commands.run( 'opencode run "Create a hello world HTTP server in Go"', ) print(result.stdout) sandbox.kill() ``` ### Example: work on a cloned repository ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create('opencode', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, timeoutMs: 600_000, }) await sandbox.git.clone('https://github.com/your-org/your-repo.git', { path: '/home/user/repo', username: 'x-access-token', password: process.env.GITHUB_TOKEN, depth: 1, }) const result = await sandbox.commands.run( `cd /home/user/repo && opencode run "Add error handling to all API endpoints"`, { onStdout: (data) => process.stdout.write(data) } ) const diff = await sandbox.commands.run('cd /home/user/repo && git diff') console.log(diff.stdout) await sandbox.kill() ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os from e2b import Sandbox sandbox = Sandbox.create("opencode", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }, timeout=600) sandbox.git.clone("https://github.com/your-org/your-repo.git", path="/home/user/repo", username="x-access-token", password=os.environ["GITHUB_TOKEN"], depth=1, ) result = sandbox.commands.run( 'cd /home/user/repo && opencode run "Add error handling to all API endpoints"', on_stdout=lambda data: print(data, end=""), ) diff = sandbox.commands.run("cd /home/user/repo && git diff") print(diff.stdout) sandbox.kill() ``` ## Connect with the OpenCode SDK OpenCode includes a [headless HTTP server](https://opencode.ai/docs/server/) that you can control programmatically using the [`@opencode-ai/sdk`](https://opencode.ai/docs/sdk/) client. Start the server inside a sandbox, get the public URL with `sandbox.getHost()`, and connect from your application. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' import { createOpencodeClient } from '@opencode-ai/sdk' const sandbox = await Sandbox.create('opencode', { envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }, lifecycle: { onTimeout: 'pause', // "pause" | "kill" }, timeoutMs: 10 * 60 * 1000, }) // Start the OpenCode server sandbox.commands.run('opencode serve --hostname 0.0.0.0 --port 4096', { background: true, }) // Wait for the server to be ready const host = sandbox.getHost(4096) const baseUrl = `https://${host}` while (true) { try { await fetch(`${baseUrl}/global/health`) break } catch { await new Promise((r) => setTimeout(r, 500)) } } // Connect to the server const client = createOpencodeClient({ baseUrl, }) // Create a session and send a prompt const { data: session } = await client.session.create({ body: { title: 'E2B Session' }, }) const { data: result } = await client.session.prompt({ path: { id: session.id }, body: { parts: [{ type: 'text', text: 'Create a hello world HTTP server in Go' }], }, }) console.log(result) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import os import time import requests from e2b import Sandbox sandbox = Sandbox.beta_create("opencode", envs={ "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"], }, auto_pause=True, timeout=10 * 60) # Start the OpenCode server sandbox.commands.run( "opencode serve --hostname 0.0.0.0 --port 4096", background=True, ) # Wait for the server to be ready host = sandbox.get_host(4096) base_url = f"https://{host}" while True: try: requests.get(f"{base_url}/global/health") break except requests.ConnectionError: time.sleep(0.5) # Create a session and send a prompt via the HTTP API session = requests.post(f"{base_url}/session").json() result = requests.post( f"{base_url}/session/{session['id']}/message", json={ "parts": [{"type": "text", "text": "Create a hello world HTTP server in Go"}], }, ).json() print(result) ``` ## Build a custom template If you need to customize the environment (e.g. pre-install dependencies, add config files), build your own template on top of the pre-built `opencode` template. ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // template.ts import { Template, waitForPort } from 'e2b' export const template = Template() .fromTemplate('opencode') .setEnvs({ OPENCODE_SERVER_PASSWORD: 'your-password', }) // Optional - start the OpenCode server on sandbox start .setStartCmd( 'opencode serve --hostname 0.0.0.0 --port 4096', waitForPort(4096) ) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # template.py from e2b import Template, wait_for_port template = ( Template() .from_template("opencode") .set_envs({ "OPENCODE_SERVER_PASSWORD": "your-password", }) # Optional - start the OpenCode server on sandbox start .set_start_cmd( "opencode serve --hostname 0.0.0.0 --port 4096", wait_for_port(4096) ) ) ``` ```typescript JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} // build.ts import { Template, defaultBuildLogger } from 'e2b' import { template as openCodeTemplate } from './template' await Template.build(openCodeTemplate, 'my-opencode', { cpuCount: 2, memoryMB: 2048, onBuildLogs: defaultBuildLogger(), }) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} # build.py from e2b import Template, default_build_logger from template import template as opencode_template Template.build(opencode_template, "my-opencode", cpu_count=2, memory_mb=2048, on_build_logs=default_build_logger(), ) ``` Run the build script to create the template. ```bash JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} npx tsx build.ts ``` ```bash Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} python build.py ``` ## Related guides Auto-pause, resume, and manage sandbox lifecycle Clone repos, manage branches, and push changes Connect to the sandbox via SSH for interactive sessions # API key Source: https://e2b.mintlify.app/docs/api-key To use the API key, you can either: * **Set the API key as the `E2B_API_KEY` environment variable** to avoid passing it each time you create a sandbox. * Or pass it directly to the `Sandbox` constructor as shown below: ```js JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Sandbox } from 'e2b' const sandbox = await Sandbox.create({ apiKey: 'YOUR_API_KEY' }) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from e2b import Sandbox sbx = Sandbox.create(api_key="YOUR_API_KEY") ``` ## Where to find API key You can get your API key at [dashboard](https://e2b.dev/dashboard?tab=keys).
# Access token The access token is used only in the CLI and is **not needed in the SDK**. There's no need to set it when logging into the CLI using `e2b auth login`. To authenticate without the browser, you can set `E2B_ACCESS_TOKEN` as an environment variable. This is useful for CI/CD pipelines. ## Where to find access token You can get your **Access token key** at the [dashboard](https://e2b.dev/dashboard/account). # Billing & limits Source: https://e2b.mintlify.app/docs/billing E2B uses [usage-based pricing](#usage-based-pricing) - you pay only for what you use. New users receive \$100 in free credits to get started. [Manage billing in dashboard](https://e2b.dev/dashboard?tab=billing) ## Plans | Feature | Hobby | Pro | Enterprise | | -------------------------------------------- | ---------------- | ------------------------------ | ---------- | | **Base price** | \$0/month | \$150/month | Custom | | **Free credits** | \$100 (one-time) | \$100 (one-time) | Custom | | **Max vCPUs** | 8 | 8+ | Custom | | **Max memory** | 8 GB | 8+ GB | Custom | | **Disk size** | 10 GB | 20+ GB | Custom | | **Max session length** | 1 hour | 24 hours | Custom | | **Concurrent sandboxes** | 20 | 100 - 1,100 | 1,100+ | | **Concurrent builds** | 20 | 20 | Custom | | **Sandbox creation rate** | 1 / sec | 5 / sec | Custom | To upgrade your plan or purchase add-ons, visit the [dashboard billing tab](https://e2b.dev/dashboard?tab=billing). For Enterprise plans, [contact sales](mailto:enterprise@e2b.dev). *** ## Usage-based pricing You pay per second for compute resources while your sandbox is running. ### Compute costs Use the [usage cost calculator](https://e2b.dev/pricing#:~:text=Usage%20Cost%20Calculator) on our pricing page to estimate costs for your specific configuration. ### Customizing compute resources You can customize allocated CPU and RAM when building custom templates by specifying `cpuCount` and `memoryMB` in the build configuration. ```js JavaScript & TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-default"}} import { Template, defaultBuildLogger } from 'e2b' await Template.build(template, 'my-template', { cpuCount: 8, memoryMB: 4096, onBuildLogs: defaultBuildLogger(), }) ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-default"}} from e2b import Template, default_build_logger Template.build( template, 'my-template', cpu_count=8, memory_mb=4096, on_build_logs=default_build_logger(), ) ``` See [template quickstart](/docs/template/quickstart) for more details on building custom templates. Need higher CPU or RAM limits? Contact [support@e2b.dev](mailto:support@e2b.dev) for more information. *** ## Monitoring usage Check your usage and costs in the [dashboard usage tab](https://e2b.dev/dashboard?tab=usage). *** ## FAQ Automatically at the start of the month for the previous month's usage. Your account will be blocked. Add a payment method to continue using E2B. Yes, you can set spending limits on the [budget page](https://e2b.dev/dashboard?tab=budget) in your dashboard. * **Enable auto-pause** - Automatically pause sandboxes after a period of inactivity to stop billing while preserving state * **Pause sandboxes when idle** - Use `sbx.pause()` to stop billing while keeping state available for later * **Kill sandboxes you no longer need** - Use `sbx.kill()` to stop billing and release resources permanently * **Allocate only what you need** - Start with default resources (2 vCPU, 1 GB RAM) and increase only if necessary * **Monitor actively running sandboxes** - Use the [CLI](/docs/cli/list-sandboxes) or [dashboard](https://e2b.dev/dashboard?tab=usage) to track active sandboxes * **Use lifecycle events** - Set up [webhooks](/docs/sandbox/lifecycle-events-webhooks) to get notified when sandboxes are created No. You only pay while a sandbox is actively running. Once a sandbox is paused, killed or times out, billing stops immediately. # E2B CLI Source: https://e2b.mintlify.app/docs/cli E2B CLI is a command line tool that allows you to manage and interact with sandboxes and [templates](/docs/template/quickstart). ## Installation **Using Homebrew (on macOS)** ```bash Terminal theme={"theme":{"light":"github-light","dark":"github-dark-default"}} brew install e2b ``` **Using NPM** You can install E2B CLI using the following command: ```bash Terminal theme={"theme":{"light":"github-light","dark":"github-dark-default"}} npm i -g @e2b/cli ``` # Authentication in CLI Source: https://e2b.mintlify.app/docs/cli/auth There are two ways to authenticate with the E2B CLI: ## Option 1: browser authentication This option requires an interactive browser environment. Run the following command to sign in through your browser: ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} e2b auth login ``` This will open your default browser and prompt you to authenticate with your E2B account. ## Option 2: setup environment variables Set your environment variables: ```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}} export E2B_API_KEY=your_api_key_here export E2B_ACCESS_TOKEN=your_acces_token_here ``` Learn more about obtaining and managing your API key and access token on the [API Key page](/docs/api-key). # Connect to sandbox Source: https://e2b.mintlify.app/docs/cli/connect-to-sandbox You can connect an interactive terminal to an already running sandbox. ```bash Terminal theme={"theme":{"light":"github-light","dark":"github-dark-default"}} e2b sandbox connect ``` Unlike the `create` command, `connect` does not kill the sandbox when you disconnect. When you exit the terminal, only your terminal session is closed—the sandbox continues running. Once connected, you can inspect the sandbox filesystem and processes to debug or experiment, or use it as a dedicated environment for running agents instead of your local computer. # Create sandbox Source: https://e2b.mintlify.app/docs/cli/create-sandbox You can create a sandbox and connect an interactive terminal to it. ```bash Terminal theme={"theme":{"light":"github-light","dark":"github-dark-default"}} e2b sandbox create