# Delivery Note OCR API Specification Base URL: `https://` The API is frontend-agnostic. Web apps, mobile apps, CLI tools, automations, and the Hugging Face Space all consume the same HTTP contract. ## Authentication and Secrets This backend currently protects the upstream Mistral credential by keeping it on the server side as `MISTRAL_API_KEY`. Clients never send the provider key. Add caller authentication at the API gateway or with a FastAPI dependency before public internet exposure. ## Endpoints | Method | Path | Purpose | | --- | --- | --- | | `GET` | `/health` | Liveness and provider configuration status | | `GET` | `/v1/schema` | JSON schema used for structured extraction | | `POST` | `/v1/ocr` | Multipart image upload OCR/inference | | `POST` | `/v1/ocr/base64` | JSON base64 OCR/inference for non-browser clients | Interactive OpenAPI docs are available at `/docs` when the backend is running. ## `POST /v1/ocr` Request: `multipart/form-data` | Field | Type | Required | Description | | --- | --- | --- | --- | | `file` | file | yes | `.jpg`, `.jpeg`, `.png`, or `.webp` image | | `repair` | query bool | no | Defaults to `true`; applies deterministic repair | | `validate` | query bool | no | Defaults to `true`; returns validation warnings | Example: ```bash curl -X POST \ -F "file=@scan.jpg" \ "http://localhost:8000/v1/ocr?repair=true&validate=true" ``` ## `POST /v1/ocr/base64` Request body: ```json { "filename": "scan.jpg", "content_type": "image/jpeg", "image_base64": "", "repair": true, "validate": true } ``` ## Response Shape ```json { "filename": "scan.jpg", "content_type": "image/jpeg", "checksum_md5": "string", "annotation": { "delivery_note_full": {"value": "111565/2026", "confidence": 0.99}, "products": [] }, "schema_valid": true, "schema_errors": [], "validation_warnings": [], "repairs": [ { "path": "products[0].pharmacist_price_ttc", "original": 7.89, "value": 5.35, "reason": "derived from line_total_ttc / quantity" } ], "raw_provider_response": {}, "parse_error": null, "metadata": { "provider": "mistral", "model": "mistral-ocr-latest", "retry_count": 0, "critical_retry_reasons": [], "retry_reasons": [], "duration_ms": 1234 } } ``` Field notes: - `annotation` is the frontend-friendly structured extraction. Every leaf is a `{value, confidence}` object; `value` may be `null` when a field is absent. The annotation is always schema-clean — repair provenance never appears inside it. - `schema_valid` / `schema_errors` report whether the (post-repair) annotation validates against `/v1/schema`. Each error carries `path`, `message`, and `validator`. - `repairs` are structured, deterministic corrections applied server-side. Each record carries `path`, `original` (the OCR reading), `value` (the corrected number), and `reason` (the accounting identity used). - `validation_warnings` are non-blocking consistency notes (row-count, line arithmetic, total reconciliation) for human review. - `raw_provider_response` preserves the original OCR provider response for debugging and replay. Entity resolution against a client database (supplier / pharmacy / product matching) is **not** performed here; it is the CRM's responsibility. See `docs/client-integration-guide.md`. ## Deployment Backend: ```bash cp .env.example .env # edit MISTRAL_API_KEY in .env docker compose up --build ``` Hugging Face Space: 1. Create a Gradio Space. 2. Deploy the Gradio UI (`app.py`) with its dependencies. 3. Set `BACKEND_API_URL` to the deployed backend URL. No backend code changes are required when the frontend URL or hosting platform changes.