Quickstart
The five-minute path from clone to first extraction. For depth on every step, see the full integration guide.
1. Boot the stack
Section titled “1. Boot the stack”Required env (in .env):
POSTGRES_PASSWORD=<random>MINIO_ROOT_USER=<random>MINIO_ROOT_PASSWORD=<random>ARTIFACT_SIGNING_SECRET=<random>SESSION_SECRET=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
# Bootstrap the first platform adminBOOTSTRAP_PLATFORM_ADMIN_ENABLED=trueBOOTSTRAP_PLATFORM_ADMIN_EMAIL=admin@yourcompany.comBOOTSTRAP_PLATFORM_ADMIN_PASSWORD=<choose-one>
# Point the LLM row at a model server. These are first-boot seeds only.LLM_URL=https://your-vllm.internal:8000LLM_MODEL=qwen3-8b-instructLLM_BACKEND_KIND=vllmFor Ollama, OpenAI, Gemini, credentials, and runtime edits after first boot, see Infrastructure setup.
# Application + infra (no GPU model servers in stack):docker compose -f docker/docker-compose.yml up -d
# Or include the bundled local PaddleOCR-VL + GLM-OCR servers# (single-GPU, 24 GiB):docker compose -f docker/docker-compose.yml \ -f docker/docker-compose.local-models.yaml up -d2. Confirm health
Section titled “2. Confirm health”curl http://localhost:8080/v1/health{ "status": "ok", "components": { "database": true, "redis": true, "worker": true, "storage": true, "providers": { "paddleocr-vl": true, "glmocr-vl": true, "llm": true } }, "queue_depth": 0 }3. Create a tenant + invite a user
Section titled “3. Create a tenant + invite a user”docstack-admin tenant create --id acme --name "Acme Corp" \ --initial-admin-email admin@acme.comdocstack-admin user invite --tenant-id acme \ --email integrator@acme.com --role tenant_adminOpen the invite URL the CLI prints to set a password.
4. Mint an API key
Section titled “4. Mint an API key”docstack-admin api-keys create --tenant-id acme \ --user-email integrator@acme.com --name backlog-sync# → printed once: rk_<public>_<secret>The secret is unrecoverable — capture it now.
5. Submit a document
Section titled “5. Submit a document”API="http://localhost:8080"KEY="rk_<public>_<secret>"
JOB=$(curl -s -X POST "$API/v1/documents" \ -H "Authorization: Bearer $KEY" \ -F "file=@invoice.pdf" \ | jq -r .job_id)echo "submitted: $JOB"6. Poll for completion
Section titled “6. Poll for completion”while true; do RESPONSE=$(curl -s -H "Authorization: Bearer $KEY" \ "$API/v1/documents/$JOB") STATUS=$(echo "$RESPONSE" | jq -r .status) echo "status: $STATUS" case "$STATUS" in completed|needs_review|rejected|failed) break ;; esac sleep 2doneecho "$RESPONSE" | jq .canonical.markdownThat’s it. The response includes the full CanonicalOcrDocument (per-page blocks, tables, formulas, charts, seals) plus, if a template was applied, the structured extraction.parsed payload and any validation flags.
Where to go next
Section titled “Where to go next”- Full integration guide — every endpoint, every parameter, every failure mode.
- Infrastructure setup — configure OCR and LLM endpoints across vLLM, Ollama, OpenAI, and Gemini.
- API reference — interactive OpenAPI browser.
- Contract testing — keep your integration aligned with the API spec automatically.