โ† Dashboard ยท Docs ยทApi Reference

Grove API Reference

Build: c237b3292bef ยท Last updated: 2026-06-07

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


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/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

/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