Grove API Reference
> Build identity is per-release โ check grove version or /api/version.
Base URL: http://:5678
Authentication Model
Every request goes through check_dashboard_auth(). Rules (first match wins):
| Path |
Auth required |
Matches PUBLIC_PREFIXES (see below) |
None โ no auth |
/portal/, /site/, /invite/* |
Portal session or public (audience-gated internally) |
/api/* with valid X-Grove-Secret header |
Peer-secret auth (global or per-peer derived) |
Any path with session['authenticated'] |
Dashboard session auth |
portal_role == 'admin' on /api/* paths |
Portal-admin session (tailnet only) |
Localhost + valid X-Grove-Secret |
CLI local auth (any route) |
Public-edge restriction (WAN-facing nodes, e.g. familynook): nginx sets X-Grove-Public-Edge: 1. The owner session and portal-admin session are both rejected over the public edge. Owner dashboard + admin /api/* are tailnet-only. The public face serves portal, site, invite, relay, and PUBLIC_PREFIXES APIs only.
PUBLIC_PREFIXES (no auth required)
/api/chunk-inventory /api/serve-chunk/ /api/receive-grant
/api/receive-chunks /api/receive-manifests /api/serve-chunk-peer/
/api/reachability /api/tombstone-action /api/manifest-inventory
/api/serve-manifest/ /api/grants-for/ /api/revoke-grant
/api/pubkey /api/gc-manifests /api/peer-request
/api/friend-request /api/friend-accept /api/version
/api/exchange-secret /api/health /api/busy-status
/api/relay/ /api/ai/status /api/invite/
/api/grove-binary/
/login /favicon.ico /manifest.json /sw.js /icon-192 /icon-512
/splash /invite/ /docs /reset-password /portal
/.well-known/ /install.sh /releases/ /site/
Auth tiers in this doc
- Public โ in PUBLIC_PREFIXES, no auth
- Peer โ requires
X-Grove-Secret (global or per-peer ECDH-derived) + optionally X-Grove-Sender:
- Dashboard โ session cookie (owner login) or peer-secret on
/api/*
- Owner โ
verify_owner_request(): dashboard session and not over public edge
- Portal โ
/portal/login session (session['portal_user']); role = portal | admin | owner
Page Routes (HTML)
| Route |
Auth |
Notes |
GET / |
Public |
Landing / Home tab |
GET /dashboard |
Dashboard |
Main dashboard |
GET /files |
Dashboard |
Files tab |
GET /feed |
Dashboard |
Feed (files shared with you) |
GET /browse |
Dashboard |
Redirects to /?path= or /dashboard |
GET /grove-files |
Dashboard |
Power-user global file list with replication tiers |
GET /login POST /login |
Public |
Dashboard login |
POST /logout |
Dashboard |
End dashboard session |
GET /setup POST /setup |
Public (localhost recovery) |
First-boot setup or password recovery |
GET /splash |
Public |
Splash/loading page |
GET /docs GET /docs/ GET /docs/ |
Public |
Embedded docs |
GET /reset-password/ |
Public |
Password reset landing |
POST /reset-password//submit |
Public |
Submit new password |
GET /restart |
Public (redirects to POST flow) |
Legacy restart shim |
GET /invite/ |
Public |
Invite landing page or install script (curl UA) |
GET /site// GET /site// |
Audience-gated |
Site renderer (public/observers/specific) |
Core Info APIs
| Route |
Method |
Auth |
Description |
/api/version |
GET |
Public |
Build hash, build time, started timestamp, file sizes |
/api/pubkey |
GET |
Public |
signing_pubkey (Ed25519) + encryption_pubkey (X25519) |
/api/health |
GET |
Public |
Disk, chunk count, peer count โ used by peer health checks |
/api/status |
GET |
Dashboard |
Cell status overview: chunks, peers, manifests, bounty |
/api/busy-status |
GET |
Public |
Idle/busy signal for watchdog (tasks, sync, last request) |
/api/breaker-status |
GET |
Dashboard |
Per-peer circuit breaker debug state |
/api/source |
GET |
Dashboard |
Serve source files for update/inspection |
/api/tasks |
GET |
Dashboard |
Active + recently-finished background jobs |
/api/update-status |
GET |
Dashboard |
Current build + pending update info |
/api/update-install |
POST |
Owner |
Apply staged update and restart |
/api/update-dismiss |
POST |
Owner |
Discard pending update |
/api/update-fleet-status |
GET |
Dashboard |
Build status across all peers |
File Operations
Dashboard file actions (session auth)
| Route |
Method |
Auth |
Description |
POST /upload |
POST |
Dashboard |
Upload files to GroveHome. Multipart files field |
GET /download |
GET |
Dashboard |
Download file. Query: ?path= or ?manifest= |
POST /download/ |
POST |
Dashboard |
Legacy: download by manifest name to Downloads/ |
GET /view/ |
GET |
Dashboard |
Inline view (images, video, audio). Honors HTTP Range for media: 206/200/416 with Accept-Ranges/Content-Range, streaming only the overlapping 4MB chunks (instant seek) |
GET /preview |
GET |
Dashboard |
Inline preview from GroveHome. Query: ?path= |
POST /add-to-grove |
POST |
Dashboard |
Ingest a file path as a Grove-tracked file |
POST /add-to-grove/ |
POST |
Dashboard |
Save shared file from manifest โ GroveHome โ ingest โ sync |
POST /add-local |
POST |
Dashboard |
Add a local file reference to Grove |
GET /static/sticker// |
GET |
Public |
Serve pixel-art sticker assets |
File / folder management
| Route |
Method |
Auth |
Description |
POST /api/file/move |
POST |
Dashboard |
Move file within GroveHome; updates manifest source_path. JSON: {source, dest_dir} |
POST /api/file/rename |
POST |
Dashboard |
Rename a file in place; updates manifest. JSON: {path, new_name} |
POST /api/file/delete-untracked |
POST |
Dashboard |
Permanently delete an untracked file inside GroveHome. JSON: {path} |
POST /api/file/decrypt-preview |
GET |
Dashboard |
Decrypt a file for inline preview |
GET /api/file/decrypt-stream |
GET |
Dashboard |
Streaming decrypt for large files |
POST /api/folder/create |
POST |
Dashboard |
Create a folder under GroveHome. JSON: {path} |
POST /api/folder/rename |
POST |
Dashboard |
Rename a folder; updates manifests. JSON: {path, new_name} |
POST /api/folder/move |
POST |
Dashboard |
Move a folder within GroveHome. JSON: {source, dest_dir} |
POST /api/folder/delete |
POST |
Dashboard |
Delete a folder and its contents |
POST /api/folder/encrypt |
POST |
Dashboard |
Encrypt all files in a folder with a password (local-only vault). JSON: {path, password} |
POST /api/folder/unlock |
POST |
Dashboard |
Unlock an encrypted folder for this session. JSON: {path, password} |
POST /api/folder/decrypt |
POST |
Dashboard |
Permanently decrypt an encrypted folder back to plaintext. JSON: {path, password?} |
POST /api/folder/lock |
POST |
Dashboard |
Lock (evict in-memory key for) an encrypted folder |
POST /api/folder-role |
POST |
Owner |
Set/clear folder role. Form: {path, role, slug, audience, audience_list[]}. Valid role: photos, notes, site, audio, video, mixed, or "" (revert to auto-detect). Persisted in folder_roles.json |
GET /api/folder-list |
GET |
Dashboard |
List folders in GroveHome |
GET /api/folder-manifests |
POST |
Dashboard |
Get manifests under a folder |
GET /api/browse |
GET |
Dashboard |
Browse GroveHome directory tree |
POST /api/archive-preflight |
POST |
Dashboard |
Check if archiving a file is safe |
POST /archive-by-path |
POST |
Dashboard |
Remove local copy of a file (keep on peers). Form: {path} |
POST /archive/ |
POST |
Dashboard |
Archive by manifest name |
POST /remove-from-grove/ |
POST |
Dashboard |
Remove a file from Grove tracking |
Batch operations
| Route |
Method |
Auth |
Description |
POST /batch-add-to-grove |
POST |
Dashboard |
Add multiple shared files to Grove |
POST /batch-remove-local |
POST |
Dashboard |
Remove local copies of multiple files |
POST /batch-remove-grove |
POST |
Dashboard |
Remove multiple files from Grove tracking |
POST /batch-delete |
POST |
Dashboard |
Bulk delete files |
Recycle bin
| Route |
Method |
Auth |
Description |
GET /api/recycle-bin/list |
GET |
Dashboard |
List pending-delete files with expiry countdown |
POST /api/recycle-bin/restore/ |
POST |
Dashboard |
Restore a file from the 24h recycle bin |
POST /api/recycle-bin/force-delete/ |
POST |
Dashboard |
Skip 24h wait; hard-delete immediately |
POST /api/recycle-bin/empty |
POST |
Dashboard |
Bulk hard-delete everything in recycle bin |
Soft-delete / tombstone
| Route |
Method |
Auth |
Description |
POST /api/delete-everywhere/ |
POST |
Dashboard |
Send file to 24h recycle bin (soft delete) |
POST /api/delete |
POST |
Dashboard |
Delete a file |
POST /delete-permanently |
POST |
Dashboard |
Permanently delete a file |
POST /api/tombstone-action |
POST |
Peer |
Receive a signed TombstoneAction from the file's creator |
POST /api/unlink-local |
POST |
Dashboard |
Delete an untracked file inside GroveHome. JSON: {path} |
Sync / restore
| Route |
Method |
Auth |
Description |
POST /sync |
POST |
Dashboard |
Sync a specific file to peers. Form: {path} |
POST /sync-all |
POST |
Dashboard |
Sync all files to peers |
POST /restore/ |
POST |
Dashboard |
Restore a file from peers (pull chunks) |
POST /restore-all |
POST |
Dashboard |
Restore all missing files from peers |
POST /restore-version |
POST |
Dashboard |
Restore a specific version of a file |
POST /fetch-remote |
POST |
Dashboard |
Fetch a file from a specific remote peer |
GET /api/serve-chunk/ |
GET |
Dashboard |
Serve a chunk locally (owner-side) |
GET /api/history |
GET |
Dashboard |
Get version history for a file. Query: ?path= |
Watched folders / ingest
| Route |
Method |
Auth |
Description |
GET /api/watched-folders |
GET |
Dashboard |
List all watched folders with exists flag |
POST /watch |
POST |
Dashboard |
Start watching a folder. JSON or form: {path} |
POST /unwatch |
POST |
Owner |
Stop watching a folder. JSON or form: {path} |
POST /batch-watch |
POST |
Dashboard |
Watch multiple folders. JSON: {paths: [...]} |
POST /batch-unwatch |
POST |
Dashboard |
Unwatch multiple folders. Form: paths[] |
POST /api/watch-scan |
POST |
Owner |
Scan a folder and return stats before watching. JSON: {path} |
POST /api/watch-start |
POST |
Owner |
Add folder to watch list + optionally queue ingest. JSON: {path, ingest_existing} |
GET /api/ingest-status |
GET |
Dashboard |
List all active/recent ingest jobs |
POST /api/ingest-pause |
POST |
Dashboard |
Pause an ingest job. JSON: {job_id} |
POST /api/ingest-resume |
POST |
Dashboard |
Resume a paused ingest job. JSON: {job_id} |
POST /api/ingest-cancel |
POST |
Dashboard |
Cancel an ingest job. JSON: {job_id} |
POST /api/ingest-throttle |
POST |
Dashboard |
Set ingest delay. JSON: {job_id, delay_ms} |
GET /api/ingest-interrupted |
GET |
Dashboard |
List jobs interrupted by a restart |
Media renderer (audio + video)
Folders annotated (or auto-detected) as audio/video render as a streaming media library. Streaming uses the chunk-wise, Range-aware spine (_manifest_range_response) so seeking a large FLAC/movie decrypts only the overlapping 4MB chunks. Auto-detection: โฅ3 files of a kind AND โฅ50% of the folder (_detect_folder_role).
| Route |
Method |
Auth |
Description |
GET /api/media-library |
GET |
Dashboard |
Folder-derived media library tree (owner). Query: `?path=&kinds=audio\ |
video\ |
audio,video (default both). Stream URLs point at /view/` |
GET /api/audio-library |
GET |
Dashboard |
Back-compat alias of /api/media-library |
GET /portal/media-library |
GET |
Portal |
Same shape, scoped to the account's visible files. Query: ?path=&kinds=โฆ. Stream URLs point at /portal/stream/ |
GET /portal/audio-library |
GET |
Portal |
Back-compat alias of /portal/media-library |
GET /portal/stream/ |
GET |
Portal |
Range-aware, chunk-wise media stream of a portal-visible file (206/200/416); same access + key resolution as /portal/download |
Library tree JSON ({ok, count, library}): library is a nested tree of {kind: 'dir'\|'track', โฆ}. dir nodes carry name + children. track nodes carry: title, name, manifest, stream (URL), size, media ('audio'\|'video'), format, lossless (bool), web_playable (bool).
Sharing
| Route |
Method |
Auth |
Description |
POST /share |
POST |
Dashboard |
Share file(s) with peers. Form: {manifest, peer} |
POST /unshare |
POST |
Dashboard |
Revoke sharing. Form: {manifest, peer} |
POST /reshare |
POST |
Dashboard |
Re-share an updated version. Form: {manifest} |
GET /api/shared-folders |
GET |
Dashboard |
Get auto-share folder configuration |
POST /api/shared-folders |
POST |
Dashboard |
Set auto-share folder configuration |
POST /api/share-grant |
POST |
Peer |
Receive a share grant from a peer cell (portal user access). JSON accepts rel_path (GroveHome-relative, plaintext, per-recipient) stored on the grant so a portal account can rebuild the folder tree for ยง7-opaque manifests |
POST /api/folder-manifests |
POST |
Dashboard |
List manifests under a folder path |
POST /api/portal/show-in-portal |
POST |
Dashboard |
Toggle file(s) visible in owner's remote portal. JSON: `{manifest\ |
folder, action: on\ |
off\ |
toggle}` |
GET /api/portal/show-in-portal/list |
GET |
Dashboard |
List manifests currently shown in the owner's remote portal |
Peers / Sync (P2P)
These are called between cells during sync. Most require X-Grove-Secret + X-Grove-Sender.
Chunk transport
| Route |
Method |
Auth |
Description |
GET /api/chunk-inventory |
GET |
Public (Peer) |
All chunk hashes this cell holds. Returns {chunks, count, total_size} |
POST /api/receive-chunks |
POST |
Public (Peer) |
Push chunks here. Multipart form: each field is {hash}: (data, "application/octet-stream") |
POST /api/receive-chunks-b64 |
POST |
Peer |
Push chunks as base64 JSON (relay-transport alternative) |
GET /api/serve-chunk-peer/ |
GET |
Public (Peer) |
Download a chunk by hash |
POST /api/delete-chunks |
POST |
Peer |
Delete chunks. JSON: {hashes: [...]} |
POST /api/purge-chunks |
POST |
Peer |
Purge chunks for a departing peer. JSON: {pubkey, chunks, action: "purge"} |
Manifest transport
| Route |
Method |
Auth |
Description |
GET /api/manifest-inventory |
GET |
Public (Peer) |
All manifest filenames. Returns {manifests: [...]} |
POST /api/receive-manifests |
POST |
Public (Peer) |
Push manifests here. JSON array of manifest objects |
GET /api/serve-manifest/ |
GET |
Public (Peer) |
Download a specific manifest file |
POST /api/delete-manifests |
POST |
Peer |
Delete specific manifests by name (test cleanup). JSON: {names: [...]} |
POST /api/gc-manifests |
POST |
Public (Peer) |
Creator-scoped manifest GC โ drops manifests by creator_pubkey + optional prefix |
Grant transport
| Route |
Method |
Auth |
Description |
GET /api/grants-for/ |
GET |
Public (Peer) |
Get grants created by a pubkey (for sync) |
POST /api/receive-grant |
POST |
Public (Peer) |
Push a share grant here |
POST /api/revoke-grant |
POST |
Public (Peer) |
Revoke a grant. Requires X-Grove-Sender == granted_by |
Network / routing
| Route |
Method |
Auth |
Description |
GET /api/reachability POST /api/reachability |
GET/POST |
Public (Peer) |
Exchange reachability lists |
GET /api/routing-table |
GET |
Dashboard |
Computed routing table |
GET /api/route-speeds |
GET |
Dashboard |
Routes to all peers with speeds and selected route |
POST /api/benchmark |
POST |
Dashboard |
Trigger manual route benchmark |
GET /api/opp-sync-status |
GET |
Dashboard |
Background opportunistic sync status |
GET /api/peer-speeds |
GET |
Dashboard |
Peer speed measurements and rankings |
GET /api/peer-health |
GET |
Dashboard |
Peer reliability + probe history |
GET /api/peer-detail/ |
GET |
Dashboard |
Detailed stats for one peer |
POST /api/exchange-secret |
POST |
Public |
Per-peer ECDH secret handshake (v0.4.1+) |
POST /api/peer-leaving |
POST |
Peer |
Fast hint that a peer is going away (signed tombstone does the actual purge) |
GET /api/replication-status |
GET |
Dashboard |
Under-replicated file count + fix panel HTML |
GET /api/replication-summary |
GET |
Dashboard |
Owner-scoped or global replication factor summary |
GET /api/replication-health |
GET |
Dashboard |
Per-chunk factor breakdown |
GET /api/network-health |
GET |
Dashboard |
Fleet-wide health overview |
Relay
| Route |
Method |
Auth |
Description |
GET /api/relay/status |
GET |
Public |
Relay connection status + host stats |
POST /api/relay/allowed-peers |
POST |
Dashboard |
Add/remove extra relay allowed peers. JSON: `{action: add\ |
remove, pubkey}` |
GET /api/relay/preferences POST /api/relay/preferences |
GET/POST |
Dashboard |
Read/write relay picker preferences. POST body: {preferred: [...], avoid: [...]} |
GET /api/relay/contribution |
GET |
Dashboard |
This cell's relay contribution stats (messages/bytes forwarded) |
UDP punch
| Route |
Method |
Auth |
Description |
GET /api/udp/status |
GET |
Dashboard |
UDP hole punch status (listening, port, external addr, connections) |
POST /api/udp/punch |
POST |
Dashboard |
Initiate a hole punch to a peer. JSON: {pubkey} |
Peer Management
| Route |
Method |
Auth |
Description |
POST /peers/add |
POST |
Dashboard |
Add a peer. Form: {host, port, user} |
POST /peers/remove |
POST |
Dashboard |
Remove a peer. Form: `{host, mode: list-only\ |
and-files}` |
POST /peers/favorite |
POST |
Dashboard |
Toggle favorite status. Form: {user} |
POST /peers/accept |
POST |
Dashboard |
Accept a pending peer connection |
POST /peers/deny |
POST |
Dashboard |
Deny a pending peer connection |
POST /friends/add |
POST |
Dashboard |
Promote peer to friend. Form: {host} |
POST /friends/remove |
POST |
Dashboard |
Demote friend to peer. Form: {host} |
POST /friends/accept |
POST |
Dashboard |
Accept a friend request |
POST /friends/deny |
POST |
Dashboard |
Deny a friend request |
POST /api/peer-request |
POST |
Public (Peer) |
Initiate peer pairing request |
POST /api/peer-accept |
POST |
Dashboard |
Accept a peer pairing request |
POST /api/peer-remove |
POST |
Peer |
Peer-authenticated peer removal |
POST /api/friend-request |
POST |
Public (Peer) |
Send a friend request |
GET /api/friend-check POST /api/friend-check |
GET/POST |
Public |
Check friend status between two pubkeys |
POST /api/friend-accept |
POST |
Public (Peer) |
Accept a friend request |
POST /api/friend-remove |
POST |
Peer |
Remove a friend |
GET /api/peer-storage-caps POST /api/peer-storage-caps |
GET/POST |
Dashboard |
Get or set storage capacity caps per peer |
POST /api/peers/set |
POST |
Peer |
Replace peer list (fleet config management) |
POST /api/peer/rename |
POST |
Dashboard |
Rename a peer. JSON: {pubkey, name} |
POST /set-peer-cap |
POST |
Dashboard |
Set storage cap for a peer |
POST /set-primary |
POST |
Dashboard |
Set primary host for a peer |
GET /api/integrity |
GET |
Dashboard |
Last integrity sweep results |
POST /api/integrity/sweep |
POST |
Dashboard |
Trigger immediate integrity check. JSON: {sample_size?} |
Peer discovery / recommendations
| Route |
Method |
Auth |
Description |
GET /api/discoverable-peers |
GET |
Peer |
Return this cell's peers for network discovery |
GET /api/discovery |
GET |
Dashboard |
Get cached network discovery results |
POST /api/discovery/scan |
POST |
Dashboard |
Trigger network discovery scan. JSON: {max_hops?} |
POST /api/discovery/add |
POST |
Dashboard |
Add a discovered peer. JSON: {pubkey} |
POST /api/recommend |
POST |
Peer |
Receive a peer recommendation from a trusted peer |
GET /api/recommendations |
GET |
Dashboard |
List pending peer recommendations |
POST /api/recommendations/accept |
POST |
Dashboard |
Accept a peer recommendation. JSON: {pubkey} |
POST /api/recommendations/deny |
POST |
Dashboard |
Deny a peer recommendation. JSON: {pubkey} |
Invite System
| Route |
Method |
Auth |
Description |
POST /api/invite/create |
POST |
Dashboard |
Create an invite. JSON: {message, name, bounty} โ {ok, token_id, url} |
GET /api/invite/list |
GET |
Dashboard |
List all invites with status |
POST /api/invite/revoke |
POST |
Dashboard |
Revoke a token. JSON: {token_id} |
POST /api/invite/receive |
POST |
Dashboard |
Receive an incoming invite from a peer |
GET /invite/ |
GET |
Public |
Invite landing page (browser) or install script (curl/wget) |
POST /api/invite//accept |
POST |
Public |
Accept invite (install script). JSON: {pubkey, self_name} |
POST /invite//download |
POST |
Public |
Download install script with name baked in |
POST /invite//portal-signup |
POST |
Public |
Sign up for a portal account via invite |
GET /api/grove-binary/ |
GET |
Public |
Serve Grove source files for installation |
GET /install.sh |
GET |
Public |
Serve install script |
GET /releases/latest/ |
GET |
Public |
Serve release files (grove.py, web.py, etc.) |
AI (GroveAI)
/api/ai/status is Public (peer-discovery shape); all other AI endpoints require Dashboard auth unless noted.
Status and configuration
| Route |
Method |
Auth |
Description |
GET /api/ai/status |
GET |
Public |
AI capability, hardware, model info, e2e, timeout_s, has_local_model |
GET /api/ai/tiers |
GET |
Dashboard |
Available model tiers (Low/Mid/High) with host, params, timeout |
GET /api/ai/network |
GET |
Dashboard |
AI status across the fleet (deduplicated by peer name) |
POST /api/ai/setup |
POST |
Dashboard |
Multi-action: detect / models / download / download_status / switch / delete / enable / disable / set_peer_policy / build_runtime / build_status / set_default_tier / set_hf_token / hf_search / hf_files / download_hf / benchmark / benchmark_status / benchmark_results |
GET /api/ai/hf-token-status |
GET |
Dashboard |
Whether a HuggingFace token is configured |
POST /api/ai/use-model |
POST |
Dashboard |
BYOG: copy a .gguf from any path into the models folder and activate it. JSON: {path, filename} |
GET /api/ai/reindex |
GET |
Dashboard |
Rebuild the RAG index from local .md files and grove.py docstrings |
Chat
| Route |
Method |
Auth |
Description |
POST /api/ai/chat |
POST |
Dashboard |
Send a message; routes to best available LLM. JSON: {text, tier?, history?} |
POST /api/ai/chat/result |
POST |
Dashboard |
Poll for async chat result. JSON: {request_id} |
GET /api/ai/chat/history |
GET |
Dashboard |
Retrieve chat history |
POST /api/ai/chat/clear |
POST |
Dashboard |
Clear chat history |
POST /api/ai/proxy |
POST |
Peer |
Proxy a chat request to this cell's AI (E2E encrypted payload). JSON: {payload, sender_pubkey} |
Image generation (Mac only โ requires stable-diffusion-webui)
| Route |
Method |
Auth |
Description |
GET /api/ai/image/status |
GET |
Dashboard |
Image gen availability, model, backend status |
POST /api/ai/image/generate |
POST |
Owner |
Enqueue image-gen job. JSON body (text-to-image) or multipart with init_image + payload JSON (img2img). Returns {job_id} immediately |
GET /api/ai/image/jobs |
GET |
Dashboard |
List all image-gen jobs (terminal jobs expire after 5 min) |
GET /api/ai/image/job/ |
GET |
Dashboard |
Status of a single job |
POST /api/ai/image/cancel-queue |
POST |
Dashboard |
Cancel queued (not yet running) image-gen jobs |
Home Tab
| Route |
Method |
Auth |
Description |
GET /api/home/insights |
GET |
Dashboard |
Grove age, file-type composition, activity sparkline (cached 30s) |
GET /api/home/replication |
GET |
Dashboard |
Replication card data for Home tab |
GET /api/home/peers |
GET |
Dashboard |
Authoritative peer list with health, live chunk counts, routing |
GET /api/home/peer/ |
GET |
Dashboard |
Detail for a single peer (Home peer-card modal) |
Storage / Drives
| Route |
Method |
Auth |
Description |
GET /api/drives |
GET |
Dashboard |
All configured drives: mode, online, chunks, free/total bytes |
GET /api/drives/available |
GET |
Dashboard |
Mounted filesystems suitable for a new drive target |
POST /api/drives/scan |
POST |
Dashboard |
Scan a drive path before adding it |
POST /api/drives/add |
POST |
Dashboard |
Add a storage drive (mirror, ingest, backup). JSON: {path, mode, target_folder?} |
POST /api/drives/start-ingest |
POST |
Dashboard |
Start ingest for a drive. JSON: {path} |
POST /api/drives/stop-ingest |
POST |
Dashboard |
Stop ingest for a drive. JSON: {path} |
POST /api/drives/remove |
POST |
Dashboard |
Remove a configured drive. JSON: {path} |
GET /api/grove-home-status |
GET |
Dashboard |
GroveHome disk usage and status |
GET /api/placement |
GET |
Dashboard |
Replication health summary |
GET /api/placement/context |
GET |
Dashboard |
Owner placement summary (desired_factor, min, total_chunks) |
POST /api/set-redundancy |
POST |
Owner |
Set desired/minimum replication factors. Form: {desired, min} |
GET /api/owner-policy POST /api/owner-policy |
GET/POST |
Dashboard |
Get or set owner replication policy. POST JSON: {desired_factor, min_factor} |
GET /api/bounty |
GET |
Dashboard |
Full bounty status including peer history |
POST /api/bounty/accrue |
POST |
Dashboard |
Trigger manual bounty accrual |
Maintenance
| Route |
Method |
Auth |
Description |
POST /api/gc |
POST |
Dashboard |
Garbage collect orphaned chunks. Form: {force: true/false} |
POST /api/tidy |
POST |
Dashboard |
Full tidy chain (peers dedup, doctor, gc, vacuum). Form: {force, skip} |
GET /api/prune-preview |
GET |
Dashboard |
Preview what pruning would remove |
POST /api/prune-excess |
POST |
Dashboard |
Remove over-replicated chunks |
POST /api/delete-manifests |
POST |
Peer |
Delete specific manifests by name |
POST /api/purge-chunks |
POST |
Peer |
Purge chunks for a departing peer |
GET /api/integrity |
GET |
Dashboard |
Last integrity sweep results |
POST /api/integrity/sweep |
POST |
Dashboard |
Trigger immediate integrity check. JSON: {sample_size?} |
Settings
| Route |
Method |
Auth |
Description |
GET /api/settings |
GET |
Dashboard |
Current cell settings |
POST /api/settings |
POST |
Dashboard |
Update settings. JSON with fields to change |
POST /api/settings/password |
POST |
Dashboard |
Change dashboard password. JSON: {current, new} |
POST /api/settings/reset-token |
POST |
Dashboard |
Generate single-use 24h password reset link |
GET /api/backup-keys |
GET |
Dashboard |
Download encryption keys as ZIP |
POST /api/restore-keys |
POST |
Dashboard |
Restore keys from backup ZIP |
POST /api/uninstall |
POST |
Dashboard |
Web-initiated software-only uninstall. JSON: {"confirm": "LEAVE"} |
POST /api/restart |
POST |
Owner |
Trigger graceful restart (watchdog respawns) |
POST /api/dismiss-tutorial |
POST |
Dashboard |
Dismiss first-boot tutorial |
POST /api/peers/set |
POST |
Peer |
Replace peer list (fleet config management) |
Gateway / TLS
| Route |
Method |
Auth |
Description |
GET /api/gateway/status |
GET |
Dashboard |
Domain, mode, cert status |
POST /api/gateway/dns-check |
POST |
Dashboard |
Validate DNS for domain. JSON: {domain} |
POST /api/gateway/provision |
POST |
Dashboard |
Provision Let's Encrypt cert. JSON: {domain, email, staging?} |
POST /api/gateway/set-mode |
POST |
Dashboard |
Set gateway mode: auto or external. JSON: {mode} |
Growth / Creature
| Route |
Method |
Auth |
Description |
GET /api/growth |
GET |
Dashboard |
Score, milestones, recent events, 30-day history |
GET /api/challenges/suggested |
GET |
Dashboard |
Top N attainable unearned milestones. Query: ?limit=5 |
POST /api/growth/snapshot |
POST |
Dashboard |
Take a growth stats snapshot (called periodically) |
POST /api/growth/milestone//notified |
POST |
Dashboard |
Mark a milestone as user-notified |
GET /api/creature |
GET |
Dashboard |
Creature state |
Chat
| Route |
Method |
Auth |
Description |
GET /api/chat |
GET |
Dashboard |
Chat messages with a peer. Query: `?peer=
| portal:cell:user>` |
|
GET /api/chat/conversations |
GET |
Dashboard |
All conversations with last-message preview |
POST /api/chat/delete |
POST |
Dashboard |
Delete a chat message |
POST /api/chat/delete-conversation |
POST |
Dashboard |
Delete an entire conversation |
POST /api/chat-message |
POST |
Dashboard |
Send an encrypted chat message. JSON: {peer, message} |
POST /api/message |
POST |
Peer |
Receive an inter-cell message |
POST /send-message |
POST |
Dashboard |
Send a message to a peer |
POST /mark-read |
POST |
Dashboard |
Mark all messages as read |
POST /clear-notifications |
POST |
Dashboard |
Clear all system notifications |
POST /clear-notification/ |
POST |
Dashboard |
Clear a single notification by index |
GET /api/portal-chat-history |
GET |
Peer |
Cell owner โ portal user chat history |
POST /api/portal-chat-relay |
POST |
Dashboard |
Relay a chat message to a portal user |
Reactions and Comments
| Route |
Method |
Auth |
Description |
GET /api/reactions/ |
GET |
Dashboard |
Get emoji reactions for a file |
POST /api/react/ |
POST |
Dashboard |
Toggle a reaction. JSON: {emoji} |
GET /api/comments/ |
GET |
Dashboard |
Get comments for a file |
POST /api/comments/ |
POST |
Dashboard |
Add a comment. JSON: {content} |
DELETE /api/comments// |
DELETE |
Dashboard |
Delete own comment |
Feed
| Route |
Method |
Auth |
Description |
GET /feed |
GET |
Dashboard |
Feed page (files shared with you) |
POST /api/feed/dismiss |
POST |
Dashboard |
Dismiss a feed item |
Portal
Portal page routes require a portal session (/portal/login). API routes require dashboard or portal-admin session.
Portal pages
| Route |
Method |
Auth |
Description |
GET /portal |
GET |
Public |
Portal landing / login redirect |
GET /portal/login POST /portal/login |
GET/POST |
Public |
Portal login |
GET /portal/logout |
GET |
Portal |
Portal logout |
GET /portal/files GET /portal/files/ |
GET |
Portal |
Browse file tree |
GET /portal/feed |
GET |
Portal |
Portal feed |
POST /portal/folder-role |
POST |
Portal (admin) |
Set folder role |
POST /portal/upload |
POST |
Portal |
Upload file. Multipart: file, optional folder |
GET /portal/download/ |
GET |
Portal |
Download a file (decrypts and serves) |
GET /portal/thumbnail/ |
GET |
Portal |
File thumbnail |
GET /portal/preview/ |
GET |
Portal |
Inline file preview |
POST /portal/rename/ |
POST |
Portal |
Rename file. JSON: {new_name} |
POST /portal/move/ |
POST |
Portal |
Move file. JSON: {folder} |
GET /portal/users-list |
GET |
Portal (admin) |
List portal users (HTML) |
POST /portal/share/ |
POST |
Portal |
Share a file with another portal user |
POST /portal/unshare/ |
POST |
Portal |
Unshare |
GET /portal/shared-with/ |
GET |
Portal |
Who a file is shared with |
GET /portal/comments/ |
GET |
Portal |
Comments on a file |
POST /portal/comment/ |
POST |
Portal |
Add a comment |
DELETE /portal/comment/ |
DELETE |
Portal |
Delete a comment |
POST /portal/react/ |
POST |
Portal |
Toggle a reaction |
GET /portal/chat |
GET |
Portal |
Portal chat UI |
GET /portal/chat/conversations |
GET |
Portal |
Chat conversations list |
POST /portal/chat/delete-room |
POST |
Portal |
Delete a chat room |
POST /portal/chat/create |
POST |
Portal |
Create a chat room |
GET /portal/chat//messages |
GET |
Portal |
Messages in a room |
POST /portal/chat//send |
POST |
Portal |
Send a message |
POST /portal/chat//members |
POST |
Portal |
Manage room members |
GET /portal/chat/cell |
GET |
Portal |
Cell owner โ portal user direct chat |
POST /portal/chat/cell/send |
POST |
Portal |
Send message to cell owner |
GET /portal/ai |
GET |
Portal |
Portal AI tab |
POST /portal/ai/ask |
POST |
Portal |
Ask the AI (routed to cell's AI stack) |
GET /portal/settings POST /portal/settings |
GET/POST |
Portal |
Portal user settings |
GET /portal/request-access |
GET |
Public |
Landing for unauthenticated visit-peer links |
Portal user management (admin API)
| Route |
Method |
Auth |
Description |
GET /api/portal/users |
GET |
Dashboard |
List all portal users |
POST /api/portal/users |
POST |
Dashboard |
Create portal user. JSON: `{username, password, role: portal\ |
admin\ |
owner, storage_cap_gb?, home_cell?, owner?} โ {ok, username, pubkey, role}` |
DELETE /api/portal/users/ |
DELETE |
Dashboard |
Delete a portal user |
PATCH /api/portal/users/ |
PATCH |
Dashboard |
Update user (password, role, storage_cap_gb) |
GET /api/portal/owner-account POST /api/portal/owner-account |
GET/POST |
Dashboard |
Get/set which portal account is the cell owner's own account |
GET /api/portal/friends |
GET |
Portal |
List friends and invite status |
POST /api/portal/friend-invite |
POST |
Portal |
Send a friend invite |
POST /api/portal/friend-invite/respond |
POST |
Portal |
Accept/reject a friend invite |
POST /api/portal/friend-invite/revoke |
POST |
Portal |
Revoke a sent invite |
POST /api/portal/friend/remove |
POST |
Portal |
Remove a friend |
POST /api/portal/suggestions |
POST |
Portal |
Get portal suggestions |
POST /api/portal/suggestions/dismiss |
POST |
Portal |
Dismiss a suggestion |
GET /api/portal/folder-list |
GET |
Portal |
List virtual folders for current portal user |
POST /api/portal/folder/create |
POST |
Portal |
Create a virtual folder. JSON: {name} |
POST /api/portal/feed/dismiss |
POST |
Portal |
Dismiss a portal feed item |
Portal proxy (cell โ gateway user management)
| Route |
Method |
Auth |
Description |
POST /api/portal/proxy/create-user |
POST |
Dashboard |
Proxy user creation to the portal host cell |
GET /api/portal/proxy/list-users |
GET |
Dashboard |
Proxy: list users on the portal host cell |
DELETE /api/portal/proxy/delete-user/ |
DELETE |
Dashboard |
Proxy: delete a user on the portal host cell |
Portal availability and hosting (home cell side)
| Route |
Method |
Auth |
Description |
GET /api/portal/availability |
GET |
Public |
Whether portal-account signup is available (invite UI) |
POST /api/portal/host/enable |
POST |
Dashboard |
Enable/disable portal hosting. JSON: {enabled} |
GET /api/portal/host/slots |
GET |
Dashboard |
List approved + pending portal hosting slots |
GET /api/portal/eligible-hosts |
GET |
Dashboard |
List peers able to host portals |
POST /api/portal/host/request |
POST |
Peer |
Receive a portal hosting request from another cell |
POST /api/portal/host/approve |
POST |
Dashboard |
Approve a pending portal hosting request |
POST /api/portal/host/reject |
POST |
Dashboard |
Reject a portal hosting request |
POST /api/portal/host/receive-keys |
POST |
Peer |
Receive encrypted identity keys from a home cell |
POST /api/portal/host/remove |
POST |
Dashboard |
Remove a portal hosting slot |
Portal relay (home cell โ gateway)
| Route |
Method |
Auth |
Description |
GET /api/portal/relay/status |
GET |
Dashboard |
Portal relay status (home cell side) |
POST /api/portal/relay/request |
POST |
Dashboard |
Send a portal hosting request to a gateway peer. JSON: {host_pubkey} |
POST /api/portal/relay/push-keys |
POST |
Dashboard |
Push encrypted identity keys to the portal host |
GET /api/portal/relay/check |
GET |
Dashboard |
Check if portal request has been approved |
Portal remote access (owner cell โ gateway)
These provision the cell owner's own portal account on a WAN gateway (Option B model: no key import).
| Route |
Method |
Auth |
Description |
GET /api/portal/remote/status |
GET |
Dashboard |
Remote portal account config status |
POST /api/portal/remote/setup |
POST |
Dashboard |
Provision owner account on a gateway peer. JSON: {host_pubkey, username, password} โ {ok, host_name, username, remote_folder} |
POST /api/portal/remote/clear |
POST |
Dashboard |
Forget remote account locally (+ optionally delete on gateway). JSON: {delete_account?} |
Portal visit-peer
| Route |
Method |
Auth |
Description |
GET /api/visit-peer |
GET |
Owner |
Redirect browser to a peer cell with signed auto-mint token. Query: ?cell=&path= |
Peer Messaging (legacy form-based)
| Route |
Method |
Auth |
Description |
POST /api/folder-role |
POST |
Owner |
Set/clear folder role (same as /api/folder-role alias at line 12413) |
PWA / Assets
| Route |
Method |
Auth |
Description |
GET /manifest.json |
GET |
Public |
PWA manifest |
GET /sw.js |
GET |
Public |
Service worker |
GET /icon-192.png |
GET |
Public |
PWA icon 192ร192 |
GET /icon-512.png |
GET |
Public |
PWA icon 512ร512 |
GET /favicon.ico |
GET |
Public |
SVG favicon (inline pine tree) |
Notes and Edge Cases
Per-peer derived secrets (v0.4.1+)
Peers now derive a bilateral secret: BLAKE2b(ECDH(my_x25519_priv, their_x25519_pub)). Send X-Grove-Secret: + X-Grove-Sender: . The receiving cell tries the global secret first (backward compat), then the derived secret.
receive-chunks-b64
Alternative to receive-chunks for relay transport where multipart is impractical. Chunks sent as base64-encoded JSON.
Ingest jobs vs. tasks
/api/ingest-status covers file-ingest background jobs (watches + drives). /api/tasks covers all background jobs (uploads, extracts, etc.) shown in the Home progress tray. Both are separate systems.
/api/gc-manifests vs /api/gc
/api/gc โ garbage collects orphaned chunks (no manifest references them). Dry-run by default.
/api/gc-manifests โ creator-scoped: a peer can ask this cell to drop manifests the peer created. Safe because it's scoped to creator_pubkey.
/api/delete-everywhere vs Recycle Bin
/api/delete-everywhere/ moves a file to the 24h recycle bin (soft delete). It's still accessible from /api/recycle-bin/list and restorable. Hard deletion (chunks + manifest) happens either at 24h expiry or via /api/recycle-bin/force-delete/.
Portal roles
portal โ normal user; sees only files shared with them
admin โ can access /api/* routes (tailnet only), manage users
owner โ the cell owner's own account; sees the cell's drive (set via portal_owner_account config)
/api/ai/setup actions summary
All actions are POST body {action: "...", ...}:
| action |
What it does |
detect |
Detect hardware + recommended model |
models |
List installed models + catalog |
download |
Download a catalog model by model_file |
download_status |
Poll download progress |
switch |
Switch active model |
delete |
Delete an installed model |
enable / disable |
Enable/disable local AI |
set_peer_policy |
Set peer model access policy (all/friends/none) |
build_runtime |
Build llama.cpp runtime |
build_status |
Poll build progress |
set_default_tier |
Set default chat tier (low/mid/high) |
set_hf_token |
Store HuggingFace API token |
hf_search |
Search HuggingFace for GGUF models |
hf_files |
List GGUF files for a repo |
download_hf |
Download a GGUF by URL |
benchmark |
Benchmark a model |
benchmark_status |
Poll benchmark progress |
benchmark_results |
Retrieve benchmark results |