SandboxAPI — Code Execution API for AI Agents

8 languages. gVisor isolation. Stateful sessions with file and package persistence. Opt-in managed public HTTPS for paid API plans. Streaming, async polling, and MCP-native tools.

Current API version: 4.0.0 · Base URL via RapidAPI: https://sandboxapi.p.rapidapi.com

Quick Start #

Direct API access

When direct accounts are enabled, sign in and create an API key in your dashboard. Save it as SANDBOXAPI_KEY in your server environment and call:

curl --fail-with-body https://api.sandboxapi.dev/v1/execute \
  -H "Authorization: Bearer $SANDBOXAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"language":"python3","code":"print(2 + 2)"}'

Keep the key in your server or secret manager. Never embed it in browser code. Direct keys and RapidAPI keys are separate credentials with separate subscriptions and allowances. Direct workspace usage includes authenticated playground runs. Basic resets at the start of each UTC month; paid direct allowances reset on the verified billing period. One accepted request costs one unit, including a batch; code failures count, confirmed infrastructure failures do not. Direct access stops at the allowance without automatic overage billing.

The examples and marketplace pricing below use the RapidAPI distribution channel. Direct clients use the same execution endpoints with the direct origin and Bearer header above. Hosted MCP currently uses RapidAPI credentials.

Synchronous execution #

curl -X POST https://sandboxapi.p.rapidapi.com/v1/execute \
  -H "Content-Type: application/json" \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -H "X-RapidAPI-Host: sandboxapi.p.rapidapi.com" \
  -d '{"language":"python3","code":"print(\"Hello, World!\")"}'

Response:

{
  "id": "exec_abc123",
  "status": "completed",
  "language": "python3",
  "stdout": "Hello, World!\n",
  "stderr": "",
  "exit_code": 0,
  "execution_time_ms": 42,
  "memory_used_kb": 8192,
  "timeout": 10,
  "created_at": "2026-06-25T10:00:00Z"
}

Stateful session 3.2.0 #

Sessions hold a sandbox open between calls. Files and installed packages persist for the session's idle TTL (max 30 minutes). Each call still runs in a fresh interpreter, so keep durable state on disk.

# 1. Create a session
curl -X POST https://sandboxapi.p.rapidapi.com/v1/sessions \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -d '{"language":"python3","idle_ttl":300}'
# → {"id":"sess_abc","language":"python3","expires_at":"..."}

# 2. Execute — writes durable state to the session filesystem
curl -X POST https://sandboxapi.p.rapidapi.com/v1/sessions/sess_abc/execute \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -d '{"code":"from pathlib import Path\nPath(\"state.txt\").write_text(\"42\")"}'

# 3. Execute again — the file is still there
curl -X POST https://sandboxapi.p.rapidapi.com/v1/sessions/sess_abc/execute \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -d '{"code":"from pathlib import Path\nprint(int(Path(\"state.txt\").read_text()) * 2)"}'
# → stdout: "84\n"

Package installation in a session 3.3.0 #

curl -X POST https://sandboxapi.p.rapidapi.com/v1/sessions/sess_abc/install \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -d '{"manager":"pip","packages":["pandas","numpy"]}'

Supported stable managers for current public runtimes are pip for Python and npm for JavaScript/TypeScript. They install only the artifacts explicitly listed in packages from a curated cache behind the managed install proxy. pip accepts cached wheels only with --only-binary=:all: --no-deps --no-build-isolation; source distributions are rejected. npm uses npm pack --ignore-scripts, validates and extracts the direct tarball, and removes dependency and lifecycle-script metadata. Transitive dependencies are not resolved yet, so list every required package explicitly. The deprecated options.no_deps field is forced true; setting it to false does not enable dependencies.

Streaming output 3.1.0 #

curl -N -X POST https://sandboxapi.p.rapidapi.com/v1/execute/stream \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -d '{"language":"python3","code":"for i in range(5):\n  print(i); import time; time.sleep(1)"}'
# → SSE events: stdout, stdout, ..., result

Events use the standard SSE format. The terminal event has event: result with a JSON payload that includes exit_code, execution_time_ms, and memory_used_kb.

Async polling 3.1.0 #

