Remote Workspaces API
Authenticate to the Kimchi Workspaces API and manage Remote Workspaces, workspace templates, sessions, events, and costs over HTTPS.
The Remote Workspaces API is the HTTP interface to Kimchi's remote workspace infrastructure. It lets you create and manage the cloud sandboxes behind Remote Workspaces — workspaces, the templates they are provisioned from, the sessions running inside them, and the events, usage, and costs they produce — without touching the Kimchi console.
This guide covers authentication, the available endpoints grouped by what they do, and how to call them.
Prerequisites
- A Kimchi account with access to an organization that has Remote Workspaces enabled.
- An API key or Service Key with permission to manage workspaces. Create one on the API Keys page in the Kimchi console (see API Keys and Service Keys).
- Your organization ID. Every management endpoint takes it as a path parameter (
{organizationId}).
Base URL
All Workspaces API endpoints are served from the same hosts as the rest of the Kimchi API, under the /ai-optimizer/v1beta prefix:
| Region | Base URL |
|---|---|
| US | https://api.cast.ai/ai-optimizer/v1beta |
| EU | https://api.eu.cast.ai/ai-optimizer/v1beta |
| India | https://api.india.cast.ai/ai-optimizer/v1beta |
Use the host for the region your organization is in.
Authentication
Every request must authenticate with one of two methods:
X-API-Keyheader — send your API key or Service Key:curl -H 'X-API-Key: {KEY}' https://api.cast.ai/ai-optimizer/v1beta/...- Bearer token — send a Kimchi identity token (the JWT used by Kimchi itself):
curl -H 'Authorization: Bearer {TOKEN}' https://api.cast.ai/ai-optimizer/v1beta/...
Workspace cost data follows the same visibility rules as the workspace list: members see their own workspaces plus org-wide shared ones, and organization owners see the whole organization. The workspace and template management endpoints apply the role rules of the console — Owner and Member can create and edit, Viewer and Analyst can read (see User Roles).
Errors return a standard Status object with a code (a google.rpc.Code value), a developer-facing message, and optional details — e.g. 404 maps to NOT_FOUND when a workspace or template does not exist, 400 to INVALID_ARGUMENT when a request is rejected at the API edge or by the sandbox operator.
Endpoints at a glance
| API | Endpoint | What it does |
|---|---|---|
| Workspaces | GET /organizations/{organizationId}/workspaces | List workspaces |
| Workspaces | POST /organizations/{organizationId}/workspaces | Create a workspace |
| Workspaces | GET /organizations/{organizationId}/workspaces/{id} | Get a workspace |
| Workspaces | PUT /organizations/{organizationId}/workspaces/{id} | Create or update a workspace (upsert) |
| Workspaces | DELETE /organizations/{organizationId}/workspaces/{id} | Delete a workspace |
| Workspaces | POST /organizations/{organizationId}/workspaces/{id}:suspend | Suspend a running workspace |
| Workspaces | POST /organizations/{organizationId}/workspaces/{id}:resume | Resume a suspended workspace |
| Workspaces | GET /organizations/{organizationId}/workspaces/{id}:cost | Get one workspace's cost over a period |
| Workspaces | GET /organizations/{organizationId}/workspaces:costReport | Get a cost report over a period |
| Workspaces | GET /organizations/{organizationId}/workspaces:costPrices | Get the effective cost unit prices |
| Workspaces | GET /organizations/{organizationId}/workspaces:getSecretMappings | Get the caller's effective secret mappings |
| Templates | GET /organizations/{organizationId}/workspace-templates | List workspace templates |
| Templates | POST /organizations/{organizationId}/workspace-templates | Create a workspace template |
| Templates | GET /organizations/{organizationId}/workspace-templates/{id} | Get a workspace template |
| Templates | PATCH /organizations/{organizationId}/workspace-templates/{id} | Update a workspace template (full replacement) |
| Templates | DELETE /organizations/{organizationId}/workspace-templates/{id} | Delete a workspace template |
| Sessions | GET /organizations/{organizationId}/workspaces/-/sessions | List sessions across all workspaces |
| Events | GET /organizations/{organizationId}/workspaces/-/events | List curated workspace events |
| Events | GET /organizations/{organizationId}/workspaces/{workspaceId}/usage | Get a usage metric time series |
| Tokens | POST /workspace-tokens:exchange | Exchange an identity token for a workspace JWT |
| Tokens | POST /workspace-tokens:verifyKey | Verify an API key's identity |
Manage workspaces
Workspaces are the sandboxes themselves: a Workspace record owns its status, resource allocation, template reference, and secret injection state.
Workspace lifecycle
| Field | Meaning |
|---|---|
id | The workspace ID (assigned by the API) |
status | INITIALIZING, ACTIVE, SUSPENDED, DELETING, TERMINATED, or FAILED |
createTime | When the workspace was created |
cluster | The cluster hosting the workspace |
creatorId | The user who created it |
clientType | What created it, e.g. harness |
uri | WebSocket URI for attaching to the workspace |
hostIdentityPublicKey | Host identity key for SSH access |
List workspaces
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces?page.limit=20'Optional query parameters: creatorId and clientType filter the listing; page.limit/page.cursor paginate; sort.field/sort.order order results (order defaults to ASC). The response is a ListWorkspacesResponse with an items array, totalCount, and nextPageCursor when more pages exist.
Create a workspace
Workspaces are usually provisioned from a template, which snapshots its preset values at creation time:
curl -X POST \
-H 'X-API-Key: {KEY}' \
-H 'Content-Type: application/json' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces' \
-d '{
"templateName": "python-dev",
"description": "Feature branch sandbox"
}'Reference templates by templateName (resolved to whatever currently carries that name) or by templateId (pinned to an exact template). Set at most one; when both are set they must agree. On create, templateName/templateId conflict with explicit spec fields — specify one or the other, never both.
Alternatively, pass create-time parameters directly in spec:
curl -X POST \
-H 'X-API-Key: {KEY}' \
-H 'Content-Type: application/json' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces' \
-d '{
"spec": {
"resources": { "cpu": "250m", "memory": "1Gi", "pvcSize": "20Gi" },
"dependencies": ["jq", "node@22"],
"egressPolicy": { "denyByDefault": true, "allowed": ["github.com", "registry.npmjs.org"] }
}
}'spec fields: resources (Kubernetes quantity strings like 500m, 1Gi — unset fields inherit the organization policy), dependencies (CLI tools to install at boot, [registry:]tool[@version] grammar), egressPolicy (denyByDefault, allowed, denied), initScript (a shell script run at boot, 64 KiB cap), files (custom files written into the sandbox, home-relative paths), and secretMappings (environment variable to secret reference). On read, only resources is populated with the resolved values; the other fields are write-only create-time inputs and come back empty ([], {}, or null).
Get and update a workspace
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces/{id}'GET returns the current Workspace. PUT /workspaces/{id} creates or updates — on an existing workspace it is a read-modify-write: spec.resources is immutable after creation (different values are rejected), the template reference must be absent or equal to the stored value, and write-only spec fields are ignored. Deleting a workspace is DELETE /workspaces/{id}.
Suspend and resume
Suspend stops a running workspace (chargeable resources are released), resume brings it back:
curl -X POST -H 'X-API-Key: {KEY}' \
https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces/{id}:suspend
curl -X POST -H 'X-API-Key: {KEY}' \
https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces/{id}:resumeWorkspace templates
Templates are organization-scoped presets that admins and owners curate so members can provision consistent workspaces. A WorkspaceTemplate carries a unique, immutable name (rename = delete and recreate), a description, and a spec mirroring the workspace create-time parameters. The full spec is returned on read — unlike Workspace.spec, template definitions are catalog content.
# Create a template
curl -X POST \
-H 'X-API-Key: {KEY}' -H 'Content-Type: application/json' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspace-templates' \
-d '{
"name": "python-dev",
"description": "Python sandbox with Node tooling",
"spec": {
"resources": { "cpu": "250m", "memory": "1Gi", "pvcSize": "20Gi" },
"dependencies": ["python", "node@22", "jq"]
}
}'
# List templates
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspace-templates'
# Update (full replacement — omitted fields are cleared; name is immutable)
curl -X PATCH \
-H 'X-API-Key: {KEY}' -H 'Content-Type: application/json' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspace-templates/{id}' \
-d '{ "name": "python-dev", "description": "Updated", "spec": { "dependencies": ["python", "node@22"] } }'A workspace resolves its template to a snapshot of values at creation time. Editing or deleting a template later affects only workspaces created afterwards — never workspaces that already exist.
Sessions, events, and usage
Sessions, events, and usage let you observe what is happening inside your workspaces.
List sessions
GET /organizations/{organizationId}/workspaces/-/sessions lists the live sandbox sessions across all workspaces (optionally filtered by clientType). Each WorkspaceSession reports its name, workspaceId, whether it is alive, startedTime, and the agentMode it runs under (RPC, ACP, or PTY).
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces/-/sessions'List workspace events
GET /organizations/{organizationId}/workspaces/-/events returns curated, customer-facing events — creation timeline, health, and lifecycle — newest first. Filter with workspaceId (empty lists events for all workspaces), fromTime/toTime (defaults: now-7d to now), minSeverity (info default, warn, error), eventTypes (e.g. workspace.oom), and page parameters.
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces/-/events?minSeverity=warn&workspaceId={id}'Each event carries workspaceId, eventTime, eventType, severity, a customer-facing title, and details (whitelisted display fields like sandbox, pod, reason). Titles and details are final renderings produced at ingest — display them as-is.
Get usage metrics
GET /organizations/{organizationId}/workspaces/{workspaceId}/usage returns a pre-aggregated time series for one metric. Pick the metric from the full enum — CPU seconds, memory working set / max usage, network receive / transmit bytes, filesystem read / write bytes, CPU throttled periods, restarts total, PVC requested bytes — and the resolution (5m or 1h buckets). fromTime/toTime default to the last 24 hours. Counter metrics are returned as per-interval rates.
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces/{workspaceId}/usage?metric=USAGE_METRIC_CPU_USAGE_SECONDS&resolution=RESOLUTION_1H'Costs
Workspace costs are fixed-rate: unit prices multiplied by the workspace's resource requests and the overlap of its lifetime with the requested period. Deleted workspaces remain billable and appear in reports for the period they existed.
GET /workspaces/{id}:cost— one workspace's cost (cpuCost,memoryCost,storageCost,totalCostin USD). Missing window bounds default to the workspace's lifetime (create time to deletion time or now); a two-sided window entirely outside the lifetime yields zero costs.GET /workspaces:costReport?startTime=...&endTime=...— per-workspace costs over a period (both bounds required) plus thetotalCostacross them. Visibility follows the caller's role: members see their own + org-wide shared workspaces, owners see the whole org.GET /workspaces:costPrices— the effective unit prices the cost endpoints apply: the organization's override row when present, else the global default. ReturnscpuHourly,memoryHourly,pvcHourly, andephemeralHourlyin USD.
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces:costReport?startTime=2026-10-01T00:00:00Z&endTime=2026-11-01T00:00:00Z'Secret mappings
GET /workspaces:getSecretMappings returns the caller's effective secret injection mappings — the environment variable name → secret reference map that CreateWorkspace injects when spec.secretMappings is unset. This is metadata only: secret values are never exposed by the API.
curl -H 'X-API-Key: {KEY}' \
'https://api.cast.ai/ai-optimizer/v1beta/organizations/{organizationId}/workspaces:getSecretMappings'Workspace token exchange
The token endpoints (note: no organizationId in the path) support machine-to-machine auth between Kimchi services and workspace infrastructure.
POST /workspace-tokens:exchange— exchange a Kimchi identity token for a short-lived, Ed25519-signed JWT scoped to one workspace ({"workspaceId": "..."}). Recipients verify it against the public key at/.well-known/jwks.json. The response carries thetokenand itsexpireTime; treat the token as expired slightly before that time to account for clock skew.POST /workspace-tokens:verifyKey— read-only introspection: returns the canonical identity (organizationId,userId) associated with the API key used to authenticate the call.
curl -X POST \
-H 'Authorization: Bearer {IDENTITY_TOKEN}' \
-H 'Content-Type: application/json' \
'https://api.cast.ai/ai-optimizer/v1beta/workspace-tokens:exchange' \
-d '{ "workspaceId": "{id}" }'See also
- Create and Use a Remote Workspace — the console and CLI journey these endpoints back.
- Workspace Templates — what a template configures.
- API Keys and Service Keys — create the key you authenticate with.
Updated 3 days ago