Overview
FileVault is two products in one codebase:
Agent Storage API
A REST API for AI agents — isolated file storage, semantic search with pgvector, persistent memory, collections, cross-agent sharing, and webhooks. One API key, no S3 glue required.
Human hosting
Drop a ZIP or HTML file on the homepage, get a shareable URL in seconds. Supports password protection, custom domains, expiry, and view analytics.
Quick start
Three curl commands to go from zero to semantic search:
# 1. Create an agent — returns your API key (shown once)
curl -X POST https://filevault.host/api/v1/agents \
-H "Content-Type: application/json" \
-d '{"name": "my-agent"}'
# 2. Upload a file and index it for search
curl -X POST https://filevault.host/api/v1/files \
-H "Authorization: Bearer fv_sk_..." \
-F "file=@report.pdf" \
-F "index=true"
# 3. Search in natural language
curl -X POST https://filevault.host/api/v1/search \
-H "Authorization: Bearer fv_sk_..." \
-H "Content-Type: application/json" \
-d '{"query": "What was the Q3 revenue?", "limit": 5}'TypeScript SDK
The SDK wraps every endpoint with full TypeScript types. Import it from src/sdk/index.ts in the repo or copy the class into your project.
import { FileVault } from '@/sdk'
const fv = new FileVault('fv_sk_...')
const file = await fv.files.upload(blob, { index: true, metadata: { project: 'q3' } })
const results = await fv.search('What is the refund policy?')
await fv.memory.add('User prefers bullet points.', { ttl_seconds: 86400 })Authentication
Every Agent API request requires a Bearer token in the Authorization header:
Authorization: Bearer fv_sk_<64 hex characters>
Keys are created via POST /api/v1/agents and stored as SHA-256 hashes — FileVault cannot recover a lost key. Missing or invalid keys return 401 Unauthorized.
The human dashboard (/dashboard) uses Clerk session auth — completely separate from the agent key system.
Files & storage
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/files | List files (paginated, indexed= filter) |
| POST | /api/v1/files | Upload a file (multipart) |
| POST | /api/v1/files/batch | Batch upload up to 10 files |
| GET | /api/v1/files/:id | File metadata + index_status |
| DELETE | /api/v1/files/:id | Delete file + all embeddings |
| POST | /api/v1/files/:id/index | Trigger indexing on demand |
Uploading
Send a multipart/form-data request with a file field. Add index=true to auto-index on upload. Optional metadata field accepts a JSON string of key/value pairs.
curl -X POST https://filevault.host/api/v1/files \
-H "Authorization: Bearer fv_sk_..." \
-F "file=@report.pdf" \
-F "index=true" \
-F 'metadata={"project":"q3","author":"alice"}'Supported types for indexing
All file types are stored. Text extraction for semantic search works on: text/html, text/plain, application/pdf, and application/json. Other file types are stored and downloadable but won't produce search results.
Indexing & search
How indexing works
When a file is indexed, FileVault: (1) extracts text from the file, (2) splits it into overlapping chunks (~500 tokens, 100-token overlap), (3) generates an embedding for each chunk via OpenRouter (openai/text-embedding-3-small), and (4) stores the vectors in a pgvector index on Supabase.
index_status lifecycle
not_indexed → pending → indexed
Poll GET /api/v1/files/:id and check the index_status field. Once indexed, the file is searchable.
Searching
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/search | Semantic search across files and memory |
POST /api/v1/search
{
"query": "quarterly revenue breakdown",
"limit": 5,
"filter": {
"type": "all", // "all" | "files" | "memory"
"file_id": "clx...", // scope to one file
"collection_id": "clx...",
"include_shared": true, // include shared agent content
"metadata": { "project": "q3" }
}
}Results are ranked by cosine similarity. Each result includes a score (0–1), the matching content chunk, and the source file_id.
Memory
Memory lets your agent store arbitrary text snippets — conversation turns, extracted facts, decisions, or anything it wants to recall later. Each memory gets an embedding and is searchable alongside files.
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/memory | Store a memory { content, ttl? } |
| GET | /api/v1/memory | List memories (paginated) |
| DELETE | /api/v1/memory/:id | Delete a single memory |
# Store with a 24-hour TTL
curl -X POST https://filevault.host/api/v1/memory \
-H "Authorization: Bearer fv_sk_..." \
-H "Content-Type: application/json" \
-d '{"content": "User prefers metric units.", "ttl": 86400}'Pass type=memory in a search request to search only memories. Omit it (or use type=all) to search both files and memories together.
Collections
Collections are named groups of files within your agent's namespace. Use them to organise by project, client, or topic — and to scope searches to a subset of your storage.
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/collections | List collections with file counts |
| POST | /api/v1/collections | Create { name } |
| GET | /api/v1/collections/:id | Get collection + files |
| DELETE | /api/v1/collections/:id | Delete collection (files unaffected) |
| POST | /api/v1/collections/:id/files | Add file { file_id } |
| DELETE | /api/v1/collections/:id/files/:fileId | Remove file from collection |
Webhooks
FileVault fires a POST to your registered URL on three events:
| Event | When it fires |
|---|---|
| file.created | After every successful upload |
| file.indexed | When indexing completes |
| file.deleted | When a file is deleted |
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/webhooks | Get registered webhook URL |
| PUT | /api/v1/webhooks | Register / update webhook URL |
| DELETE | /api/v1/webhooks | Remove webhook |
curl -X PUT https://filevault.host/api/v1/webhooks \
-H "Authorization: Bearer fv_sk_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://myapp.example.com/hooks/filevault"}'MCP server
FileVault ships an MCP server (src/mcp/server.ts) so any MCP-compatible client — Claude Desktop, Cursor, Cline — can use it without writing code.
Setup (Claude Desktop)
// ~/.claude/claude_desktop_config.json
{
"mcpServers": {
"filevault": {
"command": "npx",
"args": ["tsx", "/path/to/filevault/src/mcp/server.ts"],
"env": { "FILEVAULT_API_KEY": "fv_sk_..." }
}
}
}Replace /path/to/filevault with your local clone path. tsx must be installed globally: npm install -g tsx.
Available tools
| Tool | Description |
|---|---|
| filevault_upload_file | Upload and optionally index a file |
| filevault_search | Semantic search across files and memory |
| filevault_store_memory | Store agent memory with optional TTL |
| filevault_list_files | List stored files |
| filevault_get_usage | Get usage statistics |
Human hosting
Drop a ZIP or HTML file on the homepage and get a shareable link in seconds. No account required.
| Feature | Anonymous | Free | Pro |
|---|---|---|---|
| Max upload | 5 MB | 10 MB | 100 MB |
| Link expiry | 24 h | 30 days | Never |
| Max links | 3 / day | 10 total | Unlimited |
| Password protection | — | ✓ | ✓ |
| Custom domain | — | — | ✓ |
Custom domains (Pro)
Add a CNAME record pointing to filevault.host, then enter your domain in the dashboard card for that deployment. Traffic to your domain is proxied to the right slug automatically.
Troubleshooting
401 Unauthorized
Check that your header is exactly Authorization: Bearer fv_sk_... with no extra spaces or quotes. API keys are shown once at creation — if you lost yours, create a new agent.
Search returns no results after upload
The file needs to be indexed first. Either upload with index=true, or call POST /api/v1/files/:id/index afterwards. Poll GET /api/v1/files/:id and wait for index_status: "indexed" before searching.
429 Too Many Requests
The upload rate limit is 20 files per minute per agent. The response includes retry_after_seconds. Use /api/v1/files/batch to upload up to 10 files as a single request.
File uploaded but not returning a download URL
GET /api/v1/files/:id returns metadata only. Files stored in Cloudflare R2 are served via a CDN redirect — the storage_key field in the response maps to the R2 object key.
Checking usage
GET /api/v1/usage returns your current file count, indexed count, storage bytes, embedding count, memory count, and state checkpoint count in a single call.