# API Reference All endpoints require login (session cookie or `Authorization: Bearer `) unless marked **(public)**. ## Health | Method | Path | Description | |--------|------|-------------| | GET | `/api/health` | Health check **(public)** | ## Auth | Method | Path | Description | |--------|------|-------------| | GET | `/api/auth/status` | `{has_users, registration_open, oauth_enabled, local_auth_enabled}` **(public)** | | POST | `/api/auth/register` | Register new user (first user becomes admin; 403 if registration closed or local auth disabled) | | POST | `/api/auth/login` | Login with username/password (403 if local auth disabled) | | POST | `/api/auth/logout` | Clear session | | GET | `/api/auth/me` | Current user info (includes `has_password: bool`) | | PUT | `/api/auth/password` | Change password `{current_password, new_password}` | | PUT | `/api/auth/email` | Change email `{email, password?}` (password required only for local-auth users) | | POST | `/api/auth/invalidate-sessions` | Bump `session_version` — evicts all other sessions, keeps current alive | | POST | `/api/auth/forgot-password` | Send password reset email `{email}` | | POST | `/api/auth/reset-password` | Reset password with token `{token, new_password}` | | GET | `/api/auth/oauth/login` | Initiate OIDC PKCE flow → redirect to provider | | GET | `/api/auth/oauth/callback` | OIDC callback — exchange code, find/create user, redirect to `/` | | GET | `/api/auth/invitation/:token` | Validate invitation token **(public)** | | POST | `/api/auth/register-with-invite` | Register with token `{token, username, password}` **(public)** | ## Notes | Method | Path | Description | |--------|------|-------------| | GET | `/api/notes` | List notes. Params: `q`, `tag`, `sort`, `order`, `limit`, `offset`, `project_id`, `milestone_id`, `parent_id`, `type` (`note`/`task`/`all`) | | POST | `/api/notes` | Create note `{title, body, tags?, status?, priority?, due_date?, project_id?, milestone_id?, parent_id?}` | | GET | `/api/notes/tags` | All tags (param: `q` for filter) | | POST | `/api/notes/suggest-tags` | LLM tag suggestions `{title, body, current_tags?}` → `{suggested_tags}` | | POST | `/api/notes/link-suggestions` | Detect note titles as plain text in body `{body, project_id, exclude_note_id}` → `[{note_id, title, count}]` | | GET | `/api/notes/by-title` | Resolve note by exact title (param: `title`) | | POST | `/api/notes/resolve-title` | Get-or-create note by title `{title}` (wikilink click) | | GET | `/api/notes/:id` | Get single note | | PUT | `/api/notes/:id` | Full update | | PATCH | `/api/notes/:id` | Partial update (same fields as PUT) | | DELETE | `/api/notes/:id` | Delete note | | POST | `/api/notes/:id/convert-to-task` | Set `status='todo'`, `priority='none'` | | POST | `/api/notes/:id/convert-to-note` | Clear `status`, `priority`, `due_date` | | POST | `/api/notes/:id/append-tag` | Add tag `{tag}` → updated note | | GET | `/api/notes/:id/backlinks` | Notes/tasks with `[[Title]]` references to this note | | GET | `/api/notes/:id/versions` | List note version history | | GET | `/api/notes/:id/versions/:vid` | Get a specific version | | GET | `/api/notes/:id/draft` | Get current AI draft | | PUT | `/api/notes/:id/draft` | Save AI draft | | DELETE | `/api/notes/:id/draft` | Delete AI draft | | POST | `/api/notes/assist` | Launch AI assist generation → 202 `{body, target_section?, instruction, whole_doc?}` | | GET | `/api/notes/assist/stream` | SSE stream for assist (Last-Event-ID reconnect; events: `chunk`, `done`, `error`) | ## Tasks | Method | Path | Description | |--------|------|-------------| | GET | `/api/tasks` | List tasks. Params: `q`, `tag`, `status`, `priority`, `due_before`, `due_after`, `sort`, `order`, `limit`, `offset` | | POST | `/api/tasks` | Create task (accepts `project` name string → resolved to `project_id`) | | GET | `/api/tasks/:id` | Get task (includes `parent_title`) | | PUT | `/api/tasks/:id` | Full update | | PATCH | `/api/tasks/:id/status` | Quick status update `{status}` | | DELETE | `/api/tasks/:id` | Delete task | | GET | `/api/tasks/:id/logs` | List work logs | | POST | `/api/tasks/:id/logs` | Create log `{content, duration_minutes?}` | | PATCH | `/api/tasks/:id/logs/:log_id` | Update log | | DELETE | `/api/tasks/:id/logs/:log_id` | Delete log | ## Projects & Milestones | Method | Path | Description | |--------|------|-------------| | GET | `/api/projects` | List projects (owned + shared) | | POST | `/api/projects` | Create project | | GET | `/api/projects/:id` | Get project with `milestone_summary` | | PATCH | `/api/projects/:id` | Update project | | DELETE | `/api/projects/:id` | Delete project | | GET | `/api/projects/:id/notes` | Notes + tasks in this project | | GET | `/api/projects/:id/milestones` | List milestones | | POST | `/api/projects/:id/milestones` | Create milestone | | PATCH | `/api/projects/:id/milestones/:mid` | Update milestone | | DELETE | `/api/projects/:id/milestones/:mid` | Delete milestone | ## Sharing | Method | Path | Description | |--------|------|-------------| | GET | `/api/projects/:id/shares` | List project shares | | POST | `/api/projects/:id/shares` | Create project share `{user_id?, group_id?, permission}` | | PATCH | `/api/projects/:id/shares/:sid` | Update permission | | DELETE | `/api/projects/:id/shares/:sid` | Remove share | | GET | `/api/notes/:id/shares` | List note shares | | POST | `/api/notes/:id/shares` | Create note share | | PATCH | `/api/notes/:id/shares/:sid` | Update permission | | DELETE | `/api/notes/:id/shares/:sid` | Remove share | | GET | `/api/shared-with-me` | All resources shared with the current user | ## Groups | Method | Path | Description | |--------|------|-------------| | GET | `/api/groups` | List all groups (admin only) | | POST | `/api/groups` | Create group `{name, description?}` | | PATCH | `/api/groups/:id` | Update group | | DELETE | `/api/groups/:id` | Delete group | | GET | `/api/groups/:id/members` | List members | | POST | `/api/groups/:id/members` | Add member `{user_id, role}` | | PATCH | `/api/groups/:id/members/:uid` | Update member role | | DELETE | `/api/groups/:id/members/:uid` | Remove member | ## Chat | Method | Path | Description | |--------|------|-------------| | GET | `/api/chat/conversations` | List conversations (params: `limit`, `offset`) | | POST | `/api/chat/conversations` | Create conversation `{title?, model?}` | | POST | `/api/chat/conversations/bulk-delete` | Delete multiple conversations `{ids: number[]}` | | GET | `/api/chat/conversations/:id` | Get conversation with all messages | | PATCH | `/api/chat/conversations/:id` | Update title or model | | DELETE | `/api/chat/conversations/:id` | Delete conversation (cascades to messages) | | POST | `/api/chat/conversations/:id/messages` | Start generation → 202. Body: `{content, context_note_id?, include_note_ids?, rag_project_id?, workspace_project_id?, think?}` | | GET | `/api/chat/conversations/:id/generation/stream` | SSE stream (Last-Event-ID reconnect; events: `context`, `chunk`, `tool_call`, `status`, `done`, `error`) | | POST | `/api/chat/conversations/:id/generation/cancel` | Cancel active generation | | POST | `/api/chat/messages/:id/save-as-note` | Save assistant message as note | | POST | `/api/chat/conversations/:id/summarize` | Summarize conversation → note | | GET | `/api/chat/status` | Ollama availability + model state `{ollama, model, default_model}` | | GET | `/api/chat/models` | List installed Ollama models (includes `loaded: bool`, `modified_at`) | | POST | `/api/chat/models/pull` | Pull model (SSE NDJSON progress) `{model}` | | POST | `/api/chat/models/delete` | Delete model `{model}` | | GET | `/api/chat/ps` | Currently loaded (hot) models | | POST | `/api/chat/warm` | Pre-load model into VRAM `{model}` → 202 | ## Quick Capture | Method | Path | Description | |--------|------|-------------| | POST | `/api/quick-capture` | Classify + create item from natural language `{text}` → `{success, type, message, data}` | ## Search | Method | Path | Description | |--------|------|-------------| | GET | `/api/search` | Semantic + keyword search across notes and tasks. Params: `q`, `type` (`note`/`task`/`all`), `limit` | ## Journal | Method | Path | Description | |--------|------|-------------| | GET | `/api/journal/config` | Get journal configuration (locations, temp_unit, prep schedule) | | PUT | `/api/journal/config` | Save journal configuration; live-reschedules the prep job | | GET | `/api/journal/today` | Get/create today's journal conversation + messages | | GET | `/api/journal/day/:iso` | Get a specific day's journal conversation (read-only) | | GET | `/api/journal/days` | List dates with journal content, newest first | | POST | `/api/journal/trigger-prep` | Force-regenerate today's prep (or `{date}` for a specific day) | | GET | `/api/journal/weather` | Cached weather rows; auto-refreshes stale rows in the background | | GET | `/api/journal/weather/current` | Live current conditions for the primary configured location | | POST | `/api/journal/weather/refresh` | Manual refresh of all configured locations | | POST | `/api/journal/weather/geocode` | Geocode place name `{query}` → `{lat, lon, label}` | | POST | `/api/journal/moments/:id/update` | Update a recorded moment | | DELETE | `/api/journal/moments/:id` | Delete a moment | ## Settings | Method | Path | Description | |--------|------|-------------| | GET | `/api/settings` | All settings as `{key: value}` | | PUT | `/api/settings` | Update settings `{key: value, ...}` | | GET | `/api/settings/models` | Installed models + defaults | | GET | `/api/settings/search` | Proxy SearXNG search (params: `q`) | ## API Keys | Method | Path | Description | |--------|------|-------------| | GET | `/api/api-keys` | List user's API keys | | POST | `/api/api-keys` | Create key `{name, scope}` → `{key, ...}` (key shown once) | | DELETE | `/api/api-keys/:id` | Revoke key | ## Scribe MCP The MCP tool surface is served at `POST /mcp` (streamable HTTP, Bearer auth) by the in-app server in `src/scribe/mcp/`. It is not a REST surface — see [API Keys and Scribe MCP](api-keys-and-mcp.md) for client configuration. ## Notifications | Method | Path | Description | |--------|------|-------------| | GET | `/api/notifications` | List notifications | | GET | `/api/notifications/count` | Unread count | | POST | `/api/notifications/:id/read` | Mark read | | POST | `/api/notifications/read-all` | Mark all read | ## Push | Method | Path | Description | |--------|------|-------------| | GET | `/api/push/vapid-public-key` | VAPID public key for subscription | | POST | `/api/push/subscribe` | Register push subscription | | DELETE | `/api/push/subscribe` | Unregister push subscription | ## Images | Method | Path | Description | |--------|------|-------------| | GET | `/api/images/:id` | Serve cached image **(no auth required — IDs are opaque SHA-256)** | ## Users | Method | Path | Description | |--------|------|-------------| | GET | `/api/users/search` | Search users by username/email prefix (param: `q`, min 2 chars, excludes self) | ## Export | Method | Path | Description | |--------|------|-------------| | GET | `/api/export` | Export data. Params: `format=markdown` (ZIP with `.md` + YAML frontmatter) or `format=json` | ## Admin | Method | Path | Description | |--------|------|-------------| | GET | `/api/admin/backup` | Export backup (`?scope=user` for own data; full requires admin) | | POST | `/api/admin/restore` | Restore from JSON backup | | GET | `/api/admin/users` | List all users | | DELETE | `/api/admin/users/:id` | Delete user (cannot delete self) | | GET | `/api/admin/registration` | Get registration open/closed state | | PUT | `/api/admin/registration` | Toggle registration `{open: bool}` | | POST | `/api/admin/invitations` | Create invitation `{email}` → sends email | | GET | `/api/admin/invitations` | List pending invitations | | DELETE | `/api/admin/invitations/:id` | Revoke invitation | | GET | `/api/admin/logs` | Log entries. Params: `category`, `user_id`, `search`, `date_from`, `date_to`, `limit`, `offset` | | GET | `/api/admin/logs/stats` | Log category counts | | GET | `/api/admin/base-url` | Get base URL setting | | PUT | `/api/admin/base-url` | Set base URL `{base_url}` | | GET | `/api/admin/smtp` | Get SMTP config (password masked) | | PUT | `/api/admin/smtp` | Save SMTP config | | POST | `/api/admin/smtp/test` | Send test email `{recipient}` |