Skip to main content

HTTP API

With api.enabled (the default), Vindue serves a control API on http://127.0.0.1:<api.port> (default 47725) — two faces on one server: REST for scripts and humans, MCP for AI clients.

Security model — no auth, by design​

The server binds to loopback only, allowlists the Host header (127.0.0.1/localhost — DNS-rebinding defense), and rejects any request carrying Origin or Sec-Fetch-Site headers: browsers always attach them (even on simple GETs), while curl/scripts/MCP clients never do — so a web page you visit cannot drive your windows.

Anything that can already run code as your user can use this API; it grants no new capability. (Pinned by tests in src-tauri/src/api.rs.)

Endpoints​

JSON in/out; errors are 400 + { "error": "…" }.

The full per-endpoint reference — parameters, request/response schemas, sample calls — is generated from the Rust source (utoipa annotations on the axum handlers) and pinned by a CI drift gate, so it always matches the code: Vindue control API reference →

Operations are grouped as state (live app state), tiling, config (merge-patch sections), shortcuts (key → region bindings), and meta — the server also serves its own live spec at GET /api/v1/openapi.json.

Examples​

curl -s 127.0.0.1:47725/api/v1/state | jq .
curl -s -X POST 127.0.0.1:47725/api/v1/tile -d '{"preset":"left_half"}'
curl -s -X POST 127.0.0.1:47725/api/v1/tile \
-d '{"preset":"top_right","app":"Safari","monitor":"DELL U2720Q (right)"}'
curl -s -X POST 127.0.0.1:47725/api/v1/tile \
-d '{"cells":{"startRow":0,"endRow":2,"startCol":1,"endCol":4}}'
curl -s -X PUT 127.0.0.1:47725/api/v1/shortcuts/Digit2 \
-d '{"monitor":null,"selection":{"startRow":0,"endRow":5,"startCol":3,"endCol":5}}'

Presets & cells​

Presets: full, left_half, right_half, top_half, bottom_half, top_left, top_right, bottom_left, bottom_right — computed proportionally (half(n) = max(1, round(n/2))), so they work on any grid.

cells are inclusive 0-based indices and must fit the current grid.

:::note Accessibility Tiling needs the same Accessibility grant as the panel; the error message says so when it's missing. :::

Ideas: shell aliases per layout, a "meeting mode" script that arranges browser + notes + terminal, Shortcuts.app automations, or letting Claude do it.