Skip to main content
The OpenAI Agents API (preview) runs the agent in OpenAI’s cloud and keeps its session state. With a self-hosted environment, the agent’s shell commands and file edits run in an E2B sandbox. OpenAI supports two ways to provision that sandbox:
  • Application-managed: your application calls the E2B SDK to start, connect, and stop the sandbox. The Agents API Workbench in the E2B cookbook is built this way.
  • Webhook-managed: a controller deployed in your E2B account reacts to OpenAI webhooks and creates a dedicated worker sandbox for each session. Your application only talks to the Agents API and never imports the E2B SDK. The E2B webhook-managed example is the E2B variant of the handler OpenAI ships.
Try the application-managed Agents API Workbench first. Create the sandbox and connect to its terminal with the E2B CLI:
When the workbench is ready, the terminal prints a single-use link to its UI. Enter your OpenAI and E2B keys there and start a chat; each chat gets its own Agents API session and its own worker sandbox. The rest of this page is the quick start for the webhook-managed flow.
The Agents API is in preview. Your OpenAI project needs Agents API access, and the agent_api_sdk Python package installs from the preview repository rather than PyPI.Looking for the open-source agent framework instead? See OpenAI Agents SDK.

Prerequisites

  • an E2B API key
  • an OpenAI project with Agents API access
  • an OpenAI application key with Responses → Write, used to create sessions
  • a restricted OpenAI executor key with only List models → Read, created in the same organization, project, and user or service account as the application key
  • uv; every script declares its dependencies inline
The executor key is the only credential that enters a worker sandbox, as CODEX_API_KEY. Agent-generated code can read it, so keep the application key out of workers entirely.

Webhook-managed: set up the controller

Run everything from the webhook-managed example directory. .env is gitignored and holds the five values below.
1

Create an agent: once, prints the agent ID

The controller only manages sessions of this one agent. Put the printed ID in .env as OPENAI_AGENT_ID.
2

Build the worker template: once per Codex version, ~3 min

Workers boot from openai-agents-api-python-sdk-webhook-managed with codex exec-server baked in, so a session’s first turn does not pay for an npm install. Rebuild only after bumping CODEX_VERSION in build_template.py.
3

Start the controller: ~1 min, prints the webhook URL

Leave OPENAI_WEBHOOK_SECRET empty the first time.
The controller ID is saved to the gitignored .controller.json. Rerunning deploy.py reuses that sandbox, extends its one-hour timeout, and restarts the handler with the current .env. If that sandbox is gone, it creates a new one and prints the new webhook URL.uv run --env-file does not override variables already exported in your shell. If E2B_API_KEY is exported there, that key wins over .env.
4

Register the webhook: OpenAI platform, paste the URL

In Project settings → Webhooks of the project that owns OPENAI_API_KEY, add the URL and subscribe to agent.session.action_required and agent.session.failed. Put the generated signing secret in .env and redeploy to the same controller:
A webhook in another project of the same organization is never delivered. E2B’s own sandbox lifecycle webhooks are unrelated to this step.
5

Health check: no side effects

Webhook-managed: run a session

1

New session: one OpenAI session + one E2B worker, ~40 s

The first line printed is {"session_id": "sess_..."}. Keep it.
Behind the ~40 s: the client posts input, OpenAI sends agent.session.action_required to the controller, the controller creates the worker and launches codex exec-server inside it, the executor connects out to OpenAI, and the turn runs in /workspace.
2

Follow-up: same worker, starts immediately

SESSION_ID is the first line printed by the previous step.
3

Cleanup: no deletion webhook, release both sides

Deleting a session does not stop its sandbox.
4

New controller: ~1 min, prints a new webhook URL

After the controller’s one-hour timeout expires, rerun the deploy. It sees the old sandbox is gone, starts a fresh one, and prints a new URL. Paste it into the existing OpenAI webhook. The signing secret does not change.

Lifecycle

Workers stay running between turns and have a 30-minute timeout, refreshed on every reconnect. Pause a worker with e2b sandbox pause <id> and the next input resumes it with files intact. A killed worker is replaced by a fresh sandbox without the previous files. When a session fails, the controller pauses its worker instead of killing it, so you can inspect the sandbox afterwards. Kill it when done. OpenAI traffic cannot wake a paused or expired controller. Rerun deploy.py before the hour is up to extend it, or start a new controller as above. Remove the OpenAI webhook before killing the controller for good.

Application-managed: Agents API Workbench

If you want the agent’s events in your own process, for a live UI or for function tools, your application creates the worker and starts the executor itself. The Agents API Workbench behind the openai-agents-api-python-sdk template does exactly that: a Flask backend that runs one executor sandbox per chat, and a React frontend with a streaming transcript and a live /workspace file viewer.

Troubleshooting

The webhook points at a dead or wrong controller. Confirm the URL in OpenAI matches the controller printed by the last deploy.py, that it is registered in the project that owns the application key, and that OPENAI_AGENT_ID matches the agent the session was created for.
OPENAI_WEBHOOK_SECRET is empty in the controller. Put the signing secret in .env and run deploy.py again.
Input within about three minutes of killing or pausing a worker arrives before OpenAI notices the executor is offline, so no reconnect webhook fires and the turn runs without a shell. The session may keep declining to use the shell afterwards. Wait, or start a new session.
The controller writes JSON lines for enqueued, started, and paused to /app/controller.log. Each worker writes the executor output to /tmp/codex-executor.log. Find them by metadata: agents-webhook-controller=e2b for the controller and agents-session-id=<session> for workers.