Skip to content

REST API

RAGMill ships a FastAPI server so any language or frontend can use it over HTTP.

pip install "ragmill[server]"
ragmill serve
# or: uvicorn ragmill.server:app --host 0.0.0.0 --port 8000

Once running:

  • Chat UIhttp://localhost:8000/ (a minimal terminal-style box for testing)
  • Interactive OpenAPI docshttp://localhost:8000/docs (Swagger UI, auto-generated)
  • Healthhttp://localhost:8000/health

The server reads the same configuration env vars, so it uses whatever store and chat backend you've set.

Endpoints

Method Path Body Description
POST /ingest {directory} Full ingest + embed a directory
POST /sync {directory} Incremental sync a directory
POST /search {query, top_k, ...filters} Semantic search
POST /chat {query, top_k, ...filters} Grounded answer + sources
GET /count Number of stored chunks
POST /export Export store to a JSONL file on the server
POST /import multipart file Import a JSONL file
GET /health {status, store_type, chunk_count}
GET / Browser chat UI

Filters accepted by /search and /chat: filename, source_file, modified_after, modified_before.

Examples

Sync a folder

curl -X POST http://localhost:8000/sync \
  -H 'Content-Type: application/json' \
  -d '{"directory": "/data/docs"}'
# {"added": 12, "updated": 0, "skipped": 88, "deleted": 1}
curl -X POST http://localhost:8000/search \
  -H 'Content-Type: application/json' \
  -d '{"query": "refund policy", "top_k": 3}'

Chat (grounded answer)

curl -X POST http://localhost:8000/chat \
  -H 'Content-Type: application/json' \
  -d '{"query": "what is the refund window?", "top_k": 5}'
# {"answer": "...", "sources": [{"filename": "policy.pdf", "score": 0.71, ...}]}

Calling it from a frontend

Because it's plain JSON over HTTP, any client works. A TypeScript example:

async function ask(query: string) {
  const res = await fetch("http://localhost:8000/chat", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ query, top_k: 5 }),
  });
  if (!res.ok) throw new Error(`RAGMill ${res.status}: ${await res.text()}`);
  return (await res.json()) as { answer: string; sources: unknown[] };
}

Deploying beyond localhost

/ingest and /sync take a server-side directory path and there's no auth built in. If you expose the API beyond localhost, put it behind your own auth/gateway and don't accept untrusted directory paths. See Docker.