Reference

Public API

The complete versioned REST API, organized by resource and operation.

On this page

REST API reference

The versioned public control-plane API at https://api.zei.sh/api/v1.

The machine-readable contract is available at /api/docs-json and the interactive Swagger explorer is at /api/docs. Public routes use /public and authenticate with X-API-Key or Bearer. The API returns structured errors under an error object with code, message, requestId, and optional details.

List endpoints return data and nextCursor. Use limit and cursor for sandboxes, templates, volumes, and networks. Mutation requests should send Idempotency-Key and reuse it when retrying the same logical request.

The complete public route map is below. The clone, secret grant, and secret lease routes are included because they are part of the live controller surface even when an older contract snapshot does not list every advanced route.

terminal
1# Resources2GET    /public/templates3GET    /public/templates/:templateId4GET    /public/ssh-keys5POST   /public/ssh-keys6DELETE /public/ssh-keys/:keyId7POST   /public/volumes8GET    /public/volumes9GET    /public/volumes/:volumeId10DELETE /public/volumes/:volumeId11POST   /public/networks12GET    /public/networks13GET    /public/networks/:networkId14DELETE /public/networks/:networkId1516# Sandboxes17POST   /public/sandboxes18GET    /public/sandboxes19GET    /public/sandboxes/:sandboxId20PATCH  /public/sandboxes/:sandboxId21DELETE /public/sandboxes/:sandboxId22POST   /public/sandboxes/:sandboxId/clone23GET    /public/sandboxes/:sandboxId/exec-access24GET    /public/sandboxes/:sandboxId/terminal-url25POST   /public/sandboxes/:sandboxId/preview-codes26POST   /public/sandboxes/:sandboxId/tunnel-access27POST   /public/sandboxes/:sandboxId/ports28PUT    /public/sandboxes/:sandboxId/ports/:port/share29POST   /public/sandboxes/:sandboxId/ssh-keys/sync30GET    /public/sandboxes/:sandboxId/logs31GET    /public/sandboxes/:sandboxId/events32POST   /public/sandboxes/:sandboxId/{start|pause|resume|stop|kill}33POST   /public/sandboxes/:sandboxId/snapshots34GET    /public/sandboxes/:sandboxId/snapshots35DELETE /public/sandboxes/:sandboxId/snapshots/:snapshotId3637# Secrets38GET    /public/secrets39POST   /public/secrets40GET    /public/secrets/:secretId41PATCH  /public/secrets/:secretId42DELETE /public/secrets/:secretId43POST   /public/secrets/:secretId/grants44POST   /public/secrets/:sandboxId/leases

List templates

List templates visible to the authenticated organization.

GET /public/templates?limit=20&cursor=...

Permission: MACHINE_READ.

Use this to discover template IDs and their default runtime resources before creating a sandbox.

Response: A paginated data array and nextCursor. The default limit is 20 and the maximum is 100.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/templates?limit=20&cursor=... \2  -H "X-API-Key: $ZEISH_API_KEY"

Get a template

Fetch one visible sandbox template by ID.

GET /public/templates/:templateId

Permission: MACHINE_READ.

The response includes the image, CPU, memory, machine kind, and declared ingress settings.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/templates/:templateId \2  -H "X-API-Key: $ZEISH_API_KEY"

List SSH keys

List public SSH keys registered by the authenticated user.

GET /public/ssh-keys

Permission: MACHINE_READ.

Keys are used for SSH access to sandboxes created for the user.

Response: An array of key metadata and public key material. Private keys are never stored.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/ssh-keys \2  -H "X-API-Key: $ZEISH_API_KEY"

Register an SSH key

Register a public key for future sandbox access.

POST /public/ssh-keys

Permission: MACHINE_UPDATE.

Register the public half of a key before creating a sandbox or sync it into an existing runtime.

Request body: {"name":"workstation","publicKey":"ssh-ed25519 AAAA..."}

Response: The created key with id, name, publicKey, isManaged, and createdAt.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/ssh-keys \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"workstation","publicKey":"ssh-ed25519 AAAA..."}'

Delete an SSH key