curl -X POST "https://sandboxapi.p.rapidapi.com/v1/execute?async=true" \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -d '{"language":"python3","code":"..."}'
# → {"job_id":"job_xyz","status":"queued","poll_url":"/v1/executions/job_xyz"}

curl https://sandboxapi.p.rapidapi.com/v1/executions/job_xyz \
  -H "X-RapidAPI-Key: YOUR_API_KEY"
# Terminal responses include either result or error fields.

Production async is enabled. Ultra may request up to 300 seconds and Mega up to 600 seconds. If the queue is temporarily unavailable, an explicit async request returns HTTP 503 and never falls back to sync.

Side-effect safety: async jobs use at-least-once crash recovery. For non-idempotent HTTPS calls, send the destination API's idempotency key or use synchronous execution; a crash after a remote side effect but before result persistence can retry the job.

Supported Languages #

LanguageVersionID
Python3.12python3
JavaScriptNode 22javascript
TypeScript5.6.3 (esbuild + Node 22)typescript
Go1.22go
Java21java
C++GCC 12 / C++17cpp
CGCC 12 / GNU C17c
Bash5.2bash

TypeScript source is transpiled and bundled by esbuild 0.24 before Node 22 executes it. The API does not run a separate full tsc type-checking pass. C++ compiles with -std=c++17; C compiles with -std=gnu17.

Request Parameters #

FieldTypeRequiredDefaultDescription
languagestringYes—Language ID
codestringYes—Source code (max 1MB)
timeoutintegerNoBy languagePython/JavaScript/Bash 10s; TypeScript/C/C++ 15s; Java 20s; Go 60s, then clamped to the tier, global, and response-held ceiling. Use GET /v1/languages for supported IDs.
stdinstringNo""Standard input
networkobjectNoOffControlled public HTTPS settings; paid plans opt in with {"enabled":true}

The complete HTTP request body is capped at 2 MiB, including JSON encoding overhead. The 1 MiB limits for code and stdin are field limits inside that shared envelope. For batch requests, every item must fit in the same 2 MiB body. Each batch result caps stdout at 16 KiB and stderr at 16 KiB and sets truncated: true when either stream exceeds its cap; single and session execution keep their 1 MiB-per-stream output caps.

Controlled public HTTPS egress #

Outbound network is off by default. Basic requests and the browser playground are denied network access. Pro, Ultra, and Mega API clients can opt in to managed public HTTPS on single, streaming, or async execution, or when creating a session. Batch execution stays networkless: a batch containing network.enabled=true is rejected with BATCH_NETWORK_UNSUPPORTED, so each outbound budget maps to one RapidAPI request.

This is explicit proxy-based egress, not transparent internet access. Your HTTP client or library must honor the injected HTTPS_PROXY environment variable or be explicitly configured to use it. Clients that bypass proxy settings—including some Node built-in fetch and Java configurations—do not automatically work. Raw public sockets and direct public routes are unavailable.

{
  "language": "python3",
  "code": "from urllib.request import urlopen; print(urlopen('https://api.github.com/rate_limit').status)",
  "network": {
    "enabled": true
  }
}

Pro may enable managed public HTTPS but cannot submit allowed_domains. Ultra and Mega may optionally provide up to 32 exact hostnames or explicit leading-wildcard rules such as *.example.com. On Ultra or Mega, an omitted or empty allowed_domains list means all public HTTPS destinations remain eligible; the proxy safety rules still apply.

"network": {
  "enabled": true,
  "allowed_domains": ["api.github.com", "*.githubusercontent.com"]
}

For an Ultra or Mega session with fixed domain controls, put the same object on POST /v1/sessions:

Network-enabled session calls run in short-lived gVisor workers sharing the session's files. The persistent container stays networkless. Files persist between calls, but leftover child processes from a network-enabled call are stopped before its response; background services and process memory do not persist.

{
  "language": "python3",
  "idle_ttl": 300,
  "network": {
    "enabled": true,
    "allowed_domains": ["api.example.com"]
  }
}

The session policy is fixed at creation; it cannot be broadened by a later execute request. Current plan eligibility is rechecked on each call, so a downgrade requires a new session. Signed proxy credentials are refreshed for each session execute.

