API
The HTTP routes behind the studio and the command line: projects, transfers, assets, links, devices, agent turns, search and films.
The command line and the MCP server are clients of these routes. They live at https://puni.design/api and answer JSON. Prefer the command line or the MCP tools when one fits; the routes are here for the cases they do not cover.
#Signing requests
Send a token as a bearer: Authorization: Bearer puni_access_…. Tokens from Settings, from the command line's sign-in and from the OAuth door are the same kind. The route exchanges one for a short session on every call. The browser signs in with its own session cookie.
#Scenes
| Route | Method | Does |
|---|---|---|
/api/projects | GET, POST | List your scenes; create one from a document |
/api/projects/{id} | GET, PATCH | Read a scene with its revision (?metadata=1 for its summary and documentUrl); rename or archive |
/api/projects/{id}/checkpoints | GET, POST | List checkpoints; keep one now |
/api/projects/{id}/cover | POST | Set the cover for a saved document hash |
/api/projects/{id}/shares | GET, POST | List links; make one for a revision |
/api/projects/transfers | POST | Begin and finish a scene upload |
/api/assets | POST | Upload a small asset inline |
/api/assets/transfers | POST | Begin and finish a direct asset upload |
/api/assets/{id} | GET | Read an asset you own |
Writes carry the revision they expect. A stale revision answers 409.
#Links
| Route | Method | Does |
|---|---|---|
/api/share/{id} | GET | The link's public metadata |
/api/share/{id}/document | GET | The saved document the link points at |
/api/share/{id}/assets/{hash} | GET | An asset that document references |
/api/share/{id}/copy | POST | Remix into the caller's library |
/api/share/{id}/view | POST | Count a view, once per session |
#Devices and agents
| Route | Method | Does |
|---|---|---|
/api/device/connect, exchange, session, revoke | POST | The sign-in flow the command line runs |
/api/device/status, sessions | GET | A pending code; your connected devices |
/.well-known/oauth-protected-resource, oauth-authorization-server | GET | How a connector finds the sign-in door |
/api/oauth/authorize | GET | Start connector authorization; consent is a Puni page |
/api/oauth/register, token, revoke | POST | Register a client, exchange a grant, or revoke access |
/api/agent/turns | GET, POST | List turns with ?projectId={id}, or deliver one for a revision; no connected runner returns PUNI_RUNNER_REQUIRED |
/api/agent/turns?turnId={id} | GET | One turn with its events |
/api/agent/turns/{id}/cancel | POST | Stop a turn; edits already saved remain |
/api/projects/{id} | PATCH | Land one command batch on the revision you read, with a label; the scene keeps a checkpoint |
/api/agent/runner | GET, POST | Read presence; register or unregister a connected runner |
/api/agent/runner/turns | GET | List the signed-in owner's runner-delivered turns |
/api/agent/runner/turns/[id] | POST | Claim, heartbeat, complete, fail or release a turn with its runner capability |
/api/mcp | GET, POST, DELETE | The MCP server |
#Search, films, runtime
| Route | Method | Does |
|---|---|---|
/api/library/search | POST | Keyword or semantic search of your scenes |
/api/films/* | GET, POST | Film job uploads and downloads, when enabled |
/api/runtime | GET | The app's builds, for puni runtime |
#Errors
Product errors use JSON with an error sentence to show. A catalogued refusal adds a code to branch on and its detail, such as the revision a 409 conflict is now at. A 409 also carries conflict: true. A server fault answers 5xx with a code too, such as BACKEND_UNAVAILABLE, so a client knows to retry rather than change its request. The OpenAPI document lists every code and every status a refusal can answer with, including 422, 502 and 504. OAuth errors use error and may include error_description.
Limits: a scene document is 32 MB and an asset 64 MB. Ordinary MCP requests are capped at 768,000 bytes. upload_asset admits a larger base64 envelope for up to 8 MiB of decoded bytes; SVG retains its 2 MiB format cap. puni_compare_reference also admits a larger envelope for its bounded image input. Hosting proxies can impose smaller limits.
Inline scene and asset API transfers have a 4 MB budget. These transfer limits are separate from the MCP upload exception. Save a larger scene through /api/projects/transfers and upload a larger asset through /api/assets/transfers. A saved scene or checkpoint larger than that is refused inline with SCENE_READ_BY_URL: read it with ?metadata=1, download the documentUrl it names, and check the bytes against its sha256.
#OpenAPI
https://puni.design/api/openapi.json describes every route above as OpenAPI 3.1, generated from the routes and kept honest by a test. Point a client generator or an agent framework at it when neither MCP nor the command line fits.
Read MCP tools for the contract agents use first.
Was this useful?