---
seo:
  description: >-
    Control plane API for pols.so developer sandboxes: full Ubuntu 24.04 VMs
    with root, systemd and Docker.
sidebar:
  label: Overview
title: pols.so API
---
Control plane API for pols.so developer sandboxes: full Ubuntu 24.04 VMs
with root, systemd and Docker.

This file is the source of truth. The Go server interface, the Go client
(`pkg/api`) and the TypeScript client (`clients/typescript`) are generated
from it with `make generate`.

Authentication: `/v1` endpoints require an org-scoped API key as a
bearer token (`Authorization: Bearer pols_...`), except the public
`/v1/openapi.yaml`. The CDP WebSocket endpoint also accepts the connection
token described under `GET /v1/sandboxes/{sandbox}/browser/cdp`.

Lifecycle calls are asynchronous. They record the desired state and return
at once; a reconciler drives the runtime to it. Poll `GET
/v1/sandboxes/{sandbox}` until `status` equals `desired_state` (or is
`error` unless deletion is pending). Conflicting stop/resume requests
return 409 until the current transition finishes.

Wherever a path takes `{sandbox}` or `{template}`, either the ID
(`sbx_...`, `tpl_...`) or the org-unique name is accepted.

Computer use: every sandbox has a 1920x1080 X11 desktop and Google
Chrome. `/computer/*` takes screenshots of the whole desktop and drives
its mouse and keyboard; coordinates are pixels in that 1920x1080 space,
with (0, 0) at the top left. `/browser/cdp` connects Playwright or
Puppeteer to the sandbox's Chrome over the Chrome DevTools Protocol,
proxied by the control plane; Chrome's debugging port itself only
listens inside the sandbox.

Edge: the edge serves sandbox content on its own domain (the sandbox
domain, `on.pols.so` in production), never on the API's or the site's
domain. A published port is at
`https://<sandbox>-<port>.<sandbox domain>`, where `<sandbox>` is the
sandbox ID with `_` replaced by `-`; the desktop is at
`<sandbox>-desktop` and the CDP endpoint at `<sandbox>-cdp`. Ports are
private unless published as public: open them with a login link from
`POST /v1/sandboxes/{sandbox}/ports/{port}/link`, whose token the edge
exchanges for a cookie scoped to that one host. The desktop takes no
cookie: its link from `POST /v1/sandboxes/{sandbox}/desktop` carries a
token in the URL fragment, which the edge's desktop page presents when
it connects. `ssh <sandbox ID>@<gateway>`
reaches a running sandbox with any key registered under `/v1/ssh-keys`.

Vault: each org has a vault of passwords and environment variables,
encrypted at rest. Its owner adds, replaces and deletes entries on the
website (`https://my.pols.so/account`); API keys can only list their names
(`GET /v1/vault`) and name them in `secrets` when creating or forking a
sandbox, which gets each one as an environment variable of that name.
No endpoint returns a value.

Limits: `/v1` calls are rate limited per client address and per org,
sandbox and template lifecycle calls more tightly, and an org may have
only so many exec, file, computer and CDP calls in progress at once.
Over a limit the API answers 429 `rate_limited` with a `Retry-After`
header. A request body that stalls is answered with 408 `timeout`.

Errors and headers: a failure of the sandbox host is answered with 502
`runtime_error` and a fixed message; the details are only in the
server's log. A `{sandbox}` or `{template}` that is neither a well-formed
ID nor a name is 404 `not_found`. Names and descriptions must be UTF-8
text without control characters other than tab, and exec arguments
and paths must not contain NUL. Every response carries
`X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`,
`Content-Security-Policy: default-src 'none'; frame-ancestors 'none'`
and `Cache-Control: no-store`, except that `/v1/openapi.yaml` may be
cached.

Version 0.1.0

Base URL: `https://api.pols.so`

## org

- [`GET /v1/org`](/api/org/get-org/) — The org the API key belongs to, with its quotas and current consumption.
- [`GET /v1/org/stats`](/api/org/get-org-stats/) — CPU, memory and disk use summed over the org's running sandboxes.

## api-keys

- [`GET /v1/api-keys`](/api/api-keys/list-api-keys/) — List the org's API keys (secrets are never returned).
- [`POST /v1/api-keys`](/api/api-keys/create-api-key/) — Refused; create API keys on the website's account page. Deprecated.
- [`DELETE /v1/api-keys/{key}`](/api/api-keys/revoke-api-key/) — Refused; revoke API keys on the website's account page. Deprecated.

## sandboxes

