# Cloud Computer AI — full API notes > Shapes below are taken from server/index.js, server/computer-lifecycle.js, server/computer-record.js, and server/credits.js. Paths are relative to the console origin. This file does not contain secrets. ## Views and flags Human canvas: GET /app (also /console, /workspace, /canvas, /computers, /new) serves public/app.html. Agent view: GET /agent and GET /agent/* serve public/agent.html only when the process environment variable AGENT_VIEW_ENABLED is the string `1`. Otherwise the server responds 302 to /app. GET /api/flags is public and does not require a session. Request: none. Response: ```json { "agentView": false, "a11yFocusSafe": false, "mcp": false, "ownerLock": false, "desktopFrameA11y": false, "a11yP2CanvasAlt": false, "desktopOcr": false, "canvasListView": false, "composeServices": false } ``` `agentView` is true only when AGENT_VIEW_ENABLED=1. `a11yFocusSafe` is true only when A11Y_P3_FOCUS_SAFE=1. `mcp` is true only when MCP_ENABLED=1. `ownerLock` is OWNER_LOCK_ENABLED=1. `desktopFrameA11y` is DESKTOP_FRAME_A11Y=1. `a11yP2CanvasAlt` is A11Y_P2_CANVAS_ALT=1. `desktopOcr` is DESKTOP_OCR_ENABLED=1. `canvasListView` is CANVAS_LIST_VIEW=1. `composeServices` is true only when COMPOSE_SERVICES_ENABLED=1. Each defaults to false. These documents are always served, with or without the flag: - GET /llms.txt - GET /llms-full.txt - GET /.well-known/ccai-actions.json (file public/ccai-actions.json) - GET /agent-api.html - GET /openapi.json (file public/openapi.json) Agent view hash routes: #computers, #launch, #templates, #backups, #billing, #settings, #api, #activity, #help, #desktop/{id}. The computers table polls GET /api/computers every 5 seconds and patches rows in place. It updates the status cell text when the status string changes. It does not rebuild the table and does not move focus because of a poll. ## Auth Protected /api routes use server requireAuth. When Clerk is not configured, or CLERK_AUTH_DISABLED is `1` or `true`, the server sets a dev user and does not require a bearer token. Otherwise send: ``` Authorization: Bearer ``` The browser console gets that JWT from `await window.OpenPCAuth.getToken()`. A missing or invalid token returns: ```json { "error": "Sign in required", "code": "unauthenticated" } ``` or: ```json { "error": "Invalid or expired session", "code": "invalid_token" } ``` POST /api/api-keys (session required) creates a key. Body `{ "name": "key" }`. Response 201: ```json { "key": { "id": "k_abc123", "name": "key", "prefix": "opc_live_abcd••••wxyz", "created": "2026-10-21" }, "secret": "" } ``` The secret is not stored in later responses. GET /api/workspace maps keys with the secret removed: `{ id, name, prefix, created }`. DELETE /api/api-keys/{id} returns `{ "ok": true }`. requireAuth verifies the Clerk session JWT. It does not look up opc_live keys. Create and read keys through the session. The human canvas Settings → API keys screen is where a person reveals a new secret. When MCP_ENABLED=1, a bearer token that starts with `ccai_pat_` is verified as a personal access token. The store keeps sha256 only. requireAuth then sets `{ userId, sessionId: null, orgId: null, bypass: false, viaPat: true, patId }`. An unknown, revoked, or expired token is 401. Token management routes reject `viaPat` with 403. Create a token from a Clerk session: POST /api/tokens ```json { "name": "laptop", "expiresDays": 30 } ``` Response 201. `token` is returned once and is not stored: ```json { "token": "ccai_pat_…", "pat": { "id": "pat_…", "name": "laptop", "prefix": "ccai_pat_abcd…wxyz", "createdAt": "2026-10-22T00:00:00.000Z", "lastUsedAt": null, "revokedAt": null, "expiresAt": null } } ``` GET /api/tokens returns `{ tokens }` without hashes. DELETE /api/tokens/{id} returns `{ "ok": true }`. Omit `expiresDays` for no expiry. ## Computer record List and get return records shaped by createComputerRecord, plus later fields the provisioner sets (hostname, host, streamUrl, lines, error, backup, provisioning). Railway computers also gain deadline fields from withDeadlines. Typical fields: ```json { "id": "c_ab12cd34", "name": "Ubuntu XFCE", "status": "starting", "templateId": "t_blank", "templateName": "Ubuntu XFCE", "provider": "proxmox", "hostname": null, "externalId": null, "sandboxId": null, "streamUrl": null, "os": "Linux", "vcpu": 1, "memoryMb": 4096, "diskGb": 40, "createdAt": "2026-10-21T12:00:00.000Z", "error": null, "lines": ["$ provisioning…"] } ``` `status` is one of `starting`, `running`, `stopped`, `error`. ## GET /api/computers Response: ```json { "computers": [ { "id": "c_ab12cd34", "name": "Ubuntu XFCE", "status": "running" } ] } ``` The list is limited to the signed-in user, with the same shared-computer exceptions the console already applies. ## POST /api/computers Body fields read by the route: `name`, `templateId`, `x`, `y`, `provider`, `vcpu`, `memoryMb`, `diskGb`, `plan`, `ttlHours`, `size`, `disclosureAck`. `size` is a SKU. `small` is 1 vCPU and 4096 MB. `medium` is 2 vCPU and 8192 MB. The agent view sends `size: "small"` together with `vcpu: 1` and `memoryMb: 4096` for ordinary desktops, and `vcpu: 0`, `memoryMb: 0`, `ttlHours: null` for docker-style templates (n8n, WordPress, React CMS, vscode server, saved prompts, Railway, Backup Cloudflare). Template ids come from GET /api/workspace `templates[].id`. Examples in the default catalog include `t_blank`, `t_claude`, `t_lubuntu`, `t_debian_trixie`, `t_grok_bot_omarchy`, `t_n8n`, `t_backup_cloudflare`, `t_railway_free_vm`. Railway (`t_railway_free_vm`) requires `disclosureAck: true` or the server returns 400 `railway_ack_required`. Success is 201: ```json { "computer": { "id": "c_ab12cd34", "name": "Ubuntu XFCE", "status": "starting" } } ``` Errors use `{ "error", "code?" }`. ## GET /api/computers/{id} ```json { "computer": { "id": "c_ab12cd34" } } ``` 404 `{ "error": "not found" }` when the id is missing or not visible to the user. ## POST /api/computers/{id}/start No body required. Response `{ "computer": { "id": "c_ab12cd34", "status": "running" } }`. ## POST /api/computers/{id}/stop No body required. Response `{ "computer": { "id": "c_ab12cd34", "status": "stopped" } }`. ## DELETE /api/computers/{id} No body required for a normal computer. Response: ```json { "ok": true, "id": "c_ab12cd34" } ``` This is destructive. Confirm the computer name and id with the user before calling it. The agent view opens `dialog#confirmDialog`, names the computer, focuses Cancel, and only sends DELETE if the confirm button (`[data-testid="confirm-delete"]`) is used. Cancel and Escape return focus to the button that opened the dialog. Docker n8n computers can also require an admin password (`body.adminPassword` or header `x-ccai-admin-password`). A wrong password returns 403 and deletes nothing. The agent view surfaces that error and does not invent a password. ## GET /api/computers/{id}/screenshot Response from computerLifecycle.screenshot: ```json { "pngBase64": "" } ``` The agent view renders `data:image/png;base64,` plus `pngBase64`, and sets the image alt text to `Screenshot of desktop taken at