The proxy validates the CONNECT hostname, pinned public DNS answer, and outer TLS ClientHello SNI, then relays opaque TLS. It does not inspect encrypted HTTP hosts, paths, or payloads. Use domain rules as outbound routing controls, not as a content-level data-loss-prevention boundary.

Availability boundary: customer-facing audit logs and a static egress IP are planned and deployment-dependent. Structured operator egress logs are already part of the managed proxy controls.

Response Fields #

FieldTypeDescription
idstringExecution ID
statusstringcompleted / error / timeout
languagestringNormalized language ID used for execution
stdoutstringStandard output (max 1MB, may be truncated)
stderrstringStandard error (max 1MB)
exit_codeintegerProcess exit code
execution_time_msintegerCPU time
memory_used_kbintegerPeak memory
timeoutintegerEffective timeout in seconds
created_atstringExecution timestamp
truncatedboolPresent when output was truncated

Error Handling #

SandboxAPI distinguishes between API errors (HTTP 4xx/5xx) and execution errors (HTTP 200 with a status field). Treat any HTTP 200 response as a successful API call — the status tells you whether the user's code ran cleanly.

HTTPMeaningWhat to do
200Execution returned a resultInspect status
400Bad request (missing language, oversize body, etc.)Fix the payload
401Missing/invalid API keyCheck your RapidAPI subscription
403NETWORK_ACCESS_FORBIDDEN or NETWORK_DOMAIN_CONTROLS_FORBIDDENDisable network, remove custom domains, or upgrade the plan
408Execution or queue timeoutRaise timeout within your plan limit or use async polling
413Payload too largeTrim code or stdin
429Rate limit exceededBack off or upgrade tier
500 / 503Internal errorRetry with exponential backoff; report if persistent

Pricing & Rate Limits #

PlanPriceRequests / subscription periodSync/streamAsyncBatchRateSessionsPackagesNetwork
Basic$0/mo50030s30s1015/min——Off
Pro (recommended)$19/mo10,00060s60s5030/min2 concurrentcurated package cacheOpt-in managed HTTPS
Ultra$49/mo50,000150s300s10060/min5 concurrentcurated package cacheOpt-in + domain rules
Mega$149/mo200,000150s600s20060/min8 concurrent · 30m idlecurated cache · 300 installs/account/hourOpt-in + domain rules

All plans include gVisor isolation, 8 languages, stdin, batch execution, streaming output, production async polling, and the playground. Sessions and stable direct-artifact pip/npm installation from the curated popular-package cache are available on paid plans. Pro allows 2 concurrent sessions per RapidAPI account, Ultra allows 5, and Mega allows 8. Response-held sync/stream and sessions cap at 60s on Pro and 150s on Ultra/Mega; only production async exposes Ultra 300s and Mega 600s. Mega also includes 200,000 requests per RapidAPI subscription period, up to 200 accepted items per batch, a 30-minute idle maximum, and 300 installs per subscriber identity/hour. See pricing for the full comparison.

Gateway and batch capacity: RapidAPI holds a request for at most 180 seconds. SandboxAPI stops response-held work at 150 seconds, preserving 30 seconds for delivery and cleanup. Plan batch values are maximum accepted item counts, not parallelism guarantees; items run through bounded workers within that 150-second request wall-clock budget.

Session capacity: Session caps are per-RapidAPI-account ceilings. Shared service capacity is not reserved; during saturation, session creation may return HTTP 503 with Retry-After.

Request billing: One call to any endpoint counts as one RapidAPI request. A batch call is one request regardless of the number of items; each session endpoint call is a separate request. Starting an async job is one request, and every later polling call is another request.

Allowance ownership: RapidAPI owns and resets included requests on the marketplace subscription period. SandboxAPI separately enforces only the listed per-minute burst limit; it has no duplicate calendar-month counter.

Bandwidth billing: RapidAPI measures bandwidth in 1 MB units, with 10,240 MB/month currently included on every plan, then charges $0.001 per MB above that allowance. This platform fee is separate from the subscription-period request allowance and the proxy's per-execution transfer safety cap.

