FileVault/Documentation

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.

The Agent API and the human hosting product share infrastructure but are completely independent. You don't need a Clerk account to use the Agent API.

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}'
Your API key is shown exactly once at agent creation. Copy it immediately — it cannot be retrieved. If you lose it, create a new agent.

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

MethodPathDescription
GET/api/v1/filesList files (paginated, indexed= filter)
POST/api/v1/filesUpload a file (multipart)
POST/api/v1/files/batchBatch upload up to 10 files
GET/api/v1/files/:idFile metadata + index_status
DELETE/api/v1/files/:idDelete file + all embeddings
POST/api/v1/files/:id/indexTrigger 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.

There is no enforced per-agent storage quota at this time. The upload rate limit is 20 files per minute.

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

MethodPathDescription
POST/api/v1/searchSemantic 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.

MethodPathDescription
POST/api/v1/memoryStore a memory { content, ttl? }
GET/api/v1/memoryList memories (paginated)
DELETE/api/v1/memory/:idDelete 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.

MethodPathDescription
GET/api/v1/collectionsList collections with file counts
POST/api/v1/collectionsCreate { name }
GET/api/v1/collections/:idGet collection + files
DELETE/api/v1/collections/:idDelete collection (files unaffected)
POST/api/v1/collections/:id/filesAdd file { file_id }
DELETE/api/v1/collections/:id/files/:fileIdRemove file from collection

Agent-to-agent sharing

Grant another agent read access to your files and embeddings without sharing credentials. The grantee can include your content in searches via include_shared=true.

MethodPathDescription
GET/api/v1/sharesList shares given and received
POST/api/v1/sharesGrant access { agent_id }
DELETE/api/v1/shares/:granteeIdRevoke access
# Grant access
curl -X POST https://filevault.host/api/v1/shares \
  -H "Authorization: Bearer fv_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "clx..."}'

# Search including shared content
curl -X POST https://filevault.host/api/v1/search \
  -H "Authorization: Bearer fv_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"query": "project brief", "filter": {"include_shared": true}}'

Webhooks

FileVault fires a POST to your registered URL on three events:

EventWhen it fires
file.createdAfter every successful upload
file.indexedWhen indexing completes
file.deletedWhen a file is deleted
MethodPathDescription
GET/api/v1/webhooksGet registered webhook URL
PUT/api/v1/webhooksRegister / update webhook URL
DELETE/api/v1/webhooksRemove 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.

The MCP server is bundled in the repo, not published as a standalone npm package. You need a local clone to run it.

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

ToolDescription
filevault_upload_fileUpload and optionally index a file
filevault_searchSemantic search across files and memory
filevault_store_memoryStore agent memory with optional TTL
filevault_list_filesList stored files
filevault_get_usageGet usage statistics

Human hosting

Drop a ZIP or HTML file on the homepage and get a shareable link in seconds. No account required.

FeatureAnonymousFreePro
Max upload5 MB10 MB100 MB
Link expiry24 h30 daysNever
Max links3 / day10 totalUnlimited
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.

Still stuck?

Email us and we'll get back to you within 24 hours.