Skip to main content

Documentation Index

Fetch the complete documentation index at: https://e2b.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Anthropic Managed Agents can use a self-hosted environment when you want to run tool calls in your own infrastructure. E2B provides a reusable E2B/claude-managed-agents-webhooks template that receives Anthropic webhooks and routes each Managed Agents session to a persistent E2B worker sandbox.
For the full source, local setup scripts, and app-owned routing examples, see the Anthropic Managed Agents cookbook.

Install dependencies

npm install e2b @anthropic-ai/sdk
Export the values you will pass to the webhook sandbox:
# E2B dashboard API keys: https://e2b.dev/dashboard?tab=keys
export E2B_API_KEY="..."

# Anthropic Console API keys: https://console.anthropic.com/settings/keys
export ANTHROPIC_API_KEY="..."

# Anthropic Console environments: https://platform.claude.com/workspaces/default/environments
export ANTHROPIC_ENVIRONMENT_ID="..."

# Open the self-hosted environment in the Anthropic Console and click Generate environment key.
export ANTHROPIC_ENVIRONMENT_KEY="..."

Start the webhook sandbox

Start the public template with auto-resume enabled. The template starts a webhook server on port 8000. Because Anthropic only shows the webhook signing key after you register an endpoint, write the router config now and add the signing key to the same sandbox after registration.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('E2B/claude-managed-agents-webhooks', {
  lifecycle: { onTimeout: 'pause', autoResume: true },
})

await sandbox.files.write([
  {
    path: '/opt/anthropic-managed-agents-js/config/e2b-api-key',
    data: `${process.env.E2B_API_KEY}\n`,
  },
  {
    path: '/opt/anthropic-managed-agents-js/config/anthropic-api-key',
    data: `${process.env.ANTHROPIC_API_KEY}\n`,
  },
  {
    path: '/opt/anthropic-managed-agents-js/config/anthropic-environment-id',
    data: `${process.env.ANTHROPIC_ENVIRONMENT_ID}\n`,
  },
  {
    path: '/opt/anthropic-managed-agents-js/config/anthropic-environment-key',
    data: `${process.env.ANTHROPIC_ENVIRONMENT_KEY}\n`,
  },
])

console.log(`Webhook URL: https://${sandbox.getHost(8000)}/webhook`)
At this point /health returns 200, but /webhook returns 503 until the signing key is configured. Keep this sandbox running or paused; registering a different sandbox URL means writing the signing key into that sandbox instead.

Register the webhook

In the Anthropic Console webhooks settings, create a webhook endpoint using the printed URL:
https://<sandbox-host>/webhook
Subscribe it to:
session.status_run_started
Save the generated signing key, export it locally, then write it into the same webhook sandbox.
export ANTHROPIC_WEBHOOK_SIGNING_KEY="whsec_..."
await sandbox.files.write(
  '/opt/anthropic-managed-agents-js/config/anthropic-webhook-signing-key',
  `${process.env.ANTHROPIC_WEBHOOK_SIGNING_KEY}\n`,
)

Send work to the agent

Create or select a Managed Agents agent in the Anthropic Console, then create a session with that agent and the same ANTHROPIC_ENVIRONMENT_ID you wrote into the webhook sandbox. Creating the session does not start work; the user.message event does.
export ANTHROPIC_AGENT_ID="agent_..."
Use a small sandbox task for the first smoke test:
Use bash to echo webhook-smoke-ok. Answer only with that text.
import Anthropic from '@anthropic-ai/sdk'

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
})

const session = await client.beta.sessions.create({
  agent: process.env.ANTHROPIC_AGENT_ID!,
  environment_id: process.env.ANTHROPIC_ENVIRONMENT_ID!,
  title: 'E2B webhook smoke',
})

await client.beta.sessions.events.send(session.id, {
  events: [
    {
      type: 'user.message',
      content: [
        {
          type: 'text',
          text: 'Use bash to echo webhook-smoke-ok. Answer only with that text.',
        },
      ],
    },
  ],
})

console.log(`Session ID: ${session.id}`)
Then check the webhook sandbox:
const health = await fetch(`https://${sandbox.getHost(8000)}/health`)
console.log(await health.json())

const logs = await sandbox.commands.run(
  'tail -200 /opt/anthropic-managed-agents-js/webhook.log || true',
)
console.log(logs.stdout)

const assignments = await sandbox.commands.run(
  'cat /opt/anthropic-managed-agents-js/.managed-agent-sandbox-store.json || true',
)
console.log(assignments.stdout)
A healthy run has:
  • /health returning ok: true.
  • Router logs showing routing work and assigned session.
  • A session-to-sandbox assignment in the router’s assignment store.
  • The assigned worker sandbox’s worker.log showing claimed work, tool execution, and successful results posted back to Anthropic.
  • The Anthropic session returning to session.status_idle.
The assignment store records the worker sandbox ID for each routed session. Connect to that sandbox and check /opt/anthropic-managed-agents-js/worker.log when you need the tool execution logs. If the session stays at requires_action, check /opt/anthropic-managed-agents-js/webhook.log in the router sandbox first, then check /opt/anthropic-managed-agents-js/worker.log in the assigned worker sandbox. Stale environment keys, missing signing keys, archived sessions, and failed tool-result posts show up there.

Runtime behavior

The worker runs with /mnt/session as its workdir. File tools are constrained to that workdir, skills are downloaded under /mnt/session/skills/<name>/, and generated artifacts should be written under /mnt/session/outputs. The webhook sandbox is the router. It keeps a session-to-sandbox assignment store and starts worker sandboxes with E2B auto-resume and pause-on-timeout settings.

Session-scoped sandboxes

By default, the public webhook template gives each Managed Agents session its own E2B worker sandbox. Follow-up turns for the same session reconnect to the same worker and reuse its /mnt/session filesystem. Use cloud buckets, Archil, or volumes when files need to outlive a sandbox or be shared across many sandboxes. If you want to run that router in your own service instead of in E2B, use the cookbook’s app-webhooks/ example. It receives Anthropic webhooks in your app, claims work there, and routes each session to its own E2B sandbox by default.

Clean up

Remove the webhook endpoint in the Anthropic Console before deleting the router sandbox. Then kill the router sandbox and any assigned worker sandboxes you no longer need.

Cookbook example

Full JavaScript and Python examples for polling workers, sandbox-hosted webhooks, and app-owned routing.

Sandbox persistence

Pause and resume sandboxes to preserve filesystem state between runs.

Cloud buckets

Store generated files outside the sandbox filesystem.