Skip to content

API

Method Path Description
POST /sandboxes Create a sandbox (name; optional runtime like dind, template like starter, compose (your own compose text instead of the template's; its before_script and defaults still apply), idle_timeout like 30m, deep_sleep_after like 7d or off, ssh_keys (extra SSH public keys for this sandbox only), cpus like 2, memory like 4g, create_inner_stack: false for no template stack)
GET /sandboxes List all sandboxes
GET /sandboxes/summary How many sandboxes: quota, total, free, running, asleep, deep_sleep, archived; your own (and server_full), or for the admin the whole server, by_owner, server_limit / server_used and resources (not with a token limited to one sandbox)
GET /sandboxes/:name Get sandbox details
GET /sandboxes/:name/compose The starter stack deployed into the sandbox (compose YAML), secrets masked (Starter stack… in the UI)
PATCH /sandboxes/:name Change idle_timeout and/or deep_sleep_after (see Sleep and wake), cpus and/or memory (see CPU and memory)
POST /sandboxes/:name/start Wake a sandbox, also from deep sleep (Wake in the UI); 409 at the owner's limit with reason and running; {"sleep": "<name>"} puts that running one to sleep first
POST /sandboxes/:name/stop Put a sandbox to sleep now (Sleep in the UI)
POST /sandboxes/:name/deep-sleep Put a sandbox into deep sleep now, also a running one (Deep sleep now on the panel's Settings tab)
POST /sandboxes/:name/keep-awake Start a running sandbox's sleep countdown over (Reset next to Sleeps in); 409 if it is not running
POST /sandboxes/:name/export A zip for coding agents: a new token for the sandbox, its Docker client keys, a README (owner/admin; not with a token limited to one sandbox); docker: false without the keys, format: "env" the p7y.env text
POST /sandboxes/:name/docker-keys New Docker access certificates (Enable / Rotate Docker keys…); restarts the sandbox
GET /sandboxes/:name/registry The sandbox's images in the registry, with secret-scan results
DELETE /sandboxes/:name/registry/:app/:digest Delete one version of an image
POST /sandboxes/:name/restart Restart a sandbox
GET /sandboxes/:name/files List a folder of the sandbox's files (path, default /root): /root, /home, /srv and /opt, the folders kept over a deep sleep, and the apps' volumes; the sandbox must be running (409 not_running otherwise). See Files
GET /sandboxes/:name/files/content Download a file (path), or a folder as a tar
PUT /sandboxes/:name/files/content Upload a file to path (the body is the file; its folder must exist), up to FILES_MAX_UPLOAD
GET /sandboxes/:name/files/text A text file's content as JSON (UTF-8, up to 1 MB): for agents
POST /sandboxes/:name/files/mkdir Create a folder ({"path": "/srv/data"})
DELETE /sandboxes/:name/files Delete a file or a folder (path), not the four folders themselves (nor a volume's folder)
GET /sandboxes/:name/volumes The volumes of the apps in the sandbox's own Docker: name, path (for the routes above), project, containers that use it
DELETE /sandboxes/:name Archive the sandbox, then remove it (Archive… in the UI; see Delete = archive)
GET /runtimes List the runtimes new sandboxes may use (name, description, default; only those in ALLOWED_RUNTIMES when it is set)
GET /templates List the templates (name, description, default)
GET /ssh-keys Your SSH public keys (id, name, type, fingerprint, created_at)
POST /ssh-keys Add a public key (key, optional name); it lets you into all your sandboxes with SSH
GET /sandboxes/:name/ssh-key The sandbox's generated SSH private key (download)
POST /sandboxes/:name/ssh-key Generate it for an SSH sandbox that has none yet
GET /sandboxes/:name/terminal The browser terminal (page; the same path as a websocket: the shell)
GET /sandboxes/:name/logs The logs page (signed-in browsers)
GET /sandboxes/:name/logs/stream The sandbox's app logs as Server-Sent Events: the last 100 lines of every container, then live (token too)
DELETE /ssh-keys/:id Delete one of your keys (it stops working at once)
GET /templates/:name A template's compose.yaml as written (compose), to show or edit before a create
GET /me Who you are signed in as, your running sandboxes and limit, and server_places: the sandbox places on the server, used and limit (null without a server limit)
GET /tokens List your personal access tokens (hint: the token's start and end, e.g. p7y_aB3x…9fQz; null for tokens made before hints)
POST /tokens Mint a personal access token (name, optional expires_in like 30d/90d/never)
DELETE /tokens/:id Revoke a personal access token

All endpoints require Authorization: Bearer <ADMIN_TOKEN | personal token> or a signed-in browser session. Users only see their own sandboxes.

OpenAPI and clients

The whole API is described as OpenAPI 3.0 at /swagger.json (no token needed to read it), and you can try it in Swagger UI at /swagger. There is no official SDK yet; generate a client in your language from that document instead, for example typed TypeScript:

curl -s https://p7y.example.com/swagger.json -o p7y.json
npx openapi-typescript p7y.json -o p7y.d.ts   # use it with openapi-fetch

or any language openapi-generator supports (openapi-generator-cli generate -i p7y.json -g python -o p7y-client). The document's version is Purgatory's own, so regenerate after an upgrade.

More reading: architecture diagrams, how agents deploy, comparison with other sandbox platforms, roadmap.