Operations guide

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
The API is a pure enqueuer (it returns 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

VariablePurpose
NAUTRIS_WORKDIRJob store, uploads, trees, usage ledger
NAUTRIS_RAG_DBLanceDB path; enables /v1/search
NAUTRIS_API_KEYSname=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_AUTH1 to fail startup if no keys are configured
NAUTRIS_LICENSESigned license token (required; the server refuses to start without one)
NAUTRIS_WORKERSIn-process worker threads (0 = none)
NAUTRIS_BACKGROUND1 to enqueue for separate worker containers
NAUTRIS_FAST_MODEPer-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_OCROpt-in GPU VLM OCR tier for scanned or low-quality pages; unset = off. Requires the GPU image on a CUDA host
NAUTRIS_PII_ENGINEregex or presidio
NAUTRIS_PII_LANGUAGESPresidio NER languages, e.g. en,fr
NAUTRIS_RATE_LIMIT_RPMPer-key rate limit (0 = off); 429 + Retry-After
NAUTRIS_MAX_UPLOAD_MBPer-file upload cap on POST /v1/jobs
NAUTRIS_METRICS1 exposes Prometheus metrics at GET /metrics
NAUTRIS_PLUGINSAllowlist 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).

EndpointWhat
POST /v1/jobsSubmit files → job with per-document results
POST /v1/parseOne file → canonical tree inline
GET /v1/searchSemantic search with provenance
GET .../reviewFlagged PII awaiting a decision
POST .../reviewApprove (redact) or reject a PII flag
POST /v1/sources/{id}/syncDelta-sync a directory or S3/MinIO bucket
POST /v1/webhooksRegister a job.finished webhook
GET /v1/licensePlan, 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 ?");
Point either SDK at your own deployment, nothing is hosted for you. Registered sources can be a local directory or an 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.