03 · REST API

Bearer token.

View as Markdown

Every request to the local API must carry an Authorization header. The token is generated by the desktop app on first launch and stored locally; you control it.

Header shape

Authorization: Bearer <token from Settings → Developer>

Where to find your token

Open the desktop app → Settings → Integrations → Local API. The same panel lets you toggle the server on, change the port, copy the token to your clipboard, or rotate it. Rotating immediately invalidates every previous token and disconnects any MCP client or script that was using it.

Settings → Integrations → Local API panel showing the toggle, port, authentication token, and an example curl request.

Export it

# ~/.zshrc or ~/.bashrc
export DONUT_API_KEY="<paste from Settings → Developer>"
# ~/.config/fish/config.fish
set -gx DONUT_API_KEY "<paste from Settings → Developer>"
# Add to $PROFILE for persistence
$env:DONUT_API_KEY = "<paste from Settings → Developer>"

Use it

curl -sS http://127.0.0.1:10108/v1/profiles \
  -H "Authorization: Bearer $DONUT_API_KEY" | jq
const response = await fetch("http://127.0.0.1:10108/v1/profiles", {
  headers: { Authorization: `Bearer ${process.env.DONUT_API_KEY}` },
});
const { profiles } = await response.json();
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/profiles",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
profiles = response.json()["profiles"]
$response = Invoke-RestMethod -Uri "http://127.0.0.1:10108/v1/profiles" `
    -Headers @{ Authorization = "Bearer $env:DONUT_API_KEY" }

$response.profiles

What it grants

The token is uniform — every endpoint accepts the same bearer. Treat it like a password: anyone with the token can launch a profile, open URLs, and (on Pro) drive the browser. The server only listens on 127.0.0.1 so an attacker would need local access already, but if you’re running on a shared machine, keep the token out of shell history and shared scripts.

Missing or invalid token

Unauthenticated requests get a 401:

HTTP/1.1 401 Unauthorized
content-type: application/json

{
  "error": "missing or invalid bearer token"
}