Remove a registered public SSH key.

DELETE /public/ssh-keys/:id

Permission: MACHINE_UPDATE.

Deletion affects future provisioning. Call the sandbox SSH key sync operation to update an existing runtime.

Response: {"ok":true}

terminal
1curl -X DELETE https://api.zei.sh/api/v1/public/ssh-keys/:id \2  -H "X-API-Key: $ZEISH_API_KEY"

Create a volume

Create persistent organization storage.

POST /public/volumes

Permission: ORG_MANAGE.

Volumes are region-scoped and survive sandbox stop and runtime replacement.

Request body: {"name":"agent-data","slug":"agent-data","region":"bremen","sizeGb":20}

Response: The created volume with id, organizationId, name, slug, region, sizeGb, and timestamps.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/volumes \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"agent-data","slug":"agent-data","region":"bremen","sizeGb":20}'

List volumes

List persistent volumes in the organization.

GET /public/volumes?limit=20&cursor=...

Permission: ORG_MANAGE.

Use limit and the returned nextCursor to walk the collection.

Response: A paginated data array and nextCursor. Limits range from 1 through 100.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/volumes?limit=20&cursor=... \2  -H "X-API-Key: $ZEISH_API_KEY"

Get a volume

Fetch one organization volume by ID.

GET /public/volumes/:volumeId

Permission: ORG_MANAGE.

Use the volume ID in sandbox create or update requests.

Response: The volume resource, including its region and sizeGb.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/volumes/:volumeId \2  -H "X-API-Key: $ZEISH_API_KEY"

Delete a volume

Delete one organization volume.

DELETE /public/volumes/:volumeId

Permission: ORG_MANAGE.

Confirm that no sandbox still depends on the volume before deleting it.

Response: The deleted volume resource.

terminal
1curl -X DELETE https://api.zei.sh/api/v1/public/volumes/:volumeId \2  -H "X-API-Key: $ZEISH_API_KEY"

Create a network

Create an organization-scoped logical network.

POST /public/networks

Permission: ORG_MANAGE.

Attach the network to sandboxes with networkId.

Request body: {"name":"agent-network","slug":"agent-network","region":"bremen"}

Response: The created network with id, organizationId, name, slug, region, and createdAt.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/networks \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"agent-network","slug":"agent-network","region":"bremen"}'

List networks

List logical networks in the organization.

GET /public/networks?limit=20&cursor=...

Permission: ORG_MANAGE.

Use cursor pagination for stable iteration over organization networks.

Response: A paginated data array and nextCursor.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/networks?limit=20&cursor=... \2  -H "X-API-Key: $ZEISH_API_KEY"

Get a network

Fetch one organization network by ID.

GET /public/networks/:networkId

Permission: ORG_MANAGE.

Use the network ID in sandbox create or update requests.

Response: The network resource.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/networks/:networkId \2  -H "X-API-Key: $ZEISH_API_KEY"

Delete a network

Delete an organization network.

DELETE /public/networks/:networkId

Permission: ORG_MANAGE.

Remove the network from dependent sandboxes before deleting it.

Response: The deleted network resource.

terminal
1curl -X DELETE https://api.zei.sh/api/v1/public/networks/:networkId \2  -H "X-API-Key: $ZEISH_API_KEY"

Create a sandbox

Provision a MicroVM sandbox with optional resources, ingress, and secret injection.

POST /public/sandboxes

Permission: MACHINE_CREATE.

The request needs name and templateId or template. CPU is cores, memory is MB, and omitted resources use the template defaults.

Request body: {"name":"agent-run","templateId":"TEMPLATE_ID","cpu":4,"memory":4096,"region":"bremen","networkId":"NETWORK_ID","volumeIds":["VOLUME_ID"]}

Response: The sandbox record. Provisioning is asynchronous and normally requests a running runtime.

Reuse the same Idempotency-Key when retrying one logical create request.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"agent-run","templateId":"TEMPLATE_ID","cpu":4,"memory":4096,"region":"bremen","networkId":"NETWORK_ID","volumeIds":["VOLUME_ID"]}'

List sandboxes

List compact sandbox records in the organization.

