Kubi Docs
Kubi API

Always-on Linux desktops for AI agents.

Kubi gives your AI agent its own Linux desktop that stays on. The agent sees the screen, clicks and types, runs commands and moves files through this API, the TypeScript SDK (@trykubi/sdk) or the hosted MCP server. A person can watch live and take over at any time.

Guides, the SDK and model integrations live at https://docs.trykubi.com. This page is the reference for every endpoint.

Quickstart

  1. Create an API key in the dashboard and export it: export KUBI_API_KEY=kubi_...
  2. Look at your screen: GET /screens/{screen_id}/screenshot returns the image and a screenshot_id.
  3. Act on what you saw: POST /screens/{screen_id}/click with x, y, the screenshot_id and "screenshot": "after". The reply carries the screen after the click.

A new screen boots in about 90 seconds. Every route starts with https://api.trykubi.com/v1.

Authentication

Send Authorization: Bearer <key> on every request. A key carries permissions: read (see screens, screenshots and history), control (click, type, scroll), exec (run commands, read and write files) and power (create, start, stop and delete screens). MCP clients sign in with OAuth at the hosted MCP server instead and get the same permissions on the screens the person picks; this API refuses those tokens. People sign in to the dashboard, not through this API: sign-in, sessions, passkeys and two-factor login are Better Auth routes under https://console.trykubi.com/api/auth, outside this spec.

Errors

Every error has one shape:

JSONCode
{"error": {"code": "STALE_OBSERVATION", "message": "Input ran since your screenshot. Take a new screenshot first.", "request_id": "req_...", "retryable": false, "outcome": "not_applied", "docs_url": "https://docs.trykubi.com/errors#stale_observation"}}

Branch on code. Retry only when retryable is true. outcome: unknown means the action may have run: take a screenshot before acting again.

Retries

Send an Idempotency-Key header on every POST, clicks included. If a reply is lost, send the same request with the same key: you get the stored result, never a second click. The SDK does this for you.

Sharing a screen

There is no lock between keys: any key with the permission can call a screen at any time. Clicks and typing on one screen run one call at a time, in the order they arrive, and commands run side by side. While a person has control of a screen, calls that look at or act on it get 409 CONTROL_HELD, until they release it or 5 minutes pass with no input from them. A screenshot_id on an action refuses to act on a screen that changed since you looked, a person's input included. The optional Kubi-Run header labels calls so the screen's history groups them into runs; the SDK sends it for you.

History

Every call on a screen is saved in its history for 30 days: what was called, its parameters and typed text, which key called it, the result and the screenshot it returned. A person can turn detailed history (screenshots and typed text) off for the organization or one screen. The live view is never recorded.

Slow work

Every call answers within 30 seconds. Creating, starting and stopping a screen return an operation: poll GET /operations/{operation_id}?wait_s=25 and the call waits for a change instead of busy-looping. Long commands work the same way.

Lists

Lists take limit (1 to 100) and after (a cursor) and reply {"data": [...], "next": "<cursor or null>"}.

Rate limits

Over a limit you get 429 with Retry-After. Per key: 60 requests a minute for each screen in your organization, at least 300. Per screen: 2 screenshots and 10 other calls a second.

Versioning

/v1 only grows. Ignore fields, enum values and error codes you do not know yet. A route that will go away sends Deprecation and Sunset headers first.

Routes only a signed-in person can call from the dashboard (reading and setting a screen's proxy, setting and deleting secrets) are left out: an API key or OAuth token cannot call them.

Tags
Security Schemes
bearerAuth
An API key from the dashboard (kubi_..., read from KUBI_API_KEY by the SDK). Keys carry permissions: read (see screens, screenshots, history), control (click, type, scroll), exec (commands and files) and power (create, start, stop, delete). MCP clients sign in with OAuth at the hosted MCP server instead; this API refuses those tokens.
http