Managing and accessing the workspace
Every workspace serves one HTTP API. The web console, the zbox CLI and zbox mcp are all clients of that API. You authorize them in one of two ways: through your Zerops login, or with the workspace API key.
| Interface | Use it for | Signed in with |
|---|---|---|
| Web console | Working with sandboxes in the browser | Your Zerops login (from the Zerops GUI or the CLI), or the API key |
| HTTP API | Your own code, services and CI | The API key |
| zbox CLI | Your terminal, scripts and agents | Your Zerops login, or the API key |
| MCP server | AI agents that run code in throwaway sandboxes | Same as the CLI |
API key
The workspace API key is the service environment variable ZBOX_WORKSPACE_API_KEY, which Zerops generates when it creates the workspace (environment variables).
The API key is the whole authority over the workspace. There are no scopes and no per-user keys. Anyone who holds it, and any sandbox you give it to, can create, read, change and terminate every sandbox, base, template, integration and webhook of the workspace. Keep it out of sandboxes unless you want them to manage the workspace. See isolation and security.
You don't need the key when you are logged in to Zerops. The Zerops GUI and the CLI reach the workspace through Zerops, which adds the key on the way. When you need it, for a script, CI or another machine, print it:
The CLI reads the key from the service with your Zerops login. Because the key is a sensitive variable, the CLI may ask you to confirm the access in the browser first.
The API key never opens a sandbox port. Port links use one-time tickets instead (access modes).
Rotate the API key
- Edit
ZBOX_WORKSPACE_API_KEYof the workspace service in the Zerops GUI. - Reload the service. The reload applies the new key and keeps sandboxes running. Until then, only the old key works (environment variables).
- Update every script, CI secret and
zbox workspace usethat holds the old key.
After the reload, the old key is refused and browsers signed in to the console with it are signed out.
The Zerops GUI and a logged-in CLI reach the workspace with an access that Zerops creates with the key of that moment. An access created before the reload keeps sending the old key until it expires, an hour after its last use, and the CLI fails with Missing or invalid Workspace API key (exit code 6). Reopen the console from the Zerops GUI, and fetch a new access for the CLI:
Web console
Each workspace serves a web console at the root of its API URL. It covers sandboxes (terminal, files, policy, snapshots, ports, sessions, events, metrics), images, integrations, activity, and the workspace itself.
Open it in one of these ways:
- From the Zerops GUI: in the workspace service's left menu, open Web UI to see the console embedded in Zerops, or Open web UI in new tab. You are signed in through Zerops, with no key. Your role in the project decides whether you can open it.
- From the CLI:
zbox workspace consoleopens the console of the current workspace, signed in. For a workspace of your account it goes through Zerops. For one you added withzbox workspace use, it opens a one-time sign-in link that is valid for 60 seconds. - Directly: open the API URL, for example
https://zbox-6da-8080.prg1.zerops.app, and paste the API key into the sign-in form.
Signing in with the key exchanges it once for a session cookie, so the key is never stored in the browser. The session lasts 7 days. Sign out ends it in that browser.
The session cookie works only over HTTPS. Over the Zerops VPN, the console at http://<hostname>.zerops:8080 loads, but signing in fails without an error. Use the Zerops GUI or the public API URL for the console. The API itself works over the VPN with a bearer token.
HTTP API
The API URL is the Zerops subdomain of the workspace's port 8080, for example https://zbox-6da-8080.prg1.zerops.app (subdomain access). zbox workspace prints it on the API line. Other services in the project reach the API at http://<hostname>:8080 (project network). Every route is under /api/rest/.
Send the API key as a bearer token in the Authorization header, on every request including WebSocket upgrades. A key in the query string is refused. Only GET /api/rest/ping answers without the key.
export ZBOX_WORKSPACE_URL=https://zbox-6da-8080.prg1.zerops.app
export ZBOX_API_KEY=$(zbox workspace key)
# the workspace: capacity, usage, domains, policy
curl -H "Authorization: Bearer $ZBOX_API_KEY" "$ZBOX_WORKSPACE_URL/api/rest/workspace"
# live sandboxes, newest first
curl -H "Authorization: Bearer $ZBOX_API_KEY" "$ZBOX_WORKSPACE_URL/api/rest/sandbox-list"
The CLI, when logged in to Zerops, uses a different path: it calls the API through Zerops with a short-lived access token minted from your login, so no key is stored on your machine.
OpenAPI document
Each workspace serves its API reference without the key:
- Swagger UI:
<API URL>/api/rest/swagger/ - OpenAPI 3 document:
<API URL>/api/rest/swagger/openapi.yml
The document describes the whole contract, including a few routes and fields that the beta does not act on yet. These docs describe only what works today. Generate a client from the document if you need one. There are no published SDKs.
Operations
Requests that create, park, wake, fork, snapshot, restore or terminate sandboxes, pull or build bases, or build templates answer right away with an operation and do the work in the background (which verbs are operations). An operation has an id, a kind, a status (PENDING, RUNNING, FINISHED or FAILED), a result when it finished and an error when it failed.
To wait for one, long-poll it. waitSeconds holds the answer until the operation finishes or fails, for at most 30 seconds. If it is still running when the time is up, you get it as it is, so ask again:
Creating a sandbox (POST /api/rest/sandbox) also takes waitSeconds in its body. The answer then carries the finished operation and the sandbox in its final state. GET /api/rest/operation-list lists recent operations, newest first.
The CLI waits for every operation by default. --no-wait prints the operation instead, --timeout stops waiting while the work goes on, and zbox operation wait <id> picks the wait up again.
Idempotency keys
The requests that consume capacity require an Idempotency-Key header: create, fork, park, wake, snapshot, restore and terminate a sandbox, pull a base and create a template. Use a new unique value for each logical request, and reuse it only when you retry that same request.
- The same key with the same request within 24 hours replays the first answer. Nothing runs twice.
- The same key with a different request, or while the first request is still in progress, is refused with
409 idempotencyKeyConflict. - A request that failed releases its key, so you can retry with it.
- Keys are shared by the whole workspace, not per client.
The CLI and the console send the header for you.
Errors
Errors use the HTTP status code and one JSON shape. code is stable for your code to match on, and meta[].metadata lists problems by field:
For example, a wrong or missing key answers 401 unauthorized, an unknown sandbox 404 sandboxNotFound, and a full workspace 409 workspaceFull (capacity).
zbox CLI
Install and log in as described in getting started. Every command explains itself with --help, and zbox --help lists the commands by task. The rules below hold for all of them.
Output and exit codes
On a terminal the CLI prints tables. When stdout is a pipe or a file, it prints tab-separated values with one header line. --json prints the API objects as they are, and -q (--quiet) prints only ids, one per line. Progress and hints go to stderr. Under --json, an error is one JSON object on stderr.
| Exit code | Meaning |
|---|---|
| 0 | OK |
| 1 | Failed, for example a failed operation |
| 2 | Wrong usage: bad flags or arguments, a request the API refused as invalid, a missing --yes |
| 3 | Not found |
| 4 | Conflict: the sandbox's state does not allow it, a name is taken, an operation is in progress |
| 5 | Timed out waiting, the work may go on |
| 6 | Not authorized: no login, no workspace, a rejected key |
| 7 | Unavailable: the workspace is not reachable or is full, retry later |
| 130 | Interrupted |
zbox exec has exit codes of its own, see run a command.
Commands that delete something (remove, base remove, workspace teardown, and so on) ask for confirmation on a terminal. Without a terminal they refuse with exit code 2 unless you pass --yes (-y).
Several workspaces
The CLI remembers the workspaces you have used and keeps one as current. Commands work on the current one.
# the Box Workspace services of your Zerops account, and the ones stored here
zbox workspace list
# store a workspace of your account; it is reached through Zerops, no key is stored
zbox workspace authorize <service-id>
# store a workspace outside your account by its API URL and key
zbox workspace use https://box-1a2-8080.prg1.zerops.app --api-key <key>
# make another stored workspace the current one
zbox workspace switch <name>
# work on another stored workspace for one command only
zbox list --workspace <name>
# drop the current workspace from the CLI, nothing is deleted
zbox workspace forget
zbox workspace use stores the key in the CLI's configuration file. ZBOX_WORKSPACE=<name> in the environment does the same as --workspace.
Scripts, CI and sandboxes
These environment variables override what the CLI has stored, for scripts and CI:
| Variable | What it does |
|---|---|
ZBOX_WORKSPACE_URL and ZBOX_API_KEY | Work on the workspace at this API URL with this key, ignoring the stored ones. Set both or neither. |
ZBOX_TOKEN | A Zerops personal access token used instead of the stored login, for commands such as zbox setup and zbox workspace teardown |
ZBOX_CONFIG | Path of the configuration file, ~/.config/zbox/config.json by default |
The URL and key pair is the simplest way for CI, and for a sandbox that should manage its own workspace. A sandbox reaches its workspace's API only through the public API URL, so it needs a network mode with internet access.
MCP server
zbox mcp serves the current workspace as an MCP server on stdio, so an AI agent can run code in sandboxes. Register it in Claude Code:
Any MCP client that starts a stdio server can run the same command. It has two tools:
run_coderunscodeinpython(the default),javascriptorbash, in/workspace, and answers its stdout, stderr and exit code. The image needspython3,nodeorbashfor that. Withoutsandbox_id, every call creates a fresh sandbox namedmcp-<time>and terminates it afterwards. Withkeep: truethe sandbox stays and the answer carries its id, which later calls pass assandbox_idto continue in it.timeout_secondsis at most 50.kill_sandboxterminates a sandbox kept byrun_code.
Sandboxes come from --template or --base. Without either, they come from the first ready template, or from the only ready base when there is no template. Their network mode is project_internet unless you pass --network. The server uses the CLI's current workspace, or the one --workspace or the environment variables above name.
A sandbox kept with keep: true keeps running after the agent session ends and holds its share of the workspace until kill_sandbox or zbox remove terminates it. Check with zbox list.