{"openapi":"3.1.0","info":{"title":"Doclenz API","description":"Document intelligence API for text extraction, OCR, vision, audio transcription\nand LLM-based structured enrichment.\n\n**Authentication:** Send your API key in the `X-API-Key` header. Admin endpoints\nadditionally require `X-Admin-Key`.\n\n**Multi-tenancy:** Each API key is bound to a tenant. Files are isolated per\ntenant in MinIO and billing is tracked per tenant via Unidades de Processamento (UPs).\n\n**Content negotiation:** Use `Accept: application/json` (default),\n`Accept: application/x-toon` for 30–50% smaller LLM-friendly payloads, or\n`Accept: text/markdown` for human-readable output.\n","contact":{"name":"Doclenz Support","url":"https://doclenz.dev","email":"suporte@doclenz.dev"},"license":{"name":"Proprietary","url":"https://doclenz.dev/terms"},"version":"1.0.0"},"servers":[{"url":"https://doclenz.dev","description":"Production"},{"url":"http://localhost:8080","description":"Local development"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Admin","description":"API key management (requires X-Admin-Key)"},{"name":"Jobs","description":"Async job status and cancellation"},{"name":"Extraction","description":"Document extraction endpoints"},{"name":"System","description":"Health, metrics and supported formats"}],"paths":{"/v1/admin/keys/{key}":{"put":{"tags":["Admin"],"summary":"Update an API key","description":"Replaces the record for an existing key.","operationId":"updateKey","parameters":[{"name":"X-Admin-Key","in":"header","required":false,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyRecord"}}},"required":true},"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"AdminKeyAuth":[]}]},"delete":{"tags":["Admin"],"summary":"Revoke an API key","description":"Permanently deletes the key. Cannot be undone.","operationId":"deleteKey","parameters":[{"name":"X-Admin-Key","in":"header","required":false,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"AdminKeyAuth":[]}]}},"/v1/extract":{"post":{"tags":["Extraction"],"summary":"Extract content from a document","description":"Uploads a file and extracts its content as text chunks, optionally enriched with\nstructured data via a JSON schema. Supports PDF, DOCX, XLSX, HTML, CSV, images and text.\n\n**Pipelines:** `AUTO` (default, MIME-based routing), `TEXT`, `OCR`, `VISION`, `AUDIO`.\n\n**Async mode:** Pass `async=true` to queue the job; poll `/v1/jobs/{jobId}` for the result\nor configure a webhook in your API key to be notified on completion.\n\n**Content negotiation:** Set the `Accept` header to `application/json` (default),\n`application/x-toon`, or `text/markdown`.\n","operationId":"extract","parameters":[{"name":"async","in":"query","description":"If true, queues the job and returns 202 Accepted with a job_id","required":false,"schema":{"type":"boolean","default":false}},{"name":"pipeline","in":"query","description":"Extraction pipeline. AUTO routes based on MIME type + schema.","required":false,"schema":{"type":"string","default":"AUTO","enum":["AUTO","TEXT","OCR","VISION","AUDIO"]}},{"name":"vision_tier","in":"query","description":"Vision model tier: local, api, or api_premium","required":false,"schema":{"type":"string","default":"local"}},{"name":"vision_mode","in":"query","description":"Vision mode: auto, describe, detect_objects, extract_fields, classify","required":false,"schema":{"type":"string","default":"auto"}},{"name":"confidence_min","in":"query","description":"Minimum confidence for vision fallback","required":false,"schema":{"type":"number","format":"float","default":0.6}},{"name":"X-DocLens-Password","in":"header","description":"Password to decrypt the PDF if it's encrypted","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"Document file to extract (PDF, image, audio, etc.)"},"schema":{"type":"string","description":"Optional JSON schema for LLM Enrichment (structured extraction)"}},"required":["file"]}}}},"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"Synchronous extraction completed","content":{"*/*":{"schema":{"type":"object"}}}},"202":{"description":"Async job queued","content":{"*/*":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"object"}}}},"415":{"description":"DL-001: unsupported MIME type for sync endpoint","content":{"*/*":{"schema":{"type":"object"}}}},"422":{"description":"DL-002 (encrypted PDF) or DL-003 (corrupted file)","content":{"*/*":{"schema":{"type":"object"}}}},"429":{"description":"DL-010: monthly UP quota exceeded","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/v1/admin/keys":{"get":{"tags":["Admin"],"summary":"List all API keys","description":"Keys are returned masked (prefix + last 4 chars).","operationId":"listKeys","parameters":[{"name":"X-Admin-Key","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"AdminKeyAuth":[]}]},"post":{"tags":["Admin"],"summary":"Create a new API key","description":"Generates a key in the format `dlens_prod_{tenant}_{random}`. The full key is returned in the response only once — store it safely, it cannot be retrieved later.","operationId":"createKey","parameters":[{"name":"X-Admin-Key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}},"required":true},"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"AdminKeyAuth":[]}]}},"/v1/metrics":{"get":{"tags":["System"],"summary":"Billing usage by tenant","operationId":"metrics","responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/BillingUsage"}}}}}}}}},"/v1/metrics/workers":{"get":{"tags":["System"],"summary":"Worker metrics","description":"Returns real-time metrics from the audio and vision workers, published to Redis by each worker process. Returns empty maps if Redis is unavailable or workers are not running.","operationId":"workerMetrics","responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/v1/jobs/{jobId}":{"get":{"tags":["Jobs"],"summary":"Get async job result","description":"Returns the ExtractionResult for a job. Returns 404 if the job does not exist or has already been deleted. While the job is still processing, returns a placeholder result with status=processing.","operationId":"getJob","parameters":[{"name":"jobId","in":"path","description":"UUID of the job returned by /v1/extract?async=true","required":true,"schema":{"type":"string"}}],"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"Job found (completed, processing or failed)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExtractionResult"}}}},"404":{"description":"DL-404: job not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExtractionResult"}}}},"408":{"description":"DL-006: job still processing after 10-minute limit","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExtractionResult"}}}}}},"delete":{"tags":["Jobs"],"summary":"Delete async job","description":"Cancels a pending job and removes its temporary artifacts from MinIO. Completed jobs can also be deleted to free storage.","operationId":"deleteJob","parameters":[{"name":"jobId","in":"path","description":"UUID of the job to delete","required":true,"schema":{"type":"string"}}],"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"204":{"description":"Job deleted"},"404":{"description":"DL-404: job not found"}}}},"/v1/health":{"get":{"tags":["System"],"summary":"Health check","description":"Public endpoint (no auth required). Reports API status and, when Redis is available, the heartbeat status of the audio and vision workers.","operationId":"health","responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/v1/formats":{"get":{"tags":["formats-controller"],"operationId":"formats","responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/v1/admin/usage":{"get":{"tags":["Admin"],"summary":"UP usage per tenant","description":"Consumption joined with each tenant's quota, so a consumer can show usage against the limit. Lives under /v1/admin because /v1/metrics requires a tenant X-API-Key, which an administrator does not have.","operationId":"usage","parameters":[{"name":"X-Admin-Key","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"AdminKeyAuth":[]}]}},"/v1/admin/jobs":{"get":{"tags":["Admin"],"summary":"List recent jobs","description":"Newest first. Only covers the retention window (1 h while processing, 24 h once complete) — this is an operational view, not an audit log.","operationId":"listJobs","parameters":[{"name":"X-Admin-Key","in":"header","required":false,"schema":{"type":"string"}},{"name":"tenantId","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"400":{"description":"Bad Request","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}},"security":[{"AdminKeyAuth":[]}]}}},"components":{"schemas":{"ApiError":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"ApiKeyRecord":{"type":"object","properties":{"tenantId":{"type":"string"},"product":{"type":"string"},"requestsPerMinute":{"type":"integer","format":"int32"},"upsPerDay":{"type":"integer","format":"int32"},"upsPerMonth":{"type":"integer","format":"int32"},"features":{"type":"array","items":{"type":"string"}},"webhookUrl":{"type":"string"},"status":{"type":"string"},"active":{"type":"boolean"}}},"CreateKeyRequest":{"type":"object","properties":{"tenantId":{"type":"string"},"product":{"type":"string"},"requestsPerMinute":{"type":"integer","format":"int32"},"upsPerDay":{"type":"integer","format":"int32"},"upsPerMonth":{"type":"integer","format":"int32"},"features":{"type":"array","items":{"type":"string"}},"webhookUrl":{"type":"string"}}},"BillingUsage":{"type":"object","properties":{"tenantId":{"type":"string"},"totalUps":{"type":"integer","format":"int32"}}},"BillingInfo":{"type":"object","properties":{"tenantId":{"type":"string"},"upsConsumed":{"type":"integer","format":"int32"}}},"Chunk":{"type":"object","properties":{"index":{"type":"integer","format":"int32"},"text":{"type":"string"},"type":{"type":"string"},"page":{"type":"integer","format":"int32"},"tokens":{"type":"integer","format":"int32"},"hash":{"type":"string"}}},"DocumentMetadata":{"type":"object","properties":{"language":{"type":"string"},"languageConfidence":{"type":"number","format":"double"},"createdAt":{"type":"string","format":"date-time"},"author":{"type":"string"}}},"ExtractionResult":{"type":"object","properties":{"jobId":{"type":"string"},"status":{"type":"string"},"source":{"$ref":"#/components/schemas/SourceInfo"},"metadata":{"$ref":"#/components/schemas/DocumentMetadata"},"chunks":{"type":"array","items":{"$ref":"#/components/schemas/Chunk"}},"structured":{"$ref":"#/components/schemas/JsonNode"},"billing":{"$ref":"#/components/schemas/BillingInfo"},"processingMs":{"type":"integer","format":"int64"},"errorCode":{"type":"string"},"errorMessage":{"type":"string"}}},"JsonNode":{"type":"object","properties":{"empty":{"type":"boolean"},"array":{"type":"boolean"},"null":{"type":"boolean"},"object":{"type":"boolean"},"float":{"type":"boolean"},"container":{"type":"boolean"},"valueNode":{"type":"boolean"},"missingNode":{"type":"boolean"},"pojo":{"type":"boolean"},"floatingPointNumber":{"type":"boolean"},"short":{"type":"boolean"},"int":{"type":"boolean"},"long":{"type":"boolean"},"double":{"type":"boolean"},"bigDecimal":{"type":"boolean"},"bigInteger":{"type":"boolean"},"textual":{"type":"boolean","deprecated":true},"boolean":{"type":"boolean"},"binary":{"type":"boolean"},"nodeType":{"type":"string","enum":["ARRAY","BINARY","BOOLEAN","MISSING","NULL","NUMBER","OBJECT","POJO","STRING"]},"string":{"type":"boolean"},"integralNumber":{"type":"boolean"},"number":{"type":"boolean"},"embeddedValue":{"type":"boolean"}}},"SourceInfo":{"type":"object","properties":{"filename":{"type":"string"},"mimeType":{"type":"string"},"sizeBytes":{"type":"integer","format":"int64"},"hashSha256":{"type":"string"},"pages":{"type":"integer","format":"int32"}}}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","description":"Tenant API key issued via the admin portal.","name":"X-API-Key","in":"header"},"AdminKeyAuth":{"type":"apiKey","description":"Admin key for managing API keys. Separate from regular API keys.","name":"X-Admin-Key","in":"header"}}}}