Skip to content

🌟 API Documentation Overview

The FastAPI-powered backend provides a comprehensive document-based question answering system using Retrieval-Augmented Generation (RAG). The API supports semantic search, document indexing, and chat completions across multiple data partitions with full OpenAI compatibility.

Protected endpoints require authentication by default. Set AUTH_TOKEN in your .env and include it in the HTTP request header:

Authorization: Bearer YOUR_AUTH_TOKEN

For OpenAI-compatible endpoints, AUTH_TOKEN serves as the api_key parameter. Local no-auth development requires the explicit ALLOW_NO_AUTH=true opt-in; otherwise an empty token fails closed.


This API can be served using Uvicorn (default) or Ray Serve for distributed deployments.

By default, the backend uses uvicorn to serve the FastAPI app.

To enable Ray Serve, set the following environment variable:

.env
ENABLE_RAY_SERVE=true

Additional optional environment variables for configuring Ray Serve:

.env
RAY_SERVE_NUM_REPLICAS=1 # Number of deployment replicas
RAY_SERVE_HOST=0.0.0.0 # Host address for Ray Serve HTTP proxy
RAY_SERVE_PORT=8080 # Port for Ray Serve HTTP proxy

When using Ray Serve with a remote cluster, the HTTP server will be started on the head node of the cluster.

Verify server status and availability.

GET /health_check

Get openRAG version

GET /version

Get the current application configuration. Sensitive fields (api_key, password, token) are redacted.

GET /config

Permissions: Requires admin role

Response: JSON object with all configuration sections (LLM, embedder, vector DB, chunker, retriever, etc.)


POST /indexer/partition/{partition}/file/{file_id}

Upload a new file to a specific partition for indexing.

Parameters:

  • partition (path): Target partition name
  • file_id (path): Unique identifier for the file

Request Body (form-data):

  • file (binary): File to upload
  • metadata (JSON string): File metadata (e.g., {"owner": "user1"})

Responses:

  • 201 Created: Returns task status URL
  • 409 Conflict: File already exists in partition

OpenRAG supports temporal filtering to retrieve documents from specific time periods. The client can include the temporal field to allow temporal-aware search in search endpoints.

  • created_at: ISO 8601 format date of when the file was created

created_at is provided by the client in the metadata of the file during upload. This is a first iteration — additional temporal fields (e.g. updated_at) may be added in future releases as needed.

Upload files while modeling relations between them
Section titled “Upload files while modeling relations between them”

OpenRAG supports document relationships to enable context-aware retrieval. You can model relationships between files using the metadata field during upload. Different relationship types can be represented using the relationship_id and parent_id metadata fields, depending on the use case: folder-based relationships, email threads, etc. (see Document Relationships documentation for more details).

POST /indexer/partition/{partition}/file/{file_id}
Authorization: Bearer YOUR_AUTH_TOKEN
Content-Type: multipart/form-data
file: <binary data>
metadata: {
"relationship_id": "documents/projects/2024/q1",
...
}
  • for email threads, one can rely on both relationship_id (to group emails in the same thread) and parent_id (to model reply hierarchies within the thread). See the Document Relationships documentation for more details and examples.

Example: Original Email (Root)

POST /indexer/partition/emails/file/email_a_id
Authorization: Bearer YOUR_AUTH_TOKEN
Content-Type: multipart/form-data
file: <email binary data>
metadata: {
"relationship_id": "thread-123",
"parent_id": null,
...
}

Example: Reply Email (Child)

POST /indexer/partition/emails/file/email_b_id
Authorization: Bearer YOUR_AUTH_TOKEN
Content-Type: multipart/form-data
file: <email binary data>
metadata: {
"relationship_id": "thread-123",
"parent_id": "email_a_id",
...
}

For context-aware search, see search endpoints and relationship-based file fetching.

PUT /indexer/partition/{partition}/file/{file_id}

Replace an existing file in the partition. Deletes the current entry and creates a new indexing task.

Parameters: Same as POST endpoint Request Body: Same as POST endpoint Response: 202 Accepted with task status URL

PATCH /indexer/partition/{partition}/file/{file_id}

Update file metadata without reindexing the document.

Request Body (form-data):

  • metadata (JSON string): Updated metadata

Response: 200 OK on successful update

DELETE /indexer/partition/{partition}/file/{file_id}

Remove a file from the specified partition.

Responses:

  • 204 No Content: Successfully deleted
  • 404 Not Found: File not found in partition
GET /indexer/task/{task_id}

Monitor the progress of an asynchronous indexing task.

Response: Task status information