Network is explicit: Basic and playground traffic cannot enable it. Paid API clients must opt in per execute item or when a session is created; Ultra and Mega may add domain rules.

Security #

Every execution runs inside an OCI container backed by gVisor. The production configuration requires runsc, which mediates application syscalls through a user-space kernel and adds an isolation boundary beyond the container runtime. This is combined with strict resource limits, network off by default, no persistent storage for synchronous execution, and per-request cleanup.

Opted-in paid workloads use managed public HTTPS only: destination validation, DNS pinning, SNI enforcement, signed short-lived credentials, connection and transfer ceilings, structured operator logging, and public-address-only routing.

MCP Server #

The hosted Streamable HTTP adapter at https://mcp.sandboxapi.dev/mcp exposes four stateless tools: execute_code, execute_batch, list_languages, and get_capabilities. Each invocation is forwarded through RapidAPI using the caller's subscription key. Sessions, package install, managed HTTPS, streaming, and async are REST-only.

Claude Code, Codex, Cursor, VS Code, and Antigravity support remote MCP with Bearer authentication. Use the client setup guide for each client's configuration format. For VS Code, add this to .vscode/mcp.json to use a prompted secret:

{
  "inputs": [{
    "type": "promptString",
    "id": "sandboxapi-key",
    "description": "SandboxAPI RapidAPI key",
    "password": true
  }],
  "servers": {
    "sandboxapi": {
      "type": "http",
      "url": "https://mcp.sandboxapi.dev/mcp",
      "headers": { "Authorization": "Bearer ${input:sandboxapi-key}" }
    }
  }
}

Claude Desktop's remote connector UI also supports request headers for organizations with access to Anthropic's limited beta. SandboxAPI OAuth onboarding is planned. Keep keys in environment variables, secret stores, or personal configuration; never place a RapidAPI key in the endpoint URL.

Full integration guide on the MCP page.

Code Examples #

Python (requests)

import requests

resp = requests.post(
    "https://sandboxapi.p.rapidapi.com/v1/execute",
    headers={
        "X-RapidAPI-Key": "YOUR_API_KEY",
        "X-RapidAPI-Host": "sandboxapi.p.rapidapi.com",
    },
    json={"language": "python3", "code": "print(2 + 2)"},
)
data = resp.json()
print(data["stdout"])  # → "4\n"

JavaScript (fetch)

const resp = await fetch("https://sandboxapi.p.rapidapi.com/v1/execute", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-RapidAPI-Key": "YOUR_API_KEY",
    "X-RapidAPI-Host": "sandboxapi.p.rapidapi.com",
  },
  body: JSON.stringify({ language: "javascript", code: "console.log(2 + 2)" }),
});
const data = await resp.json();
console.log(data.stdout); // → "4\n"

Go

req, _ := http.NewRequest("POST", "https://sandboxapi.p.rapidapi.com/v1/execute",
  strings.NewReader(`{"language":"go","code":"package main\nimport \"fmt\"\nfunc main(){fmt.Println(2+2)}"}`))
req.Header.Set("X-RapidAPI-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
Try it live: open the playground to run any of these snippets in any of the 8 supported languages without writing a client.

Changelog #

VersionHighlights
4.0.0Four RapidAPI plans; 150s response-held cap under RapidAPI's 180s gateway; Ultra 300s and Mega 600s async-only; 2/5/8 session ceilings; up to 200 accepted Mega batch items within a 150s wall; request and bandwidth billing clarity; and opt-in controlled public HTTPS for paid API plans
3.3.0Package installation in sessions with cached package mirrors and supply-chain checks
3.2.0Stateful sessions with persistent files and installed packages
3.1.0SSE streaming output and async execution with polling
2.0.0Ultra tier (50K exec/mo), gVisor isolation, batch up to 100, 300s timeout, playground
1.2.0Pre-warmed sandbox pools, faster cold starts (historical measurement), memory reporting
1.1.0Batch execution endpoint (/execute/batch)
1.0.0Stable release — Pro tier, rate limit headers, /health endpoint, full error codes
0.3.0All 8 languages, stdin support, /languages endpoint
0.2.0Added TypeScript, Go, Bash
0.1.0Alpha — Python and JavaScript

Read the full release-by-release changelog →