Quickstart
Create an organization, mint a key, run code in a tier 1 sandbox, then escalate to a tier 2 shell session.
Goal: go from zero to a running agent action in about five minutes, then see the usage event it produced.
The endpoints and payloads below are the agreed v1 contract. They are the specification the
implementation is being built against, not a record of shipped behaviour. The authoritative machine
copy is openapi/workspaces-build.yaml in this repository.
Before you start
You need an organization and a secret key. Create both in the console at
https://console.workspaces.build, or ask an org admin for a key scoped to the project you are
working in.
Keys look like wb_sk_live_… (secret, server-side only) and wb_pk_live_… (publishable, safe in a
browser, can only mint scoped end-user tokens). Never ship a secret key to a client.
export WB_API_KEY="wb_sk_live_…" export WB_BASE_URL="https://api.workspaces.build/v1"
Check the key works
curl -sS "$WB_BASE_URL/whoami" \ -H "Authorization: Bearer $WB_API_KEY"
{ "organization": { "id": "org_2kQ9xw", "name": "Acme AI" }, "project": { "id": "proj_7fTn21", "name": "production" }, "scopes": ["sessions:write", "runs:write", "usage:read"], "region_default": "bom1" }Run code without managing a session
For a one-shot tier 1 evaluation,
POST /runscreates the sandbox, executes, returns the result and releases the sandbox in a single call. You never see a session ID.curl -sS "$WB_BASE_URL/runs" \ -H "Authorization: Bearer $WB_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "tier": 1, "runtime": "python3.12", "code": "import platform, json\nprint(json.dumps({\"py\": platform.python_version()}))", "timeout_ms": 10000 }'{ "id": "run_8Hc2Vd", "tier": 1, "status": "succeeded", "exit_code": 0, "stdout": "{\"py\": \"3.12.7\"}\n", "stderr": "", "started_at": "2026-10-06T09:14:22.118Z", "finished_at": "2026-10-06T09:14:22.421Z", "duration_ms": 303, "usage": { "cpu_ms": 288, "mem_gib_ms": 36864, "session_ms": 303, "egress_bytes": 0, "cold_start": false } }Keep state between calls with a session
When the agent needs a filesystem that survives across calls, create a session and exec against it. This example uses tier 2 because it needs a shell.
SESSION=$(curl -sS "$WB_BASE_URL/sessions" \ -H "Authorization: Bearer $WB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "tier": 2, "template": "tpl_base_ubuntu_24_04", "resources": { "vcpu": 2, "memory_mib": 4096 }, "idle_timeout_s": 300, "max_lifetime_s": 3600, "end_user_id": "eu_customer_4821" }' | jq -r .id) curl -sS "$WB_BASE_URL/sessions/$SESSION/exec" \ -H "Authorization: Bearer $WB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "command": ["bash", "-lc", "git clone --depth 1 https://github.com/astro/astro && ls astro | head"] }'The session is now
runningand holds a workspace at/workspace. Subsequentexeccalls see the same filesystem. It shuts down 300 seconds after the last call, or at 3600 seconds total, whichever comes first.Release it explicitly
Do not rely on the idle timeout in production — you pay for every second until it fires.
curl -sS -X DELETE "$WB_BASE_URL/sessions/$SESSION" \ -H "Authorization: Bearer $WB_API_KEY"
To keep the filesystem for later, snapshot before deleting:
curl -sS "$WB_BASE_URL/sessions/$SESSION/snapshot" \ -H "Authorization: Bearer $WB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "after-clone" }'See what it cost
curl -sS "$WB_BASE_URL/usage?group_by=meter&period=today" \ -H "Authorization: Bearer $WB_API_KEY"
{ "period": { "start": "2026-10-06T00:00:00Z", "end": "2026-10-06T09:20:00Z" }, "currency": "USD", "groups": [ { "meter": "tier2.session_s", "quantity": 47, "amount": 0.0094 }, { "meter": "cpu_ms", "quantity": 38210, "amount": 0.0019 }, { "meter": "egress_gb", "quantity": 0.031, "amount": 0.0031 } ], "total": 0.0144 }Usage is readable within about 60 seconds of the event. See metering model for the exact aggregation windows.
Where to go next
- Running untrusted code from a model? Read isolation model before you pick a tier.
- Need the agent to reach the public internet? Egress is default-deny. See networking and egress.
- Reselling to your own customers? Tag every session with
end_user_idfrom day one — it cannot be backfilled. See end-user billing. - Building a long-running agent? Read session lifecycle for the pause, snapshot and restore patterns.