HTTP API
Every route, what it takes and what it returns.
Ten routes. Six of them do the work; the rest are a sandbox and a visualiser.
| Method | Path | Status | What it does |
|---|---|---|---|
POST | /ingest | 200 | Ingest files inline — parsed, embedded and stored before the response |
POST | /jobs | 202 | Queue a file for the worker; returns a job_id immediately |
GET | /jobs/{job_id} | 200 | Job status: pending, running, complete, failed |
POST | /search | 200 | Search the corpus |
POST | /preview | 200 | Parse and chunk without embedding or storing |
GET | /health | 200 / 503 | Liveness, plus whether the vector store and the embedder answer |
GET | /visualize | 200 | A page for looking at the chunks |
GET | /retrieval_lab | 200 | A sandbox: chunk, embed and score one document in RAM |
POST | /retrieval_lab/prepare | 200 | Load a document into the sandbox |
POST | /retrieval_lab/search | 200 | Query the sandbox |
POST /ingest
Ingest one or more files. The response comes back after the documents are parsed, embedded and stored.
Form fields
| Field | Required | What it is |
|---|---|---|
files | yes | The file. Repeat for more than one. |
doc_ids | no | Comma-separated document ids, aligned with the files. Defaults to a generated uuid. |
chunking_mode | no | auto (default), balanced, precise, context_rich, custom. |
chunking_config | no | A JSON object of chunking overrides. Only used with chunking_mode=custom. |
curl -X POST http://localhost:8000/ingest \
-F "files=@./report.pdf" \
-F "files=@./notes.docx" \
-F "doc_ids=report,notes"{
"jobs": [
{"job_id": "…", "doc_id": "report", "filename": "report.pdf"},
{"job_id": "…", "doc_id": "notes", "filename": "notes.docx"}
]
}A file that fails to parse comes back with an error field on its job
rather than a silent success.
POST /jobs
Queue a file for asynchronous ingestion. The response is immediate; a worker claims the job and does the work.
curl -X POST http://localhost:8000/jobs -F "file=@./big-report.pdf"{"job_id": "…", "doc_id": "…", "filename": "big-report.pdf"}The document is held in the job queue until a worker claims it, so it
gets a tighter cap than the inline path: 50 MB. A larger body is
rejected with 413. A file whose declared content type contradicts its
bytes — a PDF that is really HTML — is rejected with 415.
The worker is a separate process:
python -m atrium.workerGET /jobs/{job_id}
{"status": "complete", "chunks_written": 82, "error": null}status is one of pending, running, complete, failed. A failed
job carries the reason in error.
POST /search
Search the corpus.
Body
| Field | Type | Default | What it is |
|---|---|---|---|
query | string | required | The question. |
top_k | integer | DEFAULT_TOP_K (8) | How many results. 1–100. |
rerank | boolean | null | follows RERANK_ENABLED | Tri-state: true forces the cross-encoder on, false forces it off. |
candidate_k | integer | the adapter's default | How many candidates to fetch before reranking. |
score_threshold | number | none | Drop results below this cosine similarity. |
curl -X POST http://localhost:8000/search \
-H 'Content-Type: application/json' \
-d '{"query": "retention policy", "top_k": 8, "rerank": false}'{
"query": "retention policy",
"top_k": 8,
"rerank": false,
"count": 8,
"took_ms": 41,
"results": [
{
"rank": 1,
"score": 0.781,
"chunk_id": "b0083c00-…",
"doc_id": "policy",
"text": "Records are retained for 24 months…",
"page_number": 14,
"section_path": ["Retention", "Data lifecycle"],
"element_type": "paragraph",
"chunking_strategy": "structure_aware",
"is_parent": false,
"parent_id": null,
"parent_text": null,
"parent_page_number": null,
"parent_section_path": []
}
]
}The result fields
| Field | What it is |
|---|---|
rank | Position in the result list, from 1. |
score | Cosine similarity against the query. |
chunk_id | The chunk's id. Stable for a given chunking strategy. |
doc_id | The document id you supplied, or a generated uuid. |
text | The chunk's text. |
page_number | The page the chunk starts on. |
section_path | The heading path above the chunk. |
element_type | heading, paragraph, list_item, table, code, image_caption or footnote. |
chunking_strategy | The strategy that produced this chunk. |
is_parent | Whether this chunk is a parent (context) chunk. |
parent_id | The parent chunk's id, if any. |
parent_text | The parent chunk's text, if any. |
parent_page_number | The parent chunk's page. |
parent_section_path | The parent chunk's heading path. |
page_number and section_path are the reason to use Atrium rather
than a chunker: they are what makes a retrieved passage citable.
POST /preview
Parse and chunk a document without embedding or storing it. Same form
fields as /ingest.
curl -X POST http://localhost:8000/preview \
-F "file=@./report.pdf" \
-F "chunking_mode=precise"GET /health
{"status": "ok", "db": true, "embedder": true, "vector_db_type": "qdrant"}200 when the service is up and the dependencies answer, 503 when it
is degraded. The container health check treats any response as "the
process is alive" — a 503 means the vector store is down, not that the
API needs restarting.
The retrieval lab
/retrieval_lab is a sandbox: it chunks, embeds and scores a single
uploaded document against an in-RAM cosine matrix. No vector store, no
sparse ranker, no reranker. It is for looking at one document; use
/search to query what you have actually ingested.
Authentication
With API_KEY set, every route except /health and /visualize
requires a bearer token:
curl -H "Authorization: Bearer $API_KEY" -X POST http://localhost:8000/search -d '{"query":"…"}'The schema browsers (/docs, /redoc, /openapi.json) are open.
Atrium Cloud
Don't want to run it yourself? Atrium Cloud is coming.
It is not here yet — the list is what there is until it is. The library is free, MIT licensed, and yours either way.