GET /public/sandboxes?limit=20&cursor=...

Permission: MACHINE_READ.

Use this for dashboards and polling. Fetch a detail record when you need enriched access information.

Response: A paginated data array and nextCursor.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/sandboxes?limit=20&cursor=... \2  -H "X-API-Key: $ZEISH_API_KEY"

Get sandbox details

Fetch one sandbox with runtime and access URL enrichment.

GET /public/sandboxes/:sandboxId

Permission: MACHINE_READ.

Use the detail response to decide whether a runtime-dependent operation is ready.

Response: The sandbox record with current status and available runtime metadata.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/sandboxes/:sandboxId \2  -H "X-API-Key: $ZEISH_API_KEY"

Update a sandbox

Change mutable sandbox configuration.

PATCH /public/sandboxes/:sandboxId

Permission: MACHINE_UPDATE.

Update name, templateId, region, CPU, memory, networkId, volumeIds, or labels.

Request body: {"name":"agent-run-final","cpu":6,"memory":8192,"labels":{"run":"2026-08-30"}}

Response: The updated sandbox record.

Set networkId to null to detach the current network.

terminal
1curl -X PATCH https://api.zei.sh/api/v1/public/sandboxes/:sandboxId \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"agent-run-final","cpu":6,"memory":8192,"labels":{"run":"2026-08-30"}}'

Delete a sandbox

Permanently delete a sandbox.

DELETE /public/sandboxes/:sandboxId

Permission: MACHINE_DELETE.

Deletion is a lifecycle action and is irreversible.

Response: The lifecycle result for the delete request.

terminal
1curl -X DELETE https://api.zei.sh/api/v1/public/sandboxes/:sandboxId \2  -H "X-API-Key: $ZEISH_API_KEY"

Clone a sandbox

Create a new sandbox from an existing sandbox state.

POST /public/sandboxes/:sandboxId/clone

Permission: MACHINE_CREATE.

Use clones for parallel agent branches and repeatable evaluation runs.

Request body: {"name":"agent-run-copy"}

Response: The new sandbox record.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/clone \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"agent-run-copy"}'

Mint data-plane access

Mint short-lived credentials for commands, files, and terminal sessions.

GET /public/sandboxes/:sandboxId/exec-access

Permission: MACHINE_UPDATE.

The token is scoped to one sandbox and is valid for about ten minutes.

Response: sandboxUrl, sandboxRpcUrl, token, and expiresAt.

Send the token as Authorization: Bearer <token>. Never log or persist it.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/exec-access \2  -H "X-API-Key: $ZEISH_API_KEY"

Get a terminal URL

Create a browser terminal URL for a sandbox.

GET /public/sandboxes/:sandboxId/terminal-url

Permission: MACHINE_READ.

Open the returned URL in a browser to use the sandbox terminal.

Response: A terminal URL and its expiration metadata.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/terminal-url \2  -H "X-API-Key: $ZEISH_API_KEY"

Sync SSH keys

Apply the user's current SSH keys to an existing sandbox runtime.

POST /public/sandboxes/:sandboxId/ssh-keys/sync

Permission: MACHINE_UPDATE.

Call this after registering or removing a user SSH key.

Response: The updated sandbox result.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/ssh-keys/sync \2  -H "X-API-Key: $ZEISH_API_KEY"

Create a preview code

Mint temporary HTTP browser or agent access to an exposed port.

POST /public/sandboxes/:sandboxId/preview-codes

Permission: MACHINE_READ.

Use the browser handoff URL for a real browser and base_url with the bearer code for fetch, WebSocket, Playwright, or CDP.

Request body: {"port":3000,"ttl_seconds":300,"path":"/health"}

Response: url, handoff_url, base_url, code, and expires_at.

TTL is 1 through 3600 seconds. Do not append paths to the browser handoff URL.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/preview-codes \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"port":3000,"ttl_seconds":300,"path":"/health"}'

Mint tunnel access

Mint a short-lived WebSocket tunnel for exposed TCP ports.

POST /public/sandboxes/:sandboxId/tunnel-access

Permission: MACHINE_UPDATE.

