Sandbox API

Get started

Your first Sandbox request, from credential to downloaded artifacts.

You need two things: the gateway hostname for your environment, and a credential. If you do not have a credential yet, whoever operates your Sandbox deployment issues one — see Provisioning credentials.

export SANDBOX_GATEWAY_URL="https://sandbox.turing.com"   # your environment's host
export SANDBOX_API_KEY="…"                                # or a team token

Running the platform yourself instead? Local development covers the compose stack, then the requests below work unchanged against http://localhost:8780.

1. Check your credential works

curl -sS -H "X-Api-Key: $SANDBOX_API_KEY" \
  "$SANDBOX_GATEWAY_URL/sandbox/v1/catalog?kind=agent"

You should get the list of agents you can run. A 401 means the credential was not recognised; nothing on /sandbox/* serves data anonymously.

Using a team token instead of an API key, send it as a bearer token:

curl -sS -H "Authorization: Bearer $TEAM_TOKEN" \
  "$SANDBOX_GATEWAY_URL/sandbox/v1/catalog?kind=agent"

2. Run something

The shortest useful request is a code execution — no agent, no model key, no task archive.

curl -sS -H "X-Api-Key: $SANDBOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"language":"python3.12","files":{"main.py":"print(sum(range(10)))"}}' \
  "$SANDBOX_GATEWAY_URL/sandbox/codeedit/v1/executions"
from sandbox_core.clients.sandbox_client import SandboxClient

client = SandboxClient.from_env()   # reads SANDBOX_GATEWAY_URL and SANDBOX_API_KEY
print(
    client.run_code_execution(
        {"language": "python3.12", "files": {"main.py": "print(sum(range(10)))"}}
    )
)

It answers on the same response — no job to poll:

{"status":"ok","exit_code":0,"stdout":"45","stderr":"","duration_ms":5427,"truncated":false}

files is keyed by path, and one path must be the language's entrypoint (main.py for python3.12). Language ids are versioned — get the list from GET /sandbox/codeedit/v1/languages.

3. Submit a job and poll it

Real work is asynchronous: you get a job_id back and poll it. Send a x-correlation-id you choose, so you can find this run in logs later.

JOB=$(curl -sS -H "X-Api-Key: $SANDBOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-correlation-id: my-first-run" \
  -d '{"agent_id":"opencode","instruction":"list the files","model":"anthropic/claude-sonnet-4-5"}' \
  "$SANDBOX_GATEWAY_URL/sandbox/agent/v1/runs" | jq -r .job_id)

curl -sS -H "X-Api-Key: $SANDBOX_API_KEY" \
  "$SANDBOX_GATEWAY_URL/sandbox/agent/v1/runs/$JOB"

Poll until status is succeeded, failed or cancelled. To watch it live instead, follow the event stream:

curl -N -H "X-Api-Key: $SANDBOX_API_KEY" \
  "$SANDBOX_GATEWAY_URL/sandbox/agent/v1/runs/$JOB/events"

An agent that calls a model needs a provider key, which the platform leases for your tenant — you never send one. If none is provisioned the run proceeds and the agent fails on its own terms; see Provisioning credentials.

4. Run a benchmark task

This is the main event, and it needs one thing from you: a task archive hosted somewhere the platform can fetch over HTTPS.

curl -sS -H "X-Api-Key: $SANDBOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-correlation-id: my-first-benchmark" \
  -d '{
    "task_slug": "my-task",
    "metadata": {"task_archive_url": "https://storage.example/tasks/my-task.zip"},
    "agents": [{"name": "a", "harbor_agent": "oracle"}]
  }' \
  "$SANDBOX_GATEWAY_URL/sandbox/harbor/v2/jobs/execute-tasks"

task_archive_url goes inside metadata. At the top level it is ignored and the request fails with metadata.task_archive_url is required.

Then poll GET /sandbox/harbor/v2/jobs/{job_id} and, when it is terminal, read outcome.valid_for_scoring before you trust any reward.

Full walkthrough, including the archive rules and how to read the result: Run a benchmark.

Next