- [`GET /v1/sandboxes`](/api/sandboxes/list-sandboxes/) — List sandboxes.
- [`POST /v1/sandboxes`](/api/sandboxes/create-sandbox/) — Create a sandbox from a template and start it.
- [`GET /v1/sandboxes/{sandbox}`](/api/sandboxes/get-sandbox/) — Get a sandbox.
- [`DELETE /v1/sandboxes/{sandbox}`](/api/sandboxes/delete-sandbox/) — Delete a sandbox and its disk.
- [`GET /v1/sandboxes/{sandbox}/stats`](/api/sandboxes/get-sandbox-stats/) — A sandbox's current CPU, memory and disk use and its recent history.
- [`POST /v1/sandboxes/{sandbox}/stop`](/api/sandboxes/stop-sandbox/) — Stop a sandbox (snapshot, then free; stopped time is not metered).
- [`POST /v1/sandboxes/{sandbox}/resume`](/api/sandboxes/resume-sandbox/) — Resume a stopped sandbox.
- [`POST /v1/sandboxes/{sandbox}/fork`](/api/sandboxes/fork-sandbox/) — Fork a sandbox into a new running sandbox with a copy of its disk.

## exec

- [`POST /v1/sandboxes/{sandbox}/exec`](/api/exec/exec-sandbox/) — Run a command in a running sandbox.

## files

- [`GET /v1/sandboxes/{sandbox}/files`](/api/files/read-sandbox-file/) — Read a file from a running sandbox.
- [`PUT /v1/sandboxes/{sandbox}/files`](/api/files/write-sandbox-file/) — Create or overwrite a file in a running sandbox.

## computer

- [`GET /v1/sandboxes/{sandbox}/computer/screenshot`](/api/computer/get-computer-screenshot/) — Take a PNG screenshot of the sandbox's whole 1920x1080 desktop.
- [`POST /v1/sandboxes/{sandbox}/computer/actions`](/api/computer/run-computer-action/) — Click, double-click, drag, type, press keys or scroll on the sandbox's desktop.

## browser

- [`GET /v1/sandboxes/{sandbox}/browser/cdp`](/api/browser/connect-cdp/) — Connect to the sandbox's Chrome DevTools Protocol endpoint (WebSocket).
- [`POST /v1/sandboxes/{sandbox}/browser/cdp`](/api/browser/create-cdp-connection/) — Get a short-lived WebSocket URL for the sandbox's Chrome DevTools Protocol endpoint.

## edge

- [`GET /v1/sandboxes/{sandbox}/ports`](/api/edge/list-ports/) — List the sandbox's published ports.
- [`PUT /v1/sandboxes/{sandbox}/ports/{port}`](/api/edge/publish-port/) — Publish a sandbox port over HTTPS, or change its visibility.
- [`DELETE /v1/sandboxes/{sandbox}/ports/{port}`](/api/edge/unpublish-port/) — Stop publishing a port.
- [`POST /v1/sandboxes/{sandbox}/ports/{port}/link`](/api/edge/create-port-link/) — Get a short-lived login link for a published port.
- [`POST /v1/sandboxes/{sandbox}/desktop`](/api/edge/create-desktop-link/) — Get a link to the sandbox's desktop in the browser (noVNC).
- [`GET /v1/sandboxes/{sandbox}/ssh`](/api/edge/get-ssh-access/) — How to reach the sandbox over SSH through the gateway.

## ssh-keys

- [`GET /v1/ssh-keys`](/api/ssh-keys/list-ssh-keys/) — List the org's SSH public keys.
- [`POST /v1/ssh-keys`](/api/ssh-keys/create-ssh-key/) — Register an SSH public key for the org's sandboxes.
- [`DELETE /v1/ssh-keys/{key}`](/api/ssh-keys/delete-ssh-key/) — Remove an SSH public key.

## vault

- [`GET /v1/vault`](/api/vault/list-vault-entries/) — List the org's vault entries (values are never returned).

## templates

- [`GET /v1/templates`](/api/templates/list-templates/) — List system templates and the org's own templates.
- [`POST /v1/templates`](/api/templates/create-template/) — Save a sandbox's disk as a named template.
- [`GET /v1/templates/{template}`](/api/templates/get-template/) — Get a template.
- [`DELETE /v1/templates/{template}`](/api/templates/delete-template/) — Delete one of the org's templates.

## usage

- [`GET /v1/usage`](/api/usage/get-usage/) — Per-second usage from running intervals.

## system

- [`GET /healthz`](/api/system/get-health/) — Liveness check.