Use this for CDP, databases, and other protocols that do not work through an HTTP Host header.

Request body: {"ttl_seconds":60}

Response: ws_url, token, and expires_at.

TTL is 1 through 3600 seconds. The default is 60 seconds.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/tunnel-access \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"ttl_seconds":60}'

Add a sandbox port

Expose a TCP or UDP port from a sandbox.

POST /public/sandboxes/:sandboxId/ports

Permission: MACHINE_UPDATE.

Declare raw L4 ingress with an internal port and optional external port and access policy.

Request body: {"internalPort":3000,"externalPort":3000,"protocol":"tcp","accessPolicy":"org"}

Response: The created port exposure.

Ports must be between 1 and 65535. Access policy is org or public.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/ports \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"internalPort":3000,"externalPort":3000,"protocol":"tcp","accessPolicy":"org"}'

Change port access

Change the access policy for an exposed port.

PUT /public/sandboxes/:sandboxId/ports/:port/share

Permission: MACHINE_UPDATE.

Use org for organization-scoped credentials or public for unauthenticated access.

Request body: {"policy":"public"}

Response: The updated port exposure.

terminal
1curl -X PUT https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/ports/:port/share \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"policy":"public"}'

List sandbox logs

Read bounded captured output from a sandbox.

GET /public/sandboxes/:sandboxId/logs?limit=100&source=app&service=...

Permission: MACHINE_READ.

Filter by source or service when diagnosing boot, memory, or application output.

Response: A bounded log history.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/logs?limit=100&source=app&service=... \2  -H "X-API-Key: $ZEISH_API_KEY"

List sandbox events

Read lifecycle events for a sandbox.

GET /public/sandboxes/:sandboxId/events?limit=100

Permission: MACHINE_READ.

Poll events to correlate asynchronous lifecycle transitions with an agent run.

Response: Events with status, source, timestamp, and optional message.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/events?limit=100 \2  -H "X-API-Key: $ZEISH_API_KEY"

Start a sandbox

Request a sandbox runtime to start.

POST /public/sandboxes/:sandboxId/start

Permission: MACHINE_UPDATE.

Use start after a sandbox is stopped and poll its detail or events until it is running.

Response: The lifecycle result.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/start \2  -H "X-API-Key: $ZEISH_API_KEY"

Pause a sandbox

Pause a sandbox while preserving its state.

POST /public/sandboxes/:sandboxId/pause

Permission: MACHINE_UPDATE.

Pause is useful when you want to preserve state without keeping the runtime active.

Response: The lifecycle result.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/pause \2  -H "X-API-Key: $ZEISH_API_KEY"

Resume a sandbox

Resume a paused sandbox.

POST /public/sandboxes/:sandboxId/resume

Permission: MACHINE_UPDATE.

Poll the sandbox detail until the runtime is running before requesting data-plane access.

Response: The lifecycle result.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/resume \2  -H "X-API-Key: $ZEISH_API_KEY"

Stop a sandbox

Stop a sandbox runtime while retaining the sandbox record.

POST /public/sandboxes/:sandboxId/stop

Permission: MACHINE_UPDATE.

Stop releases the active runtime and preserves the sandbox configuration.

Response: The lifecycle result.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/stop \2  -H "X-API-Key: $ZEISH_API_KEY"

Kill a sandbox

Force-stop a stuck sandbox runtime.

POST /public/sandboxes/:sandboxId/kill

Permission: MACHINE_UPDATE.

Use kill for a runtime that does not respond to a normal stop request.

Response: The lifecycle result.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/kill \2  -H "X-API-Key: $ZEISH_API_KEY"

Create a snapshot

Capture a sandbox runtime state for reuse.

POST /public/sandboxes/:sandboxId/snapshots

Permission: MACHINE_UPDATE.

Create snapshots from a live runtime and wait for the snapshot to become ready before using it.

Request body: {"displayName":"dependencies-v4"}

Response: The new snapshot with its status and ID.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/snapshots \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"displayName":"dependencies-v4"}'

List snapshots

List snapshots belonging to one sandbox.

