Running it for real.
Everything past the quickstart: hardening, scaling, every configuration variable, the endpoint map, and the SDKs that wrap it all.
On this page
Production setup
The license stays mandatory. Optionally replace the default token with named operator keys; usage is metered per key either way:
export NAUTRIS_LICENSE="nl1...." # required: the server refuses to start without it
export NAUTRIS_API_KEYS="team-a=sk-secret-a,ci=sk-secret-b" # optional: replaces the default token
Scale horizontally
One image, two roles (API + workers) on a shared volume:
docker compose up --scale worker=4
job.status: "queued" immediately); the worker containers claim from the shared queue and do the extraction. Workers run unprivileged with no-new-privileges and resource caps; the API runs read-only. Add workers to scale extraction throughput.Configuration
| Variable | Purpose |
|---|---|
NAUTRIS_WORKDIR | Job store, uploads, trees, usage ledger |
NAUTRIS_RAG_DB | LanceDB path; enables /v1/search |
NAUTRIS_API_KEYS | name=secret,…; auth + per-key metering. A key can carry scopes in its name: reader:read=secret, ci:read+write=secret, ops:admin=secret (unscoped keys keep full access) |
NAUTRIS_REQUIRE_AUTH | 1 to fail startup if no keys are configured |
NAUTRIS_LICENSE | Signed license token (required; the server refuses to start without one) |
NAUTRIS_WORKERS | In-process worker threads (0 = none) |
NAUTRIS_BACKGROUND | 1 to enqueue for separate worker containers |
NAUTRIS_FAST_MODE | Per-page hybrid extraction: the model-free fast path handles born-digital pages (no models, runs on any CPU), docling handles the rest. Default on; 0 forces the full ML pipeline on every page. Deprecated alias: NAUTRIS_FAST_PDF |
NAUTRIS_VLM_OCR | Opt-in GPU VLM OCR tier for scanned or low-quality pages; unset = off. Requires the GPU image on a CUDA host |
NAUTRIS_PII_ENGINE | regex or presidio |
NAUTRIS_PII_LANGUAGES | Presidio NER languages, e.g. en,fr |
NAUTRIS_RATE_LIMIT_RPM | Per-key rate limit (0 = off); 429 + Retry-After |
NAUTRIS_MAX_UPLOAD_MB | Per-file upload cap on POST /v1/jobs |
NAUTRIS_METRICS | 1 exposes Prometheus metrics at GET /metrics |
NAUTRIS_PLUGINS | Allowlist of third-party plugin entry-point names to load (* for all); unset loads none |
API endpoints
Base path /v1. Auth via the X-API-Key header (except /v1/health).
| Endpoint | What |
|---|---|
POST /v1/jobs | Submit files → job with per-document results |
POST /v1/parse | One file → canonical tree inline |
GET /v1/search | Semantic search with provenance |
GET .../review | Flagged PII awaiting a decision |
POST .../review | Approve (redact) or reject a PII flag |
POST /v1/sources/{id}/sync | Delta-sync a directory or S3/MinIO bucket |
POST /v1/webhooks | Register a job.finished webhook |
GET /v1/license | Plan, quota position, days left |
List endpoints (/v1/jobs, /v1/dead-letters, /v1/audit, /v1/webhooks/deliveries) are keyset-paginated with ?cursor=; the next page token comes back in the X-Next-Cursor header. See the interactive API explorer for the full API with schemas and try-it-out.
SDKs
The SDKs are thin pass-throughs over the REST API, so every method maps 1:1 to an endpoint and there is no business logic to drift from the server. Both are distributed with your license grant, alongside the registry access. Python (the nautris[client] extra, httpx-based) and TypeScript (@nautris/client, universal fetch for Node, browsers, and edge runtimes).
# Python
from nautris.client import NautrisClient
client = NautrisClient("http://localhost:8000", api_key="dek_...") # the token from the logs / UI
result = client.parse("contract.pdf") # tree inline
hits = client.search("quelle est la clause de résiliation ?")
src = client.register_source("s3://corpus/legal") # filesystem or s3://
client.sync_source(src["id"]) # delta sync
// TypeScript
import { NautrisClient } from "@nautris/client";
const client = new NautrisClient({ baseUrl: "http://localhost:8000", apiKey: "dek_..." });
const result = await client.parse(file); // File | Blob | path
const hits = await client.search("quelle est la clause de résiliation ?");
s3:// bucket (S3 / MinIO); sync reprocesses only what changed. Prefer not to run anything? The hosted console exposes the same endpoint shapes: see the Console API.