Zenith — Knowledge Engine
Status: Available · Spec: openapi/zenith.yaml · Base URL: https://zenith.dev.apex.reisiger.org
Zenith turns your document corpus into an answerable knowledge base. You ingest documents; Zenith parses, chunks, embeds, and indexes them; you query them with retrieval-augmented answers, structured extraction, checklist matching, or plain semantic search. Every answer cites its sources and reports its cost in ZAR.
Auth & tenancy: Bearer token (machine-to-machine JWT, or operator-enabled API key); tenant in the URL path — /api/v1/{tenant}/…. Path tenant must match the credential (tenancy rules).
The three query modes
POST /api/v1/{tenant}/query is the flagship. One endpoint, three modes:
| Mode | Returns | Use when |
|---|---|---|
rag (default) |
Grounded prose answer + sources[] citations + optional verification block |
Question answering, assistant features |
extract |
Structured JSON, optionally shaped by your output_schema |
Pulling fields/tables out of the corpus into your data model |
match |
Per-criterion scores against your match_criteria list |
Compliance checklists, submission reviews, gap analysis |
All three carry cost (ZAR breakdown) and honour X-Correlation-ID. POST /api/v1/{tenant}/batch-query runs multiple queries in parallel with the same mode set — per-item failures do not fail the batch.
Response essentials (rag mode): data.answer, data.sources[] (document id, chunk reference, relevance score — surface these; they are your provenance story), data.verification (when enabled for your tenant: confidence and claim checks), cost.total_zar.
Retrieval-only search
GET /api/v1/{tenant}/search?q=…&limit=… returns ranked passages with metadata — no language model is invoked and no generation cost is incurred. Use it when you want raw material for your own processing rather than a synthesised answer.
Ingestion
Corpus ingestion is asynchronous (submit-then-poll):
POST /api/v1/{tenant}/ingest— start a run; returnsjob_idimmediately.GET /api/v1/{tenant}/ingest/{job_id}— poll untilcompletedorfailed; progress counters included.
Where your corpus lives and how it reaches Zenith (storage location, formats, OCR for scanned material, sync cadence) is agreed at onboarding — ingestion sources are tenant configuration, not request parameters. Re-ingestion is content-aware: unchanged documents are not duplicated.
Ingestion runs (durable)
Larger corpora run through the durable runs surface — the same submit-then-poll shape, plus lifecycle control:
| Endpoint | Purpose |
|---|---|
POST /api/v1/{tenant}/ingest/runs |
Start a run (optionally scoped to specific sources or path prefixes) |
GET …/ingest/runs / …/runs/{run_id} |
List runs / full run detail with a per-file-type report |
GET …/runs/{run_id}/progress |
Live stage counters, throughput, and an ETA while the run is active |
POST …/runs/{run_id}/cancel / …/resume |
Stop an active run / continue an interrupted one where it left off |
Continuous sync
Sources can sync on a schedule instead of ad-hoc runs. GET …/ingest/sync-state shows each source's crawl checkpoint (incremental syncs fetch only what changed since the last pass). PUT …/ingest/sync-schedule/{source_id} sets a cadence and optional subtree scope; pause, resume, and sync-now subpaths control it. POST …/sync-state/{source_id}/reset forces the next run to re-crawl from scratch.
Failed documents
Documents that cannot be processed are parked, not silently dropped. GET …/ingest/failed-docs lists the open queue with per-stage and per-reason breakdowns (format=csv for export). Each record can be dismissed with an audit note, replaced by uploading a corrected file, or reopened. GET /api/v1/{tenant}/corpus/verification gives the headline reconciliation: how much of the discovered corpus is indexed, parked, or unaccounted for.
Knowledge graph
When enabled for your tenant, Zenith extracts an entity-relationship graph from the corpus and keeps it browsable:
GET /api/v1/{tenant}/graph/atlas— overview: entity/relation counts, thematic communities, and how they interconnect.GET …/graph/atlas/community/{community_id}— expand one community into its member entities and internal relations.GET …/graph/atlas/entity?name=…— a full dossier for one entity: its relations, communities, and the source documents that evidence it.GET …/graph/entitiesand…/graph/triples— paged raw browse, filterable by type, name, or source document.
Graph maintenance (extraction passes and refinement) is triggered per tenant via POST …/ingest/runs/kg-trailing and …/runs/kg-refine; both follow the async run lifecycle above.
Configuration view
GET /api/v1/{tenant}/config returns your tenant's effective Zenith configuration (active models, verification behaviour, corpus settings). It is read-only — changes go through your platform operator. This endpoint doubles as the canonical "is my tenant live" probe from the Quickstart.
Integration notes
- Citations are the contract. Build your UI to show sources from day one; retrofitting provenance is painful.
- Search vs query is a cost decision. Search is retrieval-only and cheap; query invokes generation. Route accordingly.
- Batch for fan-out. Checklist-style workloads (score 40 criteria) belong in
batch-query, not 40 sequential calls. - Expect corpus lag, not staleness. After ingestion completes, new content is queryable; poll the job rather than probing with queries.