GET /public/sandboxes/:sandboxId/snapshots

Permission: MACHINE_READ.

Use sandbox-scoped snapshot IDs for cleanup and repeatable fan-out.

Response: An array of sandbox snapshots.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/snapshots \2  -H "X-API-Key: $ZEISH_API_KEY"

Delete a snapshot

Delete one sandbox snapshot.

DELETE /public/sandboxes/:sandboxId/snapshots/:snapshotId

Permission: MACHINE_UPDATE.

Snapshot deletion is irreversible.

Response: {"ok":true}

terminal
1curl -X DELETE https://api.zei.sh/api/v1/public/sandboxes/:sandboxId/snapshots/:snapshotId \2  -H "X-API-Key: $ZEISH_API_KEY"

List secret metadata

List organization secrets without returning their values.

GET /public/secrets

Permission: ORG_MANAGE.

Use this to discover secret IDs and metadata. Values are excluded from list responses.

Response: Secret metadata only.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/secrets \2  -H "X-API-Key: $ZEISH_API_KEY"

Create a secret

Store a provider-backed plaintext or JSON secret.

POST /public/secrets

Permission: ORG_MANAGE.

The current deployment uses Vault. Other provider values require that provider to be configured.

Request body: {"name":"github-token","provider":"vault","providerReference":"secret/data/ci/github","providerKey":"token","format":"plaintext","value":"replace-me"}

Response: The secret metadata.

Values are audited when viewed or edited. Keep provider credentials out of sandbox records.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/secrets \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"github-token","provider":"vault","providerReference":"secret/data/ci/github","providerKey":"token","format":"plaintext","value":"replace-me"}'

Get a secret

Read one secret value and its metadata.

GET /public/secrets/:secretId

Permission: ORG_MANAGE.

This operation is audited and returns no-store response headers.

Response: The secret metadata and resolved value.

Treat the response as sensitive data and do not log it.

terminal
1curl -X GET https://api.zei.sh/api/v1/public/secrets/:secretId \2  -H "X-API-Key: $ZEISH_API_KEY"

Update a secret

Update secret metadata or material.

PATCH /public/secrets/:secretId

Permission: ORG_MANAGE.

Send only the fields that should change.

Request body: {"name":"github-token-rotated","value":"replace-me","version":"v2","format":"plaintext"}

Response: The updated secret metadata.

terminal
1curl -X PATCH https://api.zei.sh/api/v1/public/secrets/:secretId \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"name":"github-token-rotated","value":"replace-me","version":"v2","format":"plaintext"}'

Delete a secret

Remove a secret from its configured provider.

DELETE /public/secrets/:secretId

Permission: ORG_MANAGE.

Deletion archives the secret metadata after provider removal.

Response: The deletion result.

terminal
1curl -X DELETE https://api.zei.sh/api/v1/public/secrets/:secretId \2  -H "X-API-Key: $ZEISH_API_KEY"

Grant a secret to a sandbox

Authorize a secret for environment or file delivery.

POST /public/secrets/:secretId/grants

Permission: ORG_MANAGE.

Grant startup or command delivery to a specific sandbox and target.

Request body: {"sandboxId":"SANDBOX_ID","target":"env","targetName":"GITHUB_TOKEN","mode":"command"}

Response: The grant result.

Environment names must match shell variable syntax. File targets must be below /run/secrets.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/secrets/:secretId/grants \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"sandboxId":"SANDBOX_ID","target":"env","targetName":"GITHUB_TOKEN","mode":"command"}'

Mint a secret lease

Mint a short-lived lease for secret resolution.

POST /public/secrets/:sandboxId/leases

Permission: ORG_MANAGE.

Leases are scoped to organization, sandbox, operation, secret IDs, expiry, and nonce.

Request body: {"operation":"command"}

Response: The short-lived lease claims.

Operation is startup, command, or file. Do not persist lease tokens.

terminal
1curl -X POST https://api.zei.sh/api/v1/public/secrets/:sandboxId/leases \2  -H "X-API-Key: $ZEISH_API_KEY"3  -H "Content-Type: application/json" \4  -d '{"operation":"command"}'