GET /indexer/task/{task_id}/logs
GET /indexer/task/{task_id}/error
  • Search Across Multiple Partitions
GET /search/

Perform semantic search across specified partitions.

Query Parameters:

ParameterTypeDefaultDescription
partitions (optional)array[“all”]Partitions to search. (optional)
textstringrequiredSearch query
top_k (optional)integer5Number of initial results (optional)
include_related (optional)booleanfalseInclude chunks from files with same relationship_id
include_ancestors (optional)booleanfalseInclude chunks from ancestor files (via parent_id chain)
related_limit (optional)integer20Max related/ancestor chunks to fetch per result (used when include_related or include_ancestors is true)
filter (optional)stringNoneMilvus filter expression string for additional filtering. Supports comparison (==, !=, >, <, >=, <=), range (IN, LIKE), and logical (AND, OR, NOT) operators.

Responses:

  • 200 OK: JSON list of document links (HATEOAS format)
  • 400 Bad Request: Invalid partitions parameter
  • Search Within Single Partition
GET /search/partition/{partition}

Search within a specific partition only.

Query Parameters:

ParameterTypeDefaultDescription
textstringrequiredSearch query
top_k (optional)integer5Number of initial results (optional)
include_related (optional)booleanfalseInclude chunks from files with same relationship_id
include_ancestors (optional)booleanfalseInclude chunks from ancestor files (via parent_id chain)
related_limit (optional)integer20Max related/ancestor chunks to fetch per result (used when include_related or include_ancestors is true)
filter (optional)stringNoneMilvus filter expression string for additional filtering. Supports comparison (==, !=, >, <, >=, <=), range (IN, LIKE), and logical (AND, OR, NOT) operators.

Response: Same as multi-partition search

  • Search Within Specific File
GET /search/partition/{partition}/file/{file_id}

Search within a particular file in a partition.

Query Parameters: Same as partition search, including filter. Response: Same as other search endpoints


Extracts are the individual chunks a document is split into during indexing. Each has a stable extract_id, surfaced as the link on search results and on the file/chunk-listing endpoints below.

GET /extract/{extract_id}

Retrieve a specific document extract (chunk) by its ID.

Parameters:

  • extract_id (path): The unique chunk identifier (from search or chunk-listing results)

Permissions: Requires access to the partition containing the chunk — regular users are limited to their assigned partitions; admins can read any chunk.

Response: 200 OK

{
"page_content": "The text content of the chunk…",
"metadata": {
"file_id": "doc-a-id",
"filename": "Document A.pdf",
"partition": "my_partition",
"page": 3,
"indexed_at": "2026-01-01T12:00:00Z"
}
}

Errors:

  • 403 Forbidden: You don’t have access to the chunk’s partition
  • 404 Not Found: No extract with that ID

Partitions are the multi-tenant document collections OpenRAG indexes into. All routes below are prefixed with /partition. Access is role-based (hierarchy owner > editor > viewer): viewer for reads, owner for partition deletion, config changes, and member management. Admins with SUPER_ADMIN_MODE=true bypass membership checks.

GET /partition/

List the partitions you can access — admins see all partitions, regular users see only their memberships. Each entry includes partition, document_count, and (for non-admins) your role.

POST /partition/{partition}

Create an empty partition; you automatically become its owner. Returns 201 Created, or 409 Conflict if the name is taken. Non-admins are capped by MAX_PARTITIONS_PER_USER (a 403 is returned when the cap is reached).

DELETE /partition/{partition}

Permanently delete a partition and all its files and chunks. Owner only. Returns 204 No Content. This cannot be undone.

GET /partition/{partition}

Viewer+. Query: limit (optional). Returns { "files": [ { "file_id", "filename", "link", … } ] }, where link points at the file-detail endpoint below.

GET /partition/{partition}/file/{file_id}

Viewer+. Query: limit (max chunks, default 2000). Returns { "metadata": {…}, "documents": [ { "link": "…/extract/{id}" } ] }. Returns 404 if the file isn’t in the partition.

GET /partition/{partition}/chunks

List document chunks (extracts) in a partition. Viewer+.

Query Parameters:

ParameterTypeDefaultDescription
include_embeddingbooleantrueInclude each chunk’s vector embedding
file_idstringNoneRestrict to a single file’s chunks (recommended for the document-detail view)
limitintegerunboundedMax chunks to return

Returns { "chunks": [ { "content", "metadata", "link", "embedding"? } ] }. Note the chunk text is under content here, whereas the single-chunk GET /extract/{extract_id} endpoint returns it under page_content.

Each partition references an indexation and a retrieval preset, plus an embedder and chat LLM.

  • Get resolved config
GET /partition/{partition}/config

Viewer+. Returns the partition’s preset references and the fully resolved indexation/retrieval pipeline configuration.

  • Update config
PATCH /partition/{partition}

Owner only. Body fields (all optional): description, embedder, indexation_preset, retrieval_preset, chat_history_depth, chat_llm. Returns the updated resolved config.

curl -X PATCH http://localhost:8080/partition/my_partition \
-H "Authorization: Bearer YOUR_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{"indexation_preset": "legal", "retrieval_preset": "hyde"}'

Manage who can access a partition and with which role — all owner only.

EndpointMethodDescription
/partition/{partition}/usersGETList members → { "members": [...] }
/partition/{partition}/usersPOSTAdd a member — form fields user_id (int), role (default viewer) → 201
/partition/{partition}/users/{user_id}PATCHUpdate a member’s role — form field role200
/partition/{partition}/users/{user_id}DELETERemove a member → 204
  • Get Files by Relationship
GET /partition/{partition}/relationships/{relationship_id}

Returns all files sharing the same relationship_id within a partition. Viewer+.

Parameters:

  • partition — partition name
  • relationship_id — the relationship group identifier (client-defined)

Response:

{
"files": [
{
"file_id": "doc-a-id",
"filename": "Document A",
"relationship_id": "group-123",
"parent_id": null
},
{
"file_id": "doc-b-id",
"filename": "Document B",
"relationship_id": "group-123",
"parent_id": "doc-a-id"
}
]
}
  • Get File Ancestors
GET /partition/{partition}/file/{file_id}/ancestors

Returns the complete ancestor path from root to the specified file. Viewer+.

Parameters:

  • partition — partition name
  • file_id — the file to trace ancestors for
  • max_ancestor_depth (optional) — limit on ancestor depth to return. None means unlimited.

Response:

{
"ancestors": [
{
"file_id": "email-a-id",
"filename": "Original Email",
"parent_id": null
},
{
"file_id": "email-b-id",
"filename": "First Reply",
"parent_id": "email-a-id"
},
{
"file_id": "email-c-id",
"filename": "Second Reply",
"parent_id": "email-b-id"
}
]
}

Named, reusable indexation and retrieval pipeline configurations. Partitions reference a preset by name (see PATCH /partition/{partition}) instead of carrying an inline config, so a change to a preset propagates to every partition using it. Six defaults are seeded on first boot (default, legal, finance for indexation; default, multiquery, hyde for retrieval); the default preset of each type cannot be deleted or renamed.

All routes are prefixed with /presets and require the admin role. preset_type is one of indexation | retrieval.

GET /presets/options

Returns the choices valid inside a preset config: chunking_strategies, parsing_strategies (pymupdf, marker, docling), retrieval_types, and reranker_providers.

POST /presets/

Body: name (string), preset_type (indexation | retrieval), config (object — its keys depend on the type). Returns 201 Created with the stored preset.

curl -X POST http://localhost:8080/presets/ \
-H "Authorization: Bearer YOUR_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "hyde-large",
"preset_type": "retrieval",
"config": {"type": "hyde", "top_k": 50, "top_n": 10}
}'

An indexation config instead accepts keys such as chunking ({name, chunk_size, chunk_overlap_rate}), parsing_strategy, enable_image_captioning, enable_contextualization, and contextualization_mode.

GET /presets/

Query: preset_type (optional) to filter by type. Returns a list of presets with name, preset_type, config, created_at, updated_at.

GET /presets/{preset_type}/{name}
PUT /presets/{preset_type}/{name}
DELETE /presets/{preset_type}/{name}

PUT accepts a partial body (name to rename and/or config; at least one required) and returns the updated preset. DELETE returns 204 No Content.


A registry of named inference endpoints (embedder, reranker, LLM, VLM) that partitions and presets can point at, so operators can manage and switch inference backends at runtime instead of via .env. Stored API keys are redacted in every response and only returned through the explicit reveal action below.

All routes are prefixed with /model-endpoints and require the admin role. model_type is one of embedder | reranker | llm | vlm.

POST /model-endpoints/

Body: name, model_type, endpoint (URL), model_name (optional), batch_size (default 32), timeout (seconds, default 30), extra (object — put api_key here), is_default (default false). Returns 201 Created; the response carries has_api_key rather than the key itself.

curl -X POST http://localhost:8080/model-endpoints/ \
-H "Authorization: Bearer YOUR_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "prod-embedder",
"model_type": "embedder",
"endpoint": "https://vllm.internal/v1",
"model_name": "jinaai/jina-embeddings-v3",
"extra": {"api_key": "sk-…"}
}'
GET /model-endpoints/ # ?model_type= to filter
GET /model-endpoints/{model_type}/{name}
PUT /model-endpoints/{model_type}/{name}
DELETE /model-endpoints/{model_type}/{name} # 204 No Content

PUT takes a partial body (any of the create fields, plus name to rename) and returns the updated endpoint.

POST /model-endpoints/{model_type}/{name}/set-default

Promotes the endpoint to the default used for its model_type, and returns it.

POST /model-endpoints/{model_type}/{name}/reveal-api-key

Explicit admin action that returns { "api_key": "…" } (or null if none is stored). This is the only endpoint that returns the key in clear text; the action is logged.

POST /model-endpoints/validate # probe a draft (unsaved) endpoint
POST /model-endpoints/{model_type}/{name}/validate # probe a registered endpoint

Both probe the target for reachability and model availability, returning { "reachable", "model_found", "models_served", "detail" }. The draft form takes endpoint (+ optional model_name, api_key); to reuse a saved key without resending it, pass stored_api_key_model_type and stored_api_key_name (both required together, and only accepted when the draft endpoint matches the saved one).


These endpoints provide full OpenAI API compatibility for seamless integration with existing tools and workflows. For detailed example of openai usage see this section

  • List Available Models
GET /v1/models

List all available RAG models (partitions).

Model Naming Convention:

  • Pattern: openrag-{partition_name} => This model allows to chat specifically with the partition {partition_name}
  • Special model: partition-all (queries entire vector database)
  • Chat Completions
POST /v1/chat/completions

OpenAI-compatible chat completion using RAG pipeline.

Request Body:

curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_AUTH_TOKEN" \
-d '{
"model": "openrag-{partition_name}",
"messages": [
{
"role": "user",
"content": "Your question here"
}
],
"temperature": 0.1,
"stream": false
}'

You can also direclty use this endpoint with no RAG pipeline, i.e. to directly use the LLM. For that, instead of using the openrag prefix for the model, you can:

  • Specify no model
  • Specify an empty model
  • Specify the openRAG configured model, e.g. Mistral-Small-3.1-24B-Instruct-2503.

Request Body:

curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_AUTH_TOKEN" \
-d '{
"model": "",
"messages": [
{
"role": "user",
"content": "Your question here"
}
],
"temperature": 0.1,
"stream": false
}'
  • Text Completions
POST /v1/completions

OpenAI-compatible text completion endpoint.

  • When using the openai endpoint /v1/chat/completions, you can pass extra arguments via the metadata field of the request body to customize the RAG behavior:
OptionTypeDefaultDescription
websearchboolfalseAugments the RAG context with live web search results. When used with a partition (openrag-{partition}), document and web results are combined. When used without a partition (direct LLM mode), web results are the sole context. Requires WEBSEARCH_API_TOKEN to be configured. See web search configuration.
spoken_style_answerboolfalseGenerates a succinct spoken-style conversational answer based on the retrieved documents.
use_map_reduceboolfalseUses a map-reduce strategy to aggregate information from multiple documents. See map-reduce configuration.
llm_overrideobjectnullOverrides only the downstream LLM model name while still using OpenRAG’s configured LLM endpoint and credentials. Accepts: model (string). Endpoint URL and API key are server-side configuration and cannot be changed by a client request.

Examples:

Enabling conversational answer with openai chat completions endpoint
curl -X 'POST' 'http://localhost:8080/v1/chat/completions' \
-H 'accept: application/json' \
-H 'Authorization: Bearer YOUR_AUTH_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"model": "openrag-{partition_name}",
"messages": [
{
"role": "user",
"content": "your_query"
}
],
"temperature": 0.3,
"stream": false,
"metadata": {
"spoken_style_answer": true
}
}'
Enabling web search with RAG documents
curl -X 'POST' 'http://localhost:8080/v1/chat/completions' \
-H 'accept: application/json' \
-H 'Authorization: Bearer YOUR_AUTH_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"model": "openrag-{partition_name}",
"messages": [
{
"role": "user",
"content": "your_query"
}
],
"stream": false,
"metadata": {
"websearch": true
}
}'
Web search only (no RAG partition)
curl -X 'POST' 'http://localhost:8080/v1/chat/completions' \
-H 'accept: application/json' \
-H 'Authorization: Bearer YOUR_AUTH_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"model": "",
"messages": [
{
"role": "user",
"content": "your_query"
}
],
"stream": false,
"metadata": {
"websearch": true
}
}'
Using another configured LLM model with OpenRAG's RAG pipeline
curl -X 'POST' 'http://localhost:8080/v1/chat/completions' \
-H 'accept: application/json' \
-H 'Authorization: Bearer YOUR_AUTH_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"model": "openrag-{partition_name}",
"messages": [
{
"role": "user",
"content": "your_query"
}
],
"stream": false,
"metadata": {
"llm_override": {
"model": "gpt-4o"
}
}
}'

Tools are useful features that can be called directly by the client.

  • List available tools
GET /v1/tools

Request:

curl http://localhost:8080/v1/tools

Response:

[
{
"name": "Tool name",
"description": "Tool description"
}
]
  • Execute a tool
POST /v1/tools/execute

The parameters are given in multipart.

Request:

curl -X POST http://localhost:8080/v1/tools/execute \
-H "Content-Type: multipart/form-data" \
-H "Authorization: Bearer YOUR_AUTH_TOKEN" \
-F "file=@file.pdf" \
-F 'tool={"name":"extractText"}' \
-F 'metadata={"mime":"application/pdf","name":"test.pdf"}' \

Response:

{
"message": "File content"
}

For indexing multiple files programmatically, you can use the data_indexer.py utility script in the scripts/ folder or simply use indexer ui.

from openai import OpenAI, AsyncOpenAI
api_base_url = "http://localhost:8080" # fastapi base url of 'openrag'
base_url = f"{api_base_url}/v1"
auth_key = ... # your API authentication key AUTH_TOKEN from .env
client = OpenAI(api_key=auth_key, base_url=base_url)
your_partition= 'my_partition' # name of your partition
model = f"openrag-{your_partition}"
settings = {
'model': model,
'temperature': 0.3,
'stream': False
}
response = client.chat.completions.create(
**settings,
messages=[
{"role": "user", "content": "What information do you have about...?"}
]
)

The API uses standard HTTP status codes:

  • 200 OK: Successful request
  • 201 Created: Resource created successfully
  • 202 Accepted: Request accepted for processing
  • 204 No Content: Successful deletion
  • 400 Bad Request: Invalid request parameters
  • 404 Not Found: Resource not found
  • 409 Conflict: Resource already exists

Error responses include detailed JSON messages to help with debugging and integration.

An external indexer uses an admin token to create a user, then uses the returned user token for all subsequent operations.

sequenceDiagram
    participant Indexer
    participant OpenRAG

    Note over Indexer, OpenRAG: 1. Create User (admin token)

    Indexer->>OpenRAG: POST /users<br/>Authorization: Bearer {admin_token}<br/>{display_name: "alice"}
    OpenRAG-->>Indexer: 201 {id: 2, token: "or-xxx..."}
    Indexer->>Indexer: Store user token "or-xxx..."

    Note over Indexer, OpenRAG: 2. Create Partition (user token). Automatically grants owner rights to the user

    Indexer->>OpenRAG: POST /partition/{partition}<br/>Authorization: Bearer or-xxx...
    OpenRAG-->>Indexer: 201 Created

    Note over Indexer, OpenRAG: 3. Index a File (user token)

    Indexer->>Indexer: New data

    Indexer->>OpenRAG: POST /indexer/partition/{partition}/file/{file_id}<br/>Authorization: Bearer or-xxx...<br/>Body: multipart (file + metadata)
    OpenRAG->>OpenRAG: Validate token, check file quota
    OpenRAG-->>Indexer: 201 {task_status_url: "{task_url}"}

    Note over OpenRAG: Background: serialize → chunk → embed → store

Query indexed documents via the OpenAI-compatible chat completions endpoint.

sequenceDiagram
    participant Client
    participant OpenRAG
    participant LLM

    Client->>OpenRAG: POST /v1/chat/completions<br/>Authorization: Bearer or-xxx...<br/>{model: "openrag-{partition}",<br/>messages: [...], stream: true}

    OpenRAG->>OpenRAG: Authenticate user
    OpenRAG->>OpenRAG: Resolve partition from model name
    OpenRAG->>OpenRAG: Check user has access to partition
    OpenRAG->>OpenRAG: Retrieve relevant documents
    OpenRAG->>OpenRAG: Build prompt with retrieved context
    OpenRAG->>LLM: Query LLM

    loop SSE Stream
        OpenRAG-->>Client: data: {delta: {content: "..."},<br/>sources: [...]}
    end
    OpenRAG-->>Client: data: [DONE]