HTTP API
All /api/* routes require a valid session cookie. /s/:token, /uploads/:name,
/og/:token.png, /api/share/:token and /healthz are public.
Auth
POST /api/login { password } → sets httpOnly session cookie
POST /api/logout
GET /api/me → { authed, app } | 401
Items (all five types)
GET /api/items → { items: [...] } (metadata only)
POST /api/items { type, title, folder?, language?, content }
GET /api/items/:id → { ...meta, content }
PUT /api/items/:id { title?, folder?, language?, content? }
DELETE /api/items/:id
type is one of code | draw | mind | doc | kanban. content is the editor's
serialized form (source text, Excalidraw/Mind Elixir/Kanban JSON, or doc HTML).
Folders
POST /api/folders { action: "create" | "rename" | "delete", name, newName? }
GET /api/folders → { folders: [...] }
Sharing
POST /api/items/:id/share { ttlDays } → { token, url, expiresAt }
ttlDays 0/absent = never; 1–30 = days
GET /api/items/:id/shares
DELETE /api/shares/:token
GET /api/share/:token (PUBLIC) → { type, title, language, content } | 404/410
History & backlinks
GET /api/items/:id/history → { commits: [...] }
GET /api/items/:id/history/:hash → { content } (file at that commit)
POST /api/items/:id/restore { hash }
GET /api/items/:id/backlinks → { backlinks: [...], outgoing: [...] }
Uploads & sync
POST /api/upload (image body) → { url: "/uploads/<file>" }
POST /api/sync → pull + commit + push, returns status
GET /api/sync/status → { enabled, state, lastSync, message }