Base URL: http://localhost:8000/api
All endpoints except /auth/register, /auth/login, /health, and /shared/{token} (public) require authentication.
# JWT Bearer Token
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# OR API Key
X-API-Key: dv_live_abc123...POST /api/auth/register
Content-Type: application/json
{"email": "user@example.com", "password": "securepassword"}
Response (201):
{"id": "uuid", "email": "user@example.com", "role": "editor", "token": "jwt..."}The first registered user is automatically assigned the admin role.
POST /api/auth/login
Content-Type: application/json
{"email": "user@example.com", "password": "securepassword"}
Response (200):
{"token": "jwt...", "user": {"id": "uuid", "email": "user@example.com", "role": "editor"}}Error (401): {"detail": "Invalid credentials"}
Error (429): {"detail": "Too many login attempts", "retry_after": 30}
GET /api/auth/me
Authorization: Bearer {token}
Response (200):
{"id": "uuid", "email": "user@example.com", "role": "editor"}POST /api/auth/api-keys
Authorization: Bearer {token}
Content-Type: application/json
{"name": "My Integration"}
Response (201):
{"id": "key-uuid", "name": "My Integration", "key": "dv_live_abc123...", "created_at": "..."}Note: The key field is only returned on creation. Store it securely.
POST /api/documents/upload
Authorization: Bearer {token}
Content-Type: multipart/form-data
file: (binary)
Response (202):
{"task_id": "uuid", "filename": "report.pdf", "status": "queued"}Supported formats: PDF, DOCX, PPTX, PNG, JPG, TIFF. Max size: 50MB.
GET /api/documents?page=1&page_size=20&search=quarterly&tags=finance&sort=uploaded_at&order=desc
Authorization: Bearer {token}
Response (200):
{
"items": [{"document_id": "uuid", "filename": "report.pdf", "page_count": 10, "chunk_count": 45, "source_type": "digital", "file_type": "pdf", "summary": "...", "uploaded_at": "...", "tags": ["finance"]}],
"total": 1, "page": 1, "total_pages": 1
}DELETE /api/documents/{document_id}
Authorization: Bearer {token}
Response (200): {"status": "deleted"}
GET /api/documents/tasks/{task_id}
Authorization: Bearer {token}
Response (200):
{"task_id": "uuid", "status": "processing", "progress": 0.65, "stage": "Embedding chunks", "error_message": null}Status values: queued, processing, completed, failed.
GET /api/documents/{document_id}/versions
Authorization: Bearer {token}
Response (200):
{"versions": [{"id": "uuid", "version_number": 2, "filename": "report_v2.pdf", "file_size": 2048, "is_current": true, "uploaded_at": "..."}]}POST /api/query
Authorization: Bearer {token}
Content-Type: application/json
{
"question": "What were the Q3 revenue figures?",
"document_ids": ["uuid1"], // optional, scope to specific docs
"session_id": "uuid", // optional, include chat history
"mode": "basic", // "basic" or "agent"
"no_cache": false // skip semantic cache
}
Response (200):
{
"answer": "According to the report, Q3 revenue was $4.2M...",
"citations": [
{"text": "Q3 revenue reached $4.2 million", "document_id": "uuid", "document_name": "report.pdf", "page": 5, "bbox": [72, 200, 540, 220], "chunk_id": "uuid"}
],
"confidence": 0.92,
"cached": false,
"mode": "basic"
}POST /api/query/stream
Authorization: Bearer {token}
Content-Type: application/json
{"question": "...", "session_id": "uuid"}
SSE Events:
event: token
data: {"content": "According"}
event: citation
data: {"text": "...", "document_id": "...", "page": 5}
event: guardrails
data: {"confidence": 0.92, "hallucination_filtered": false}
event: done
data: {"mode": "basic", "cached": false}
event: error
data: {"message": "Rate limit exceeded", "code": 429}
GET /api/sessions?page=1&page_size=20
Authorization: Bearer {token}
GET /api/sessions/{session_id}
Authorization: Bearer {token}
PATCH /api/sessions/{session_id}
Authorization: Bearer {token}
Content-Type: application/json
{"title": "New title"}
Response (200): {"id": "uuid", "title": "New title"}
POST /api/sessions/{session_id}/generate-title
Authorization: Bearer {token}
Uses LLM to generate a short title from the first user message.
Response (200): {"id": "uuid", "title": "Generated Title"}
DELETE /api/sessions/{session_id}
Authorization: Bearer {token}
GET /api/sessions/{session_id}/export?format=markdown
Authorization: Bearer {token}
Formats: markdown, pdf.
GET /api/documents/graph?threshold=0.5&max_nodes=200
Authorization: Bearer {token}
POST /api/feedback
Authorization: Bearer {token}
Content-Type: application/json
{"session_id": "uuid", "message_id": "uuid", "rating": "positive", "comment": "Very helpful!"}
GET /api/feedback/stats
Authorization: Bearer {token}
POST /api/documents/{document_id}/tags
Authorization: Bearer {token}
Content-Type: application/json
{"tags": ["finance", "quarterly"]}
DELETE /api/documents/{document_id}/tags/{tag}
Authorization: Bearer {token}
GET /api/admin/users
PUT /api/admin/users/{user_id}/role {"role": "editor"}
DELETE /api/admin/users/{user_id}
GET /api/admin/audit?action=login&user_id=uuid&page=1&page_size=50
POST /api/sessions/{id}/shares {"is_public": true, "expires_hours": 24}
GET /api/sessions/{id}/shares
DELETE /api/sessions/{id}/shares/{token}
GET /shared/{token} (public access for public shares)
GET /api/health # System health (no auth)
GET /api/metrics # Prometheus metrics (no auth)
| Endpoint | Viewer | Editor | Admin |
|---|---|---|---|
| Query | 30/min | 60/min | 150/min |
| Upload | 10/min | 20/min | 50/min |
| Auth | 5/min (per IP) | — | — |
Rate limit headers are included in responses:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1705312800All errors follow a consistent format:
{
"detail": "Human-readable error message"
}| Status | Meaning |
|---|---|
| 400 | Bad request (validation error) |
| 401 | Authentication required or failed |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 409 | Conflict (duplicate email, etc.) |
| 413 | Request body too large |
| 415 | Unsupported file format |
| 422 | Validation error (FastAPI) |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
| 502 | External service error (LLM API) |
| 504 | External service timeout |