MENU navbar-image

Introduction

API des Eingang-Dashboards. Quelle der Wahrheit für api/openapi.yaml und das generierte TypeScript-SDK.

Alle Endpoints liegen unter `/api/v1` und antworten in JSON. Angemeldet wird über die
Sanctum-SPA-Session: erst `GET /sanctum/csrf-cookie`, dann `POST /api/v1/auth/login` —
danach tragen Session-Cookie und `X-XSRF-TOKEN` jede Anfrage. Alles außer dem Login
antwortet ohne Session mit 401.

<aside>Diese Doku wird aus dem Laravel-Code generiert (`make api`) — nicht von Hand pflegen.</aside>

Authenticating requests

To authenticate requests, include a Cookie header with the value "eingang-session={SESSION_COOKIE}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Session-Cookie aus dem Login (POST /api/v1/auth/login nach GET /sanctum/csrf-cookie). Das SDK erledigt das über credentials: include.

Anmeldung

Sanctum-SPA-Session: erst GET /sanctum/csrf-cookie, dann Login; danach trägt das Session-Cookie die Anmeldung. Konten entstehen nur über php artisan users:create.

Login

Meldet mit E-Mail und Passwort an und startet die Session. Vorher muss der Client GET /sanctum/csrf-cookie geholt haben und X-XSRF-TOKEN mitschicken.

Example request:
curl --request POST \
    "http://localhost:8310/api/v1/auth/login" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"gbailey@example.net\",
    \"password\": \"|]|{+-\"
}"
const url = new URL(
    "http://localhost:8310/api/v1/auth/login"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "gbailey@example.net",
    "password": "|]|{+-"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "user": {
        "id": 1,
        "name": "Thomas",
        "email": "thomas@example.com"
    }
}
 

Example response (422):


{
    "message": "E-Mail oder Passwort stimmen nicht.",
    "errors": {
        "email": [
            "E-Mail oder Passwort stimmen nicht."
        ]
    }
}
 

Example response (429, Zu viele Versuche):


{
    "message": "Too Many Attempts."
}
 

Request      

POST api/v1/auth/login

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string     

Must be a valid email address. Example: gbailey@example.net

password   string     

Example: |]|{+-

Response

Response Fields

user   object     

Das angemeldete Konto.

id   integer     
name   string     
email   string     

Logout

requires authentication

Beendet die Session und macht das Cookie ungültig.

Example request:
curl --request POST \
    "http://localhost:8310/api/v1/auth/logout" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/auth/logout"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (204):

Empty response
 

Request      

POST api/v1/auth/logout

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Current user

requires authentication

Das angemeldete Konto der laufenden Session; ohne Session 401.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/auth/me" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/auth/me"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "user": {
        "id": 1,
        "name": "Thomas",
        "email": "thomas@example.com"
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/auth/me

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Response

Response Fields

user   object     

Das angemeldete Konto.

id   integer     
name   string     
email   string     

Eingänge

Posteingang: PDFs hochladen, die Pipeline (OCR → Auslesen → Fristen → Stempel → Ablage) läuft im Queue-Worker. Korrekturen und Bestätigen erzeugen Fristen, Stempel und Ablage neu.

List documents

requires authentication

Alle Eingänge, neueste zuerst, mit der nächsten offenen Frist.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/documents" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/documents"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "id": "01K6EXAMPLE0000000000000001",
            "originalName": "04-beschluss.pdf",
            "status": "ready",
            "receivedAt": "2026-10-01T09:14:05+02:00",
            "channel": "post",
            "pageCount": 2,
            "hasTextLayer": true,
            "documentType": "beschluss",
            "senderName": "Landgericht Augsburg",
            "senderType": "gericht",
            "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
            "fileNumber": "3 O 877/26",
            "nextDeadline": {
                "kind": "Sofortige Beschwerde",
                "notedEnd": "2026-10-15",
                "preDeadline": "2026-10-08",
                "daysLeft": 14,
                "isNotfrist": true
            },
            "deadlineCount": 1,
            "extractor": "staged",
            "dataLocation": "local",
            "error": null,
            "progress": {
                "extractor": "staged",
                "status": "succeeded",
                "stage": null,
                "startedAt": "2026-10-01T09:14:06+02:00",
                "durationMs": 11840,
                "stages": [
                    {
                        "stage": "text",
                        "ms": 410
                    },
                    {
                        "stage": "rules",
                        "ms": 620
                    },
                    {
                        "stage": "llm",
                        "ms": 10950
                    },
                    {
                        "stage": "ink",
                        "ms": 80
                    },
                    {
                        "stage": "merge",
                        "ms": 1
                    }
                ],
                "inkCandidates": 0
            },
            "createdAt": "2026-10-01T09:14:05+02:00"
        }
    ]
}
 

Request      

GET api/v1/documents

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Response

Response Fields

data   object[]     

Die Eingänge.

status   string     

Pipeline-Schritt.

Must be one of:
  • queued
  • ocr
  • extracting
  • ready
  • failed
  • confirmed
channel   string     

Eingangskanal.

Must be one of:
  • bea
  • post
  • fax
  • email
  • personal
pageCount   integer     

Seitenzahl, sobald die OCR durch ist.

hasTextLayer   boolean     

Das PDF hatte schon eine Textebene.

documentType   string     

Dokumentart laut Extraktions-Schema.

senderName   string     

Absender.

senderType   string     

Art des Absenders.

subject   string     

Betreff.

fileNumber   string     

Gerichtliches Aktenzeichen, sonst das eigene.

nextDeadline   object     

Nächste offene Frist mit notiertem Ende.

kind   string     

Art der Frist.

notedEnd   string     

Notiertes Fristende, YYYY-MM-DD.

isNotfrist   boolean     

Notfrist.

preDeadline   string     

Vorfrist, YYYY-MM-DD.

daysLeft   integer     

Tage bis zum notierten Ende, negativ wenn überschritten.

extractor   string     

Auslese-Weg des aktiven Laufs.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
dataLocation   string     

Wohin die Daten des aktiven Laufs gingen.

Must be one of:
  • local
  • eu
  • us
error   string     

Grund, wenn die Pipeline fehlschlug.

progress   object     

Fortschritt des laufenden, sonst des aktiven Auslese-Laufs je Stufe; null ohne Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
stage   string     

Stufe, die gerade läuft (bei failed die, an der er scheiterte); null, wenn fertig oder ohne Stufen.

startedAt   string     

Start des Laufs, ISO 8601.

durationMs   integer     

Dauer des Laufs ohne Vorlauf, sobald fertig.

stages   object[]     

Fertige Stufen in Reihenfolge: text (Vorlauf), bei staged dann rules, llm, ink, vision (nur bei farbiger Tinte), merge.

stage   string     

Stufe.

ms   integer     

Dauer in Millisekunden.

inkCandidates   integer     

Ausschnitte mit farbiger Tinte, die an das Vision-Modell gingen (0 = Stufe vision entfällt); null, solange die Tintenprüfung nicht lief oder ohne sie.

id   string     

ULID des Eingangs.

originalName   string     

Dateiname beim Upload.

receivedAt   string     

Eingang (Upload-Zeitpunkt oder erkannter physischer Stempel), ISO 8601.

deadlineCount   integer     

Anzahl der Fristen.

createdAt   string     

Upload-Zeitpunkt, ISO 8601.

Upload documents

requires authentication

Nimmt eine oder mehrere PDFs (je ≤ 30 MB) entgegen, legt das Original ab und stellt je Datei die Pipeline in die Queue. Die Antwort kommt sofort mit Status queued; den Fortschritt zeigt GET /documents.

Example request:
curl --request POST \
    "http://localhost:8310/api/v1/documents" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "channel=post"\
    --form "files[]=@/private/var/folders/8l/cm840xx94xv8cql8r7__swn40000gn/T/php9luusg25opus1PB2Kag" 
const url = new URL(
    "http://localhost:8310/api/v1/documents"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('channel', 'post');
body.append('files[]', document.querySelector('input[name="files[]"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());

Example response (201):


{
    "data": [
        {
            "id": "01K6EXAMPLE0000000000000001",
            "originalName": "04-beschluss.pdf",
            "status": "queued",
            "receivedAt": "2026-10-01T09:14:05+02:00",
            "channel": "post",
            "pageCount": null,
            "hasTextLayer": null,
            "documentType": null,
            "senderName": null,
            "senderType": null,
            "subject": null,
            "fileNumber": null,
            "nextDeadline": null,
            "deadlineCount": 0,
            "extractor": null,
            "dataLocation": null,
            "error": null,
            "progress": null,
            "createdAt": "2026-10-01T09:14:05+02:00"
        }
    ]
}
 

Example response (422, Keine PDF):


{
    "message": "Nur PDF-Dateien, bitte.",
    "errors": {
        "files.0": [
            "Nur PDF-Dateien, bitte."
        ]
    }
}
 

Request      

POST api/v1/documents

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: multipart/form-data

Accept        

Example: application/json

Body Parameters

files   file[]     

Eine PDF, höchstens 30 MB. Must be a file. Must not be greater than 30720 kilobytes.

channel   string  optional    

Wie die Post kam; gilt für alle Dateien des Uploads. Example: post

Must be one of:
  • bea
  • post
  • fax
  • email
  • personal

Response

Response Fields

data   object[]     

Die angelegten Eingänge, Status queued.

status   string     

Pipeline-Schritt.

Must be one of:
  • queued
  • ocr
  • extracting
  • ready
  • failed
  • confirmed
channel   string     

Eingangskanal.

Must be one of:
  • bea
  • post
  • fax
  • email
  • personal
pageCount   integer     

Seitenzahl, sobald die OCR durch ist.

hasTextLayer   boolean     

Das PDF hatte schon eine Textebene.

documentType   string     

Dokumentart laut Extraktions-Schema.

senderName   string     

Absender.

senderType   string     

Art des Absenders.

subject   string     

Betreff.

fileNumber   string     

Gerichtliches Aktenzeichen, sonst das eigene.

nextDeadline   object     

Nächste offene Frist mit notiertem Ende.

kind   string     

Art der Frist.

notedEnd   string     

Notiertes Fristende, YYYY-MM-DD.

isNotfrist   boolean     

Notfrist.

preDeadline   string     

Vorfrist, YYYY-MM-DD.

daysLeft   integer     

Tage bis zum notierten Ende, negativ wenn überschritten.

extractor   string     

Auslese-Weg des aktiven Laufs.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
dataLocation   string     

Wohin die Daten des aktiven Laufs gingen.

Must be one of:
  • local
  • eu
  • us
error   string     

Grund, wenn die Pipeline fehlschlug.

progress   object     

Fortschritt des laufenden, sonst des aktiven Auslese-Laufs je Stufe; null ohne Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
stage   string     

Stufe, die gerade läuft (bei failed die, an der er scheiterte); null, wenn fertig oder ohne Stufen.

startedAt   string     

Start des Laufs, ISO 8601.

durationMs   integer     

Dauer des Laufs ohne Vorlauf, sobald fertig.

stages   object[]     

Fertige Stufen in Reihenfolge: text (Vorlauf), bei staged dann rules, llm, ink, vision (nur bei farbiger Tinte), merge.

stage   string     

Stufe.

ms   integer     

Dauer in Millisekunden.

inkCandidates   integer     

Ausschnitte mit farbiger Tinte, die an das Vision-Modell gingen (0 = Stufe vision entfällt); null, solange die Tintenprüfung nicht lief oder ohne sie.

Get document

requires authentication

Ein Eingang mit allen geltenden Feldern (ausgelesen, darüber die Korrekturen), den Fristen mit Rechenweg, dem aktiven Auslese-Lauf und den Datei-URLs.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "id": "01K6EXAMPLE0000000000000001",
        "originalName": "04-beschluss.pdf",
        "status": "ready",
        "receivedAt": "2026-10-01T09:14:05+02:00",
        "channel": "post",
        "pageCount": 2,
        "hasTextLayer": true,
        "documentType": "beschluss",
        "senderName": "Landgericht Augsburg",
        "senderType": "gericht",
        "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
        "fileNumber": "3 O 877/26",
        "nextDeadline": {
            "kind": "Sofortige Beschwerde",
            "notedEnd": "2026-10-15",
            "preDeadline": "2026-10-08",
            "daysLeft": 14,
            "isNotfrist": true
        },
        "deadlineCount": 1,
        "extractor": "staged",
        "dataLocation": "local",
        "error": null,
        "progress": {
            "extractor": "staged",
            "status": "succeeded",
            "stage": null,
            "startedAt": "2026-10-01T09:14:06+02:00",
            "durationMs": 13210,
            "stages": [
                {
                    "stage": "text",
                    "ms": 3920
                },
                {
                    "stage": "rules",
                    "ms": 370
                },
                {
                    "stage": "llm",
                    "ms": 9620
                },
                {
                    "stage": "ink",
                    "ms": 135
                },
                {
                    "stage": "vision",
                    "ms": 3060
                },
                {
                    "stage": "merge",
                    "ms": 1
                }
            ],
            "inkCandidates": 2
        },
        "createdAt": "2026-10-01T09:14:05+02:00",
        "fields": {
            "document_type": "beschluss",
            "sender": {
                "type": "gericht",
                "name": "Landgericht Augsburg",
                "address": "Am Alten Einlaß 1, 86150 Augsburg"
            },
            "court": {
                "name": "Landgericht Augsburg",
                "chamber": "3. Zivilkammer"
            },
            "contact_person": {
                "name": "Wagner",
                "role": "Urkundsbeamtin der Geschäftsstelle",
                "phone": "0821 4711-3317",
                "email": "poststelle@lg-augsburg.example"
            },
            "letter_date": "2026-09-15",
            "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
            "file_numbers": {
                "court": "3 O 877/26",
                "own": "0731/26",
                "opponent": "L-117/26",
                "authority": "A-1/26",
                "prosecutor": "112 Js 4567/26"
            },
            "parties": {
                "claimant": "Hofmann Getränke GmbH",
                "defendant": "Sven Radtke",
                "client": "Hofmann Getränke GmbH",
                "opponent": "Sven Radtke"
            },
            "service": {
                "kind": "eeb",
                "date": "2026-09-30"
            },
            "existing_stamp": {
                "present": false,
                "received_date": "2026-09-30",
                "initials": "ao"
            },
            "handwritten_notes": [
                {
                    "text": "FA: 15.10.26",
                    "interpreted_as": "frist",
                    "date": "2026-10-15"
                }
            ],
            "deadlines": [
                {
                    "kind": "Sofortige Beschwerde",
                    "norm": "§ 569 ZPO",
                    "duration_text": "zwei Wochen",
                    "trigger": "zustellung",
                    "explicit_date": "2026-10-15",
                    "is_notfrist": true,
                    "source_quote": "Die sofortige Beschwerde ist binnen einer Notfrist von zwei Wochen einzulegen."
                }
            ],
            "hearings": [
                {
                    "kind": "Haupttermin",
                    "date": "2026-11-12",
                    "time": "10:30",
                    "room": "Sitzungssaal B 214",
                    "personal_appearance": true
                }
            ],
            "amounts": [
                {
                    "label": "Kosten",
                    "value_eur": 596.6
                }
            ],
            "amount_in_dispute_eur": 12400,
            "action_required": [
                {
                    "kind": "frist_notieren",
                    "note": "Sofortige Beschwerde notieren"
                }
            ],
            "summary": "Beschluss von Landgericht Augsburg vom 15.09.2026, Az. 3 O 877/26. Erkannte Fristen: Sofortige Beschwerde (zwei Wochen).",
            "tags": [
                "beschluss",
                "gericht",
                "notfrist"
            ],
            "confidence": {
                "document_type": 0.9
            }
        },
        "correctedFields": [
            "file_numbers"
        ],
        "deadlines": [
            {
                "id": "01K6EXAMPLE0000000000000002",
                "kind": "Sofortige Beschwerde",
                "norm": "§ 569 ZPO",
                "isNotfrist": true,
                "triggerDate": "2026-10-01",
                "legalEnd": "2026-10-15",
                "notedEnd": "2026-10-15",
                "preDeadline": "2026-10-08",
                "daysLeft": 14,
                "sourceQuote": "Die sofortige Beschwerde ist binnen einer Notfrist von zwei Wochen einzulegen.",
                "explanation": "Zustellung (Eingang in der Kanzlei) 01.10.2026 (Do) + 2 Wochen § 569 ZPO → 15.10.2026 (Do), Werktag, VF 08.10.2026 (Do), Notfrist",
                "quoteLocation": {
                    "page": 1,
                    "rects": [
                        [
                            302.5,
                            674.9,
                            199.1,
                            11.1
                        ],
                        [
                            73.7,
                            686.8,
                            428.4,
                            11.1
                        ]
                    ],
                    "score": 0.97,
                    "pageWidth": 595.3,
                    "pageHeight": 841.9,
                    "textLeft": 73.7,
                    "textRight": 521.4,
                    "estimated": false
                },
                "calculationSteps": [
                    {
                        "kind": "trigger",
                        "label": "Zustellung (Eingang in der Kanzlei)",
                        "date": "2026-10-01",
                        "note": "Fristbeginn am Folgetag (§ 187 Abs. 1 BGB)"
                    },
                    {
                        "kind": "end",
                        "label": "Rechnerisches Ende",
                        "date": "2026-10-15",
                        "note": "+ 2 Wochen § 569 ZPO (§ 188 Abs. 2 BGB)"
                    },
                    {
                        "kind": "pre_deadline",
                        "label": "Vorfrist",
                        "date": "2026-10-08",
                        "note": "Fristende − 7 Tage"
                    }
                ],
                "doneAt": "2026-10-02T10:00:00+02:00"
            }
        ],
        "run": {
            "id": "01K6EXAMPLE0000000000000003",
            "extractor": "staged",
            "model": "regex + fastino/gliner2-multi-v1 + qwen3.6:35b",
            "dataLocation": "local",
            "status": "succeeded",
            "durationMs": 13210,
            "inputTokens": 1200,
            "outputTokens": 800,
            "costUsd": 0,
            "notes": [
                "GLiNER-Sidecar aus: nur Regex-Felder."
            ],
            "error": "Ergebnis passt nicht zum Schema",
            "isComparison": false,
            "createdAt": "2026-10-01T09:14:07+02:00"
        },
        "files": {
            "original": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/original",
            "ocr": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/ocr",
            "stamped": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/stamped"
        },
        "pages": [
            "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/1",
            "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/2"
        ],
        "filedPath": "ablage/3 O 877-26/2026-10-01 Beschluss – Landgericht Augsburg.pdf",
        "ocrText": "Landgericht Augsburg …",
        "quotePositions": "text_layer",
        "confirmedAt": "2026-10-02T10:00:00+02:00"
    }
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diesen Eingang gibt es nicht."
}
 

Request      

GET api/v1/documents/{id}

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

Response

Response Fields

data   object     

Der Eingang.

status   string     

Pipeline-Schritt.

Must be one of:
  • queued
  • ocr
  • extracting
  • ready
  • failed
  • confirmed
channel   string     

Eingangskanal.

Must be one of:
  • bea
  • post
  • fax
  • email
  • personal
extractor   string     

Auslese-Weg des aktiven Laufs.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
dataLocation   string     

Wohin die Daten des aktiven Laufs gingen.

Must be one of:
  • local
  • eu
  • us
pageCount   integer     

Seitenzahl.

hasTextLayer   boolean     

Das PDF hatte schon eine Textebene.

documentType   string     

Dokumentart.

senderName   string     

Absender.

senderType   string     

Art des Absenders.

subject   string     

Betreff.

fileNumber   string     

Gerichtliches Aktenzeichen, sonst das eigene.

nextDeadline   object     

Nächste offene Frist.

kind   string     

Art der Frist.

notedEnd   string     

Notiertes Fristende, YYYY-MM-DD.

preDeadline   string     

Vorfrist, YYYY-MM-DD.

daysLeft   integer     

Tage bis zum notierten Ende, negativ wenn überschritten.

isNotfrist   boolean     

Notfrist.

error   string     

Grund, wenn die Pipeline fehlschlug.

progress   object     

Fortschritt des laufenden, sonst des aktiven Auslese-Laufs je Stufe; null ohne Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
stage   string     

Stufe, die gerade läuft (bei failed die, an der er scheiterte); null, wenn fertig oder ohne Stufen.

startedAt   string     

Start des Laufs, ISO 8601.

durationMs   integer     

Dauer des Laufs ohne Vorlauf, sobald fertig.

stages   object[]     

Fertige Stufen in Reihenfolge: text (Vorlauf), bei staged dann rules, llm, ink, vision (nur bei farbiger Tinte), merge.

stage   string     

Stufe.

ms   integer     

Dauer in Millisekunden.

inkCandidates   integer     

Ausschnitte mit farbiger Tinte, die an das Vision-Modell gingen (0 = Stufe vision entfällt); null, solange die Tintenprüfung nicht lief oder ohne sie.

fields   object     

Felder nach eingang.schema.json; null, solange nicht ausgelesen.

run   object     

Aktiver Auslese-Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
dataLocation   string     

Wohin die Daten gingen.

Must be one of:
  • local
  • eu
  • us
error   string     

Fehler des Laufs.

model   string     

Modell.

inputTokens   integer     

Eingabe-Tokens, soweit bekannt.

outputTokens   integer     

Ausgabe-Tokens, soweit bekannt.

costUsd   number     

Geschätzte Kosten in USD.

files   object     

URLs der Fassungen; null, solange es sie nicht gibt.

original   string     

Original-PDF.

ocr   string     

OCR-Fassung.

stamped   string     

Gestempelte Fassung.

pages   string[]     

URLs der Seitenbilder (PNG aus der OCR-Fassung), Seite 1 zuerst; leer, solange die OCR nicht durch ist.

filedPath   string     

Ablagepfad relativ zur Ablage-Wurzel.

ocrText   string     

Text aus Textebene oder OCR.

quotePositions   string     

Woher Fundstellen ihre Position haben: text_layer (Textebene, auch nach ocrmypdf), ocr_blocks (Absatz-Blöcke aus Mistral OCR, geschätzt), none (Mistral OCR ohne Positionen, keine Markierung); null vor dem Vorlauf.

Must be one of:
  • text_layer
  • ocr_blocks
  • none
confirmedAt   string     

Bestätigt am, ISO 8601.

deadlines   object[]     

Fristen, nach notiertem Ende sortiert.

norm   string     

Norm.

kind   string     

Art der Frist.

triggerDate   string     

Auslösedatum, YYYY-MM-DD.

legalEnd   string     

Gesetzliches Ende (§§ 187 ff. BGB, § 222 ZPO).

notedEnd   string     

Notiertes Ende nach Wochenend-Regel.

preDeadline   string     

Vorfrist.

daysLeft   integer     

Tage bis zum notierten Ende.

sourceQuote   string     

Zitat aus dem Dokument.

quoteLocation   object     

Fundstelle des Zitats in der durchsuchbaren Fassung; null, wenn es nicht sicher gefunden wurde.

page   integer     

Seite, ab 1.

rects   number[][]     

Je Zeile ein Rechteck [x, y, w, h] in pt, Ursprung oben links.

score   number     

Trefferquote 0–1 (ab 0,8 gilt das Zitat als gefunden).

pageWidth   number     

Seitenbreite in pt.

pageHeight   number     

Seitenhöhe in pt.

textLeft   number     

Linke Kante der Textspalte neben der Fundstelle in pt.

textRight   number     

Rechte Kante der Textspalte neben der Fundstelle in pt.

estimated   boolean     

Zeilen aus Mistrals Absatz-Blöcken geschätzt (Scan ohne Textebene), nicht aus Wort-Boxen.

calculationSteps   object[]     

Rechenweg in Schritten; leer, wenn nicht gerechnet werden konnte.

kind   string     

Art des Schritts.

Must be one of:
  • letter
  • fiction
  • trigger
  • end
  • month_end
  • shift
  • firm_rule
  • pre_deadline
label   string     

Bezeichnung des Schritts.

date   string     

Datum des Schritts, YYYY-MM-DD.

note   string     

Norm oder Begründung.

doneAt   string     

Erledigt am.

correctedFields   string[]     

Top-Level-Felder, die von Hand korrigiert wurden.

Update document

requires authentication

Korrekturen aus dem Modal: jedes mitgeschickte Top-Level-Feld unter fields ersetzt das ausgelesene ganz und wird gegen das Schema validiert. Danach werden Fristen neu berechnet, der Stempel neu gesetzt und die Ablage verschoben (nicht dupliziert).

Example request:
curl --request PATCH \
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"channel\": \"post\",
    \"fields\": {
        \"file_numbers\": {
            \"court\": \"2 O 123\\/26\",
            \"own\": \"0815\\/26\",
            \"opponent\": null,
            \"authority\": null,
            \"prosecutor\": null
        }
    }
}"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "channel": "post",
    "fields": {
        "file_numbers": {
            "court": "2 O 123\/26",
            "own": "0815\/26",
            "opponent": null,
            "authority": null,
            "prosecutor": null
        }
    }
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": {
        "id": "01K6EXAMPLE0000000000000001",
        "originalName": "04-beschluss.pdf",
        "status": "ready",
        "receivedAt": "2026-10-01T09:14:05+02:00",
        "channel": "post",
        "pageCount": 2,
        "hasTextLayer": true,
        "documentType": "beschluss",
        "senderName": "Landgericht Augsburg",
        "senderType": "gericht",
        "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
        "fileNumber": "3 O 877/26",
        "nextDeadline": {
            "kind": "Sofortige Beschwerde",
            "notedEnd": "2026-10-15",
            "preDeadline": "2026-10-08",
            "daysLeft": 14,
            "isNotfrist": true
        },
        "deadlineCount": 1,
        "extractor": "staged",
        "dataLocation": "local",
        "error": null,
        "progress": {
            "extractor": "staged",
            "status": "succeeded",
            "stage": null,
            "startedAt": "2026-10-01T09:14:06+02:00",
            "durationMs": 13210,
            "stages": [
                {
                    "stage": "text",
                    "ms": 3920
                },
                {
                    "stage": "rules",
                    "ms": 370
                },
                {
                    "stage": "llm",
                    "ms": 9620
                },
                {
                    "stage": "ink",
                    "ms": 135
                },
                {
                    "stage": "vision",
                    "ms": 3060
                },
                {
                    "stage": "merge",
                    "ms": 1
                }
            ],
            "inkCandidates": 2
        },
        "createdAt": "2026-10-01T09:14:05+02:00",
        "fields": {
            "document_type": "beschluss",
            "sender": {
                "type": "gericht",
                "name": "Landgericht Augsburg",
                "address": "Am Alten Einlaß 1, 86150 Augsburg"
            },
            "court": {
                "name": "Landgericht Augsburg",
                "chamber": "3. Zivilkammer"
            },
            "contact_person": {
                "name": "Wagner",
                "role": "Urkundsbeamtin der Geschäftsstelle",
                "phone": "0821 4711-3317",
                "email": "poststelle@lg-augsburg.example"
            },
            "letter_date": "2026-09-15",
            "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
            "file_numbers": {
                "court": "3 O 877/26",
                "own": "0731/26",
                "opponent": "L-117/26",
                "authority": "A-1/26",
                "prosecutor": "112 Js 4567/26"
            },
            "parties": {
                "claimant": "Hofmann Getränke GmbH",
                "defendant": "Sven Radtke",
                "client": "Hofmann Getränke GmbH",
                "opponent": "Sven Radtke"
            },
            "service": {
                "kind": "eeb",
                "date": "2026-09-30"
            },
            "existing_stamp": {
                "present": false,
                "received_date": "2026-09-30",
                "initials": "ao"
            },
            "handwritten_notes": [
                {
                    "text": "FA: 15.10.26",
                    "interpreted_as": "frist",
                    "date": "2026-10-15"
                }
            ],
            "deadlines": [
                {
                    "kind": "Sofortige Beschwerde",
                    "norm": "§ 569 ZPO",
                    "duration_text": "zwei Wochen",
                    "trigger": "zustellung",
                    "explicit_date": "2026-10-15",
                    "is_notfrist": true,
                    "source_quote": "Die sofortige Beschwerde ist binnen einer Notfrist von zwei Wochen einzulegen."
                }
            ],
            "hearings": [
                {
                    "kind": "Haupttermin",
                    "date": "2026-11-12",
                    "time": "10:30",
                    "room": "Sitzungssaal B 214",
                    "personal_appearance": true
                }
            ],
            "amounts": [
                {
                    "label": "Kosten",
                    "value_eur": 596.6
                }
            ],
            "amount_in_dispute_eur": 12400,
            "action_required": [
                {
                    "kind": "frist_notieren",
                    "note": "Sofortige Beschwerde notieren"
                }
            ],
            "summary": "Beschluss von Landgericht Augsburg vom 15.09.2026, Az. 3 O 877/26. Erkannte Fristen: Sofortige Beschwerde (zwei Wochen).",
            "tags": [
                "beschluss",
                "gericht",
                "notfrist"
            ],
            "confidence": {
                "document_type": 0.9
            }
        },
        "correctedFields": [
            "file_numbers"
        ],
        "deadlines": [
            {
                "id": "01K6EXAMPLE0000000000000002",
                "kind": "Sofortige Beschwerde",
                "norm": "§ 569 ZPO",
                "isNotfrist": true,
                "triggerDate": "2026-10-01",
                "legalEnd": "2026-10-15",
                "notedEnd": "2026-10-15",
                "preDeadline": "2026-10-08",
                "daysLeft": 14,
                "sourceQuote": "Die sofortige Beschwerde ist binnen einer Notfrist von zwei Wochen einzulegen.",
                "explanation": "Zustellung (Eingang in der Kanzlei) 01.10.2026 (Do) + 2 Wochen § 569 ZPO → 15.10.2026 (Do), Werktag, VF 08.10.2026 (Do), Notfrist",
                "quoteLocation": {
                    "page": 1,
                    "rects": [
                        [
                            302.5,
                            674.9,
                            199.1,
                            11.1
                        ],
                        [
                            73.7,
                            686.8,
                            428.4,
                            11.1
                        ]
                    ],
                    "score": 0.97,
                    "pageWidth": 595.3,
                    "pageHeight": 841.9,
                    "textLeft": 73.7,
                    "textRight": 521.4,
                    "estimated": false
                },
                "calculationSteps": [
                    {
                        "kind": "trigger",
                        "label": "Zustellung (Eingang in der Kanzlei)",
                        "date": "2026-10-01",
                        "note": "Fristbeginn am Folgetag (§ 187 Abs. 1 BGB)"
                    },
                    {
                        "kind": "end",
                        "label": "Rechnerisches Ende",
                        "date": "2026-10-15",
                        "note": "+ 2 Wochen § 569 ZPO (§ 188 Abs. 2 BGB)"
                    },
                    {
                        "kind": "pre_deadline",
                        "label": "Vorfrist",
                        "date": "2026-10-08",
                        "note": "Fristende − 7 Tage"
                    }
                ],
                "doneAt": "2026-10-02T10:00:00+02:00"
            }
        ],
        "run": {
            "id": "01K6EXAMPLE0000000000000003",
            "extractor": "staged",
            "model": "regex + fastino/gliner2-multi-v1 + qwen3.6:35b",
            "dataLocation": "local",
            "status": "succeeded",
            "durationMs": 13210,
            "inputTokens": 1200,
            "outputTokens": 800,
            "costUsd": 0,
            "notes": [
                "GLiNER-Sidecar aus: nur Regex-Felder."
            ],
            "error": "Ergebnis passt nicht zum Schema",
            "isComparison": false,
            "createdAt": "2026-10-01T09:14:07+02:00"
        },
        "files": {
            "original": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/original",
            "ocr": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/ocr",
            "stamped": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/stamped"
        },
        "pages": [
            "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/1",
            "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/2"
        ],
        "filedPath": "ablage/3 O 877-26/2026-10-01 Beschluss – Landgericht Augsburg.pdf",
        "ocrText": "Landgericht Augsburg …",
        "quotePositions": "text_layer",
        "confirmedAt": "2026-10-02T10:00:00+02:00"
    }
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diesen Eingang gibt es nicht."
}
 

Example response (409, Noch nicht ausgelesen):


{
    "message": "Der Eingang ist noch nicht fertig ausgelesen."
}
 

Example response (422, Passt nicht zum Schema):


{
    "message": "/letter_date: The data must match the 'date' format",
    "errors": {
        "fields": [
            "/letter_date: The data must match the 'date' format"
        ]
    }
}
 

Request      

PATCH api/v1/documents/{id}

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

Body Parameters

channel   string  optional    

Eingangskanal. Example: post

Must be one of:
  • bea
  • post
  • fax
  • email
  • personal
fields   object  optional    

Top-Level-Felder nach eingang.schema.json, die ersetzt werden (z. B. deadlines, file_numbers). Jedes mitgeschickte Feld ersetzt das ausgelesene ganz; danach werden Fristen, Stempel und Ablage neu erzeugt.

Response

Response Fields

data   object     

Der Eingang wie bei GET /documents/{id}.

status   string     

Pipeline-Schritt.

Must be one of:
  • queued
  • ocr
  • extracting
  • ready
  • failed
  • confirmed
channel   string     

Eingangskanal.

Must be one of:
  • bea
  • post
  • fax
  • email
  • personal
extractor   string     

Auslese-Weg des aktiven Laufs.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
dataLocation   string     

Wohin die Daten des aktiven Laufs gingen.

Must be one of:
  • local
  • eu
  • us
pageCount   integer     

Seitenzahl.

hasTextLayer   boolean     

Das PDF hatte schon eine Textebene.

documentType   string     

Dokumentart.

senderName   string     

Absender.

senderType   string     

Art des Absenders.

subject   string     

Betreff.

fileNumber   string     

Gerichtliches Aktenzeichen, sonst das eigene.

nextDeadline   object     

Nächste offene Frist.

kind   string     

Art der Frist.

notedEnd   string     

Notiertes Fristende, YYYY-MM-DD.

preDeadline   string     

Vorfrist, YYYY-MM-DD.

daysLeft   integer     

Tage bis zum notierten Ende, negativ wenn überschritten.

isNotfrist   boolean     

Notfrist.

error   string     

Grund, wenn die Pipeline fehlschlug.

progress   object     

Fortschritt des laufenden, sonst des aktiven Auslese-Laufs je Stufe; null ohne Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
stage   string     

Stufe, die gerade läuft (bei failed die, an der er scheiterte); null, wenn fertig oder ohne Stufen.

startedAt   string     

Start des Laufs, ISO 8601.

durationMs   integer     

Dauer des Laufs ohne Vorlauf, sobald fertig.

stages   object[]     

Fertige Stufen in Reihenfolge: text (Vorlauf), bei staged dann rules, llm, ink, vision (nur bei farbiger Tinte), merge.

stage   string     

Stufe.

ms   integer     

Dauer in Millisekunden.

inkCandidates   integer     

Ausschnitte mit farbiger Tinte, die an das Vision-Modell gingen (0 = Stufe vision entfällt); null, solange die Tintenprüfung nicht lief oder ohne sie.

fields   object     

Felder nach eingang.schema.json; null, solange nicht ausgelesen.

run   object     

Aktiver Auslese-Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
dataLocation   string     

Wohin die Daten gingen.

Must be one of:
  • local
  • eu
  • us
error   string     

Fehler des Laufs.

model   string     

Modell.

inputTokens   integer     

Eingabe-Tokens, soweit bekannt.

outputTokens   integer     

Ausgabe-Tokens, soweit bekannt.

costUsd   number     

Geschätzte Kosten in USD.

files   object     
original   string     

Original-PDF.

ocr   string     

OCR-Fassung.

stamped   string     

Gestempelte Fassung.

pages   string[]     

URLs der Seitenbilder (PNG aus der OCR-Fassung), Seite 1 zuerst; leer, solange die OCR nicht durch ist.

filedPath   string     

Ablagepfad relativ zur Ablage-Wurzel.

ocrText   string     

Text aus Textebene oder OCR.

quotePositions   string     

Woher Fundstellen ihre Position haben: text_layer (Textebene, auch nach ocrmypdf), ocr_blocks (Absatz-Blöcke aus Mistral OCR, geschätzt), none (Mistral OCR ohne Positionen, keine Markierung); null vor dem Vorlauf.

Must be one of:
  • text_layer
  • ocr_blocks
  • none
confirmedAt   string     

Bestätigt am, ISO 8601.

deadlines   object     
norm   string     

Norm.

kind   string     

Art der Frist.

triggerDate   string     

Auslösedatum, YYYY-MM-DD.

legalEnd   string     

Gesetzliches Ende (§§ 187 ff. BGB, § 222 ZPO).

notedEnd   string     

Notiertes Ende nach Wochenend-Regel.

preDeadline   string     

Vorfrist.

daysLeft   integer     

Tage bis zum notierten Ende.

sourceQuote   string     

Zitat aus dem Dokument.

quoteLocation   object     

Fundstelle des Zitats in der durchsuchbaren Fassung; null, wenn es nicht sicher gefunden wurde.

page   integer     

Seite, ab 1.

rects   number[][]     

Je Zeile ein Rechteck [x, y, w, h] in pt, Ursprung oben links.

score   number     

Trefferquote 0–1 (ab 0,8 gilt das Zitat als gefunden).

pageWidth   number     

Seitenbreite in pt.

pageHeight   number     

Seitenhöhe in pt.

textLeft   number     

Linke Kante der Textspalte neben der Fundstelle in pt.

textRight   number     

Rechte Kante der Textspalte neben der Fundstelle in pt.

estimated   boolean     

Zeilen aus Mistrals Absatz-Blöcken geschätzt (Scan ohne Textebene), nicht aus Wort-Boxen.

calculationSteps   object[]     

Rechenweg in Schritten; leer, wenn nicht gerechnet werden konnte.

kind   string     

Art des Schritts.

Must be one of:
  • letter
  • fiction
  • trigger
  • end
  • month_end
  • shift
  • firm_rule
  • pre_deadline
label   string     

Bezeichnung des Schritts.

date   string     

Datum des Schritts, YYYY-MM-DD.

note   string     

Norm oder Begründung.

doneAt   string     

Erledigt am.

Confirm document

requires authentication

„Bestätigen & ablegen“: setzt den Eingang auf confirmed, stempelt neu und legt ab. Ein zweiter Aufruf ändert nichts mehr.

Example request:
curl --request POST \
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/confirm" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/confirm"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "id": "01K6EXAMPLE0000000000000001",
        "originalName": "04-beschluss.pdf",
        "status": "ready",
        "receivedAt": "2026-10-01T09:14:05+02:00",
        "channel": "post",
        "pageCount": 2,
        "hasTextLayer": true,
        "documentType": "beschluss",
        "senderName": "Landgericht Augsburg",
        "senderType": "gericht",
        "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
        "fileNumber": "3 O 877/26",
        "nextDeadline": {
            "kind": "Sofortige Beschwerde",
            "notedEnd": "2026-10-15",
            "preDeadline": "2026-10-08",
            "daysLeft": 14,
            "isNotfrist": true
        },
        "deadlineCount": 1,
        "extractor": "staged",
        "dataLocation": "local",
        "error": null,
        "progress": {
            "extractor": "staged",
            "status": "succeeded",
            "stage": null,
            "startedAt": "2026-10-01T09:14:06+02:00",
            "durationMs": 13210,
            "stages": [
                {
                    "stage": "text",
                    "ms": 3920
                },
                {
                    "stage": "rules",
                    "ms": 370
                },
                {
                    "stage": "llm",
                    "ms": 9620
                },
                {
                    "stage": "ink",
                    "ms": 135
                },
                {
                    "stage": "vision",
                    "ms": 3060
                },
                {
                    "stage": "merge",
                    "ms": 1
                }
            ],
            "inkCandidates": 2
        },
        "createdAt": "2026-10-01T09:14:05+02:00",
        "fields": {
            "document_type": "beschluss",
            "sender": {
                "type": "gericht",
                "name": "Landgericht Augsburg",
                "address": "Am Alten Einlaß 1, 86150 Augsburg"
            },
            "court": {
                "name": "Landgericht Augsburg",
                "chamber": "3. Zivilkammer"
            },
            "contact_person": {
                "name": "Wagner",
                "role": "Urkundsbeamtin der Geschäftsstelle",
                "phone": "0821 4711-3317",
                "email": "poststelle@lg-augsburg.example"
            },
            "letter_date": "2026-09-15",
            "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
            "file_numbers": {
                "court": "3 O 877/26",
                "own": "0731/26",
                "opponent": "L-117/26",
                "authority": "A-1/26",
                "prosecutor": "112 Js 4567/26"
            },
            "parties": {
                "claimant": "Hofmann Getränke GmbH",
                "defendant": "Sven Radtke",
                "client": "Hofmann Getränke GmbH",
                "opponent": "Sven Radtke"
            },
            "service": {
                "kind": "eeb",
                "date": "2026-09-30"
            },
            "existing_stamp": {
                "present": false,
                "received_date": "2026-09-30",
                "initials": "ao"
            },
            "handwritten_notes": [
                {
                    "text": "FA: 15.10.26",
                    "interpreted_as": "frist",
                    "date": "2026-10-15"
                }
            ],
            "deadlines": [
                {
                    "kind": "Sofortige Beschwerde",
                    "norm": "§ 569 ZPO",
                    "duration_text": "zwei Wochen",
                    "trigger": "zustellung",
                    "explicit_date": "2026-10-15",
                    "is_notfrist": true,
                    "source_quote": "Die sofortige Beschwerde ist binnen einer Notfrist von zwei Wochen einzulegen."
                }
            ],
            "hearings": [
                {
                    "kind": "Haupttermin",
                    "date": "2026-11-12",
                    "time": "10:30",
                    "room": "Sitzungssaal B 214",
                    "personal_appearance": true
                }
            ],
            "amounts": [
                {
                    "label": "Kosten",
                    "value_eur": 596.6
                }
            ],
            "amount_in_dispute_eur": 12400,
            "action_required": [
                {
                    "kind": "frist_notieren",
                    "note": "Sofortige Beschwerde notieren"
                }
            ],
            "summary": "Beschluss von Landgericht Augsburg vom 15.09.2026, Az. 3 O 877/26. Erkannte Fristen: Sofortige Beschwerde (zwei Wochen).",
            "tags": [
                "beschluss",
                "gericht",
                "notfrist"
            ],
            "confidence": {
                "document_type": 0.9
            }
        },
        "correctedFields": [
            "file_numbers"
        ],
        "deadlines": [
            {
                "id": "01K6EXAMPLE0000000000000002",
                "kind": "Sofortige Beschwerde",
                "norm": "§ 569 ZPO",
                "isNotfrist": true,
                "triggerDate": "2026-10-01",
                "legalEnd": "2026-10-15",
                "notedEnd": "2026-10-15",
                "preDeadline": "2026-10-08",
                "daysLeft": 14,
                "sourceQuote": "Die sofortige Beschwerde ist binnen einer Notfrist von zwei Wochen einzulegen.",
                "explanation": "Zustellung (Eingang in der Kanzlei) 01.10.2026 (Do) + 2 Wochen § 569 ZPO → 15.10.2026 (Do), Werktag, VF 08.10.2026 (Do), Notfrist",
                "quoteLocation": {
                    "page": 1,
                    "rects": [
                        [
                            302.5,
                            674.9,
                            199.1,
                            11.1
                        ],
                        [
                            73.7,
                            686.8,
                            428.4,
                            11.1
                        ]
                    ],
                    "score": 0.97,
                    "pageWidth": 595.3,
                    "pageHeight": 841.9,
                    "textLeft": 73.7,
                    "textRight": 521.4,
                    "estimated": false
                },
                "calculationSteps": [
                    {
                        "kind": "trigger",
                        "label": "Zustellung (Eingang in der Kanzlei)",
                        "date": "2026-10-01",
                        "note": "Fristbeginn am Folgetag (§ 187 Abs. 1 BGB)"
                    },
                    {
                        "kind": "end",
                        "label": "Rechnerisches Ende",
                        "date": "2026-10-15",
                        "note": "+ 2 Wochen § 569 ZPO (§ 188 Abs. 2 BGB)"
                    },
                    {
                        "kind": "pre_deadline",
                        "label": "Vorfrist",
                        "date": "2026-10-08",
                        "note": "Fristende − 7 Tage"
                    }
                ],
                "doneAt": "2026-10-02T10:00:00+02:00"
            }
        ],
        "run": {
            "id": "01K6EXAMPLE0000000000000003",
            "extractor": "staged",
            "model": "regex + fastino/gliner2-multi-v1 + qwen3.6:35b",
            "dataLocation": "local",
            "status": "succeeded",
            "durationMs": 13210,
            "inputTokens": 1200,
            "outputTokens": 800,
            "costUsd": 0,
            "notes": [
                "GLiNER-Sidecar aus: nur Regex-Felder."
            ],
            "error": "Ergebnis passt nicht zum Schema",
            "isComparison": false,
            "createdAt": "2026-10-01T09:14:07+02:00"
        },
        "files": {
            "original": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/original",
            "ocr": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/ocr",
            "stamped": "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/stamped"
        },
        "pages": [
            "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/1",
            "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/2"
        ],
        "filedPath": "ablage/3 O 877-26/2026-10-01 Beschluss – Landgericht Augsburg.pdf",
        "ocrText": "Landgericht Augsburg …",
        "quotePositions": "text_layer",
        "confirmedAt": "2026-10-02T10:00:00+02:00"
    }
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diesen Eingang gibt es nicht."
}
 

Example response (409, Noch nicht ausgelesen):


{
    "message": "Der Eingang ist noch nicht fertig ausgelesen."
}
 

Request      

POST api/v1/documents/{id}/confirm

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

Response

Response Fields

data   object     

Der Eingang wie bei GET /documents/{id}.

status   string     

Pipeline-Schritt.

Must be one of:
  • queued
  • ocr
  • extracting
  • ready
  • failed
  • confirmed
channel   string     

Eingangskanal.

Must be one of:
  • bea
  • post
  • fax
  • email
  • personal
extractor   string     

Auslese-Weg des aktiven Laufs.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
dataLocation   string     

Wohin die Daten des aktiven Laufs gingen.

Must be one of:
  • local
  • eu
  • us
pageCount   integer     

Seitenzahl.

hasTextLayer   boolean     

Das PDF hatte schon eine Textebene.

documentType   string     

Dokumentart.

senderName   string     

Absender.

senderType   string     

Art des Absenders.

subject   string     

Betreff.

fileNumber   string     

Gerichtliches Aktenzeichen, sonst das eigene.

nextDeadline   object     

Nächste offene Frist.

kind   string     

Art der Frist.

notedEnd   string     

Notiertes Fristende, YYYY-MM-DD.

preDeadline   string     

Vorfrist, YYYY-MM-DD.

daysLeft   integer     

Tage bis zum notierten Ende, negativ wenn überschritten.

isNotfrist   boolean     

Notfrist.

error   string     

Grund, wenn die Pipeline fehlschlug.

progress   object     

Fortschritt des laufenden, sonst des aktiven Auslese-Laufs je Stufe; null ohne Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
stage   string     

Stufe, die gerade läuft (bei failed die, an der er scheiterte); null, wenn fertig oder ohne Stufen.

startedAt   string     

Start des Laufs, ISO 8601.

durationMs   integer     

Dauer des Laufs ohne Vorlauf, sobald fertig.

stages   object[]     

Fertige Stufen in Reihenfolge: text (Vorlauf), bei staged dann rules, llm, ink, vision (nur bei farbiger Tinte), merge.

stage   string     

Stufe.

ms   integer     

Dauer in Millisekunden.

inkCandidates   integer     

Ausschnitte mit farbiger Tinte, die an das Vision-Modell gingen (0 = Stufe vision entfällt); null, solange die Tintenprüfung nicht lief oder ohne sie.

fields   object     

Felder nach eingang.schema.json; null, solange nicht ausgelesen.

run   object     

Aktiver Auslese-Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
dataLocation   string     

Wohin die Daten gingen.

Must be one of:
  • local
  • eu
  • us
error   string     

Fehler des Laufs.

model   string     

Modell.

inputTokens   integer     

Eingabe-Tokens, soweit bekannt.

outputTokens   integer     

Ausgabe-Tokens, soweit bekannt.

costUsd   number     

Geschätzte Kosten in USD.

files   object     
original   string     

Original-PDF.

ocr   string     

OCR-Fassung.

stamped   string     

Gestempelte Fassung.

pages   string[]     

URLs der Seitenbilder (PNG aus der OCR-Fassung), Seite 1 zuerst; leer, solange die OCR nicht durch ist.

filedPath   string     

Ablagepfad relativ zur Ablage-Wurzel.

ocrText   string     

Text aus Textebene oder OCR.

quotePositions   string     

Woher Fundstellen ihre Position haben: text_layer (Textebene, auch nach ocrmypdf), ocr_blocks (Absatz-Blöcke aus Mistral OCR, geschätzt), none (Mistral OCR ohne Positionen, keine Markierung); null vor dem Vorlauf.

Must be one of:
  • text_layer
  • ocr_blocks
  • none
confirmedAt   string     

Bestätigt am, ISO 8601.

deadlines   object     
norm   string     

Norm.

kind   string     

Art der Frist.

triggerDate   string     

Auslösedatum, YYYY-MM-DD.

legalEnd   string     

Gesetzliches Ende (§§ 187 ff. BGB, § 222 ZPO).

notedEnd   string     

Notiertes Ende nach Wochenend-Regel.

preDeadline   string     

Vorfrist.

daysLeft   integer     

Tage bis zum notierten Ende.

sourceQuote   string     

Zitat aus dem Dokument.

quoteLocation   object     

Fundstelle des Zitats in der durchsuchbaren Fassung; null, wenn es nicht sicher gefunden wurde.

page   integer     

Seite, ab 1.

rects   number[][]     

Je Zeile ein Rechteck [x, y, w, h] in pt, Ursprung oben links.

score   number     

Trefferquote 0–1 (ab 0,8 gilt das Zitat als gefunden).

pageWidth   number     

Seitenbreite in pt.

pageHeight   number     

Seitenhöhe in pt.

textLeft   number     

Linke Kante der Textspalte neben der Fundstelle in pt.

textRight   number     

Rechte Kante der Textspalte neben der Fundstelle in pt.

estimated   boolean     

Zeilen aus Mistrals Absatz-Blöcken geschätzt (Scan ohne Textebene), nicht aus Wort-Boxen.

calculationSteps   object[]     

Rechenweg in Schritten; leer, wenn nicht gerechnet werden konnte.

kind   string     

Art des Schritts.

Must be one of:
  • letter
  • fiction
  • trigger
  • end
  • month_end
  • shift
  • firm_rule
  • pre_deadline
label   string     

Bezeichnung des Schritts.

date   string     

Datum des Schritts, YYYY-MM-DD.

note   string     

Norm oder Begründung.

doneAt   string     

Erledigt am.

Get document file

requires authentication

Liefert eine Fassung als PDF: original (unverändert), ocr (mit Textebene) oder stamped (mit digitalem Eingangsstempel). Inline für die Vorschau; mit ?download=1 als Anhang.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/stamped?download=" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/files/stamped"
);

const params = {
    "download": "0",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

Binary data -  Die PDF-Datei.
 

Example response (404, Fassung gibt es (noch) nicht):


{
    "message": "Diese Fassung gibt es nicht."
}
 

Request      

GET api/v1/documents/{id}/files/{file}

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

file   string     

Die Fassung. Example: stamped

Must be one of:
  • original
  • ocr
  • stamped

Query Parameters

download   boolean  optional    

Als Datei herunterladen statt inline anzeigen. Example: false

Get document page image

requires authentication

Liefert ein Seitenbild der OCR-Fassung als PNG (150 dpi). Die Fundstellen der Fristen (quoteLocation, in pt) liegen auf genau diesen Seiten.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/1" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/pages/1"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

Binary data -  Das Seitenbild als PNG.
 

Example response (404, Seite gibt es (noch) nicht):


{
    "message": "Diese Seite gibt es nicht."
}
 

Request      

GET api/v1/documents/{id}/pages/{page}

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

page   integer     

Seite, ab 1. Example: 1

Extract document

requires authentication

„Mit … neu auslesen“: legt einen Lauf mit dem gewählten Weg an und startet ihn im Queue-Worker. Gelingt er, wird er der aktive Lauf; Fristen, Stempel und Ablage werden neu erzeugt, Korrekturen bleiben. Fehlt dem Weg die Konfiguration (Key), kommt der Lauf sofort als failed mit Grund zurück, ohne dass etwas das Haus verlässt. Den Fortschritt zeigt GET /documents/{id}/runs.

Example request:
curl --request POST \
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/extract" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"extractor\": \"ollama_text\"
}"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/extract"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "extractor": "ollama_text"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (202):


{
    "data": {
        "id": "01K6EXAMPLE0000000000000009",
        "extractor": "ollama_text",
        "model": null,
        "dataLocation": "local",
        "status": "running",
        "durationMs": null,
        "inputTokens": null,
        "outputTokens": null,
        "costUsd": null,
        "notes": [],
        "error": null,
        "isComparison": false,
        "createdAt": "2026-10-01T09:20:00+02:00"
    }
}
 

Example response (202, Weg nicht konfiguriert):


{
    "data": {
        "id": "01K6EXAMPLE0000000000000010",
        "extractor": "claude",
        "model": null,
        "dataLocation": "us",
        "status": "failed",
        "durationMs": 0,
        "inputTokens": null,
        "outputTokens": null,
        "costUsd": null,
        "notes": [],
        "error": "Nicht konfiguriert: ANTHROPIC_API_KEY fehlt.",
        "isComparison": false,
        "createdAt": "2026-10-01T09:20:00+02:00"
    }
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diesen Eingang gibt es nicht."
}
 

Example response (409, Vorlauf läuft noch):


{
    "message": "Der Eingang wird noch vorverarbeitet."
}
 

Example response (422, Unbekannter Weg):


{
    "message": "Unbekannter Auslese-Weg.",
    "errors": {
        "extractor": [
            "Unbekannter Auslese-Weg."
        ]
    }
}
 

Request      

POST api/v1/documents/{id}/extract

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

Body Parameters

extractor   string     

Auslese-Weg. claude schickt das PDF in die USA (Anthropic), mistral in die EU; die übrigen laufen lokal. Example: ollama_text

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake

Response

Response Fields

data   object     

Der angelegte Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
dataLocation   string     

Wohin die Daten gehen.

Must be one of:
  • local
  • eu
  • us
model   string     

Modell, sobald der Lauf fertig ist.

durationMs   integer     

Dauer in Millisekunden, sobald fertig.

inputTokens   integer     

Eingabe-Tokens, soweit bekannt.

outputTokens   integer     

Ausgabe-Tokens, soweit bekannt.

costUsd   number     

Geschätzte Kosten in USD (lokal 0).

error   string     

Grund, wenn der Lauf fehlschlug.

id   string     

ULID des Laufs.

notes   string[]     

Einschränkungen des Laufs.

isComparison   boolean     

Lauf aus dem Vergleich; wird nie der aktive Lauf.

createdAt   string     

Angelegt am, ISO 8601.

List runs

requires authentication

Alle Auslese-Läufe eines Eingangs, neueste zuerst, mit normalisiertem Ergebnis.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/runs" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/runs"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "id": "01K6EXAMPLE0000000000000009",
            "extractor": "ollama_text",
            "model": "qwen3.6:27b",
            "dataLocation": "local",
            "status": "succeeded",
            "durationMs": 48210,
            "inputTokens": 5210,
            "outputTokens": 812,
            "costUsd": 0,
            "notes": [],
            "error": null,
            "isComparison": false,
            "createdAt": "2026-10-01T09:20:00+02:00",
            "result": {
                "document_type": "beschluss",
                "sender": {
                    "type": "gericht",
                    "name": "Landgericht Augsburg",
                    "address": "Am Alten Einlaß 1, 86150 Augsburg"
                },
                "court": {
                    "name": "Landgericht Augsburg",
                    "chamber": "3. Zivilkammer"
                },
                "contact_person": {
                    "name": "Wagner",
                    "role": "Urkundsbeamtin der Geschäftsstelle",
                    "phone": "0821 4711-3317",
                    "email": "poststelle@lg-augsburg.example"
                },
                "letter_date": "2026-09-15",
                "subject": "Hofmann Getränke GmbH ./. Sven Radtke wegen Kaufpreisforderung",
                "file_numbers": {
                    "court": "3 O 877/26",
                    "own": "0731/26",
                    "opponent": "L-117/26",
                    "authority": "A-1/26",
                    "prosecutor": "112 Js 4567/26"
                },
                "parties": {
                    "claimant": "Hofmann Getränke GmbH",
                    "defendant": "Sven Radtke",
                    "client": "Hofmann Getränke GmbH",
                    "opponent": "Sven Radtke"
                },
                "service": {
                    "kind": "eeb",
                    "date": "2026-09-30"
                },
                "existing_stamp": {
                    "present": false,
                    "received_date": "2026-09-30",
                    "initials": "ao"
                },
                "handwritten_notes": [
                    {
                        "text": "FA: 15.10.26",
                        "interpreted_as": "frist",
                        "date": "2026-10-15"
                    }
                ],
                "deadlines": [
                    {
                        "kind": "Sofortige Beschwerde",
                        "norm": "§ 569 ZPO",
                        "duration_text": "zwei Wochen",
                        "trigger": "zustellung",
                        "explicit_date": "2026-10-15",
                        "is_notfrist": true,
                        "source_quote": "Die sofortige Beschwerde ist binnen einer Notfrist von zwei Wochen einzulegen."
                    }
                ],
                "hearings": [
                    {
                        "kind": "Haupttermin",
                        "date": "2026-11-12",
                        "time": "10:30",
                        "room": "Sitzungssaal B 214",
                        "personal_appearance": true
                    }
                ],
                "amounts": [
                    {
                        "label": "Kosten",
                        "value_eur": 596.6
                    }
                ],
                "amount_in_dispute_eur": 12400,
                "action_required": [
                    {
                        "kind": "frist_notieren",
                        "note": "Sofortige Beschwerde notieren"
                    }
                ],
                "summary": "Beschluss von Landgericht Augsburg vom 15.09.2026, Az. 3 O 877/26. Erkannte Fristen: Sofortige Beschwerde (zwei Wochen).",
                "tags": [
                    "beschluss",
                    "gericht",
                    "notfrist"
                ],
                "confidence": {
                    "document_type": 0.9
                }
            },
            "timings": [
                {
                    "stage": "llm",
                    "ms": 48190,
                    "ollama": {
                        "total_ms": 48150,
                        "load_ms": 120,
                        "prompt_eval_ms": 9400,
                        "prompt_eval_tokens": 5210,
                        "eval_ms": 38480,
                        "eval_tokens": 812
                    }
                }
            ]
        },
        {
            "id": "01K6EXAMPLE0000000000000010",
            "extractor": "claude",
            "model": null,
            "dataLocation": "us",
            "status": "failed",
            "durationMs": 0,
            "inputTokens": null,
            "outputTokens": null,
            "costUsd": null,
            "notes": [],
            "error": "Nicht konfiguriert: ANTHROPIC_API_KEY fehlt.",
            "isComparison": false,
            "createdAt": "2026-10-01T09:18:00+02:00",
            "result": null,
            "timings": null
        }
    ]
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diesen Eingang gibt es nicht."
}
 

Request      

GET api/v1/documents/{id}/runs

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

Response

Response Fields

data   object[]     

Die Läufe.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
dataLocation   string     

Wohin die Daten gingen.

Must be one of:
  • local
  • eu
  • us
model   string     

Modell.

durationMs   integer     

Dauer in Millisekunden.

inputTokens   integer     

Eingabe-Tokens, soweit bekannt.

outputTokens   integer     

Ausgabe-Tokens, soweit bekannt.

costUsd   number     

Geschätzte Kosten in USD (lokal 0).

error   string     

Grund, wenn der Lauf fehlschlug.

result   object     

Normalisiertes Ergebnis nach eingang.schema.json; null, solange der Lauf nicht gelang.

timings   object[]     

Dauer je Stufe in Reihenfolge (text = Vorlauf, falls direkt davor; beim Treiber z. B. images, llm, bei staged rules, llm, ink, vision, merge); null ohne Messung. Ollama-Stufen von staged tragen zusätzlich model, ink die Zahl der Ausschnitte candidates. Solange der Lauf läuft, stehen hier die fertigen Stufen.

stage   string     

Stufe, z. B. text, rules, llm, ink, vision.

ms   integer     

Dauer der Stufe in Millisekunden.

ollama   object     

Kennzahlen der Ollama-Antwort in Millisekunden und Tokens; nur bei Ollama-Stufen.

total_ms   integer     

Gesamtdauer laut Ollama; null, wenn Ollama sie nicht meldet.

load_ms   integer     

Laden des Modells.

prompt_eval_ms   integer     

Eingabe verarbeiten.

prompt_eval_tokens   integer     

Eingabe-Tokens.

eval_ms   integer     

Ausgabe erzeugen.

eval_tokens   integer     

Ausgabe-Tokens.

id   string     

ULID des Laufs.

notes   string[]     

Einschränkungen des Laufs.

isComparison   boolean     

Lauf aus dem Vergleich; wird nie der aktive Lauf.

createdAt   string     

Angelegt am, ISO 8601.

Compare extractors

requires authentication

„Alle Wege laufen lassen“ im Debug-Vergleich: legt je gewähltem Weg einen Lauf an und startet ihn im Queue-Worker. Diese Läufe werden nicht der aktive Lauf; Felder, Fristen, Stempel und Ablage bleiben unverändert. Ein Weg, der auf diesem Eingang schon läuft, wird übersprungen. Ergebnis und Bewertung zeigt GET /documents/{id}/comparison.

Example request:
curl --request POST \
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/compare" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"extractors\": [
        \"rules\"
    ]
}"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/compare"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "extractors": [
        "rules"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (202):


{
    "data": [
        {
            "id": "01K6EXAMPLE0000000000000011",
            "extractor": "ollama_text",
            "model": null,
            "dataLocation": "local",
            "status": "running",
            "durationMs": null,
            "inputTokens": null,
            "outputTokens": null,
            "costUsd": null,
            "notes": [],
            "error": null,
            "isComparison": true,
            "createdAt": "2026-10-01T09:30:00+02:00"
        },
        {
            "id": "01K6EXAMPLE0000000000000012",
            "extractor": "rules",
            "model": null,
            "dataLocation": "local",
            "status": "running",
            "durationMs": null,
            "inputTokens": null,
            "outputTokens": null,
            "costUsd": null,
            "notes": [],
            "error": null,
            "isComparison": true,
            "createdAt": "2026-10-01T09:30:00+02:00"
        }
    ]
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diesen Eingang gibt es nicht."
}
 

Example response (409, Vorlauf läuft noch):


{
    "message": "Der Eingang wird noch vorverarbeitet."
}
 

Example response (422, Unbekannter Weg):


{
    "message": "Unbekannter Auslese-Weg.",
    "errors": {
        "extractors.0": [
            "Unbekannter Auslese-Weg."
        ]
    }
}
 

Request      

POST api/v1/documents/{id}/compare

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

Body Parameters

extractors   string[]     

Ein Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake

Response

Response Fields

data   object[]     

Die angelegten Läufe.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
dataLocation   string     

Wohin die Daten gehen.

Must be one of:
  • local
  • eu
  • us
model   string     

Modell, sobald der Lauf fertig ist.

durationMs   integer     

Dauer in Millisekunden, sobald fertig.

inputTokens   integer     

Eingabe-Tokens, soweit bekannt.

outputTokens   integer     

Ausgabe-Tokens, soweit bekannt.

costUsd   number     

Geschätzte Kosten in USD (lokal 0).

error   string     

Grund, wenn der Lauf fehlschlug.

id   string     

ULID des Laufs.

notes   string[]     

Einschränkungen des Laufs.

isComparison   boolean     

Lauf aus dem Vergleich; wird nie der aktive Lauf.

createdAt   string     

Angelegt am, ISO 8601.

Get comparison

requires authentication

Feld × Weg für den Debug-Vergleich: je Auslese-Weg der neueste Lauf mit seinen Werten, bewertet gegen die Soll-Lösung, falls der Eingang byte-gleich ein Sample des Testsatzes ist (private Samples erscheinen als „privat-N“). Groß/Klein und Leerzeichen zählen nicht, Listen sind Mengen; Freitext (Betreff, Zusammenfassung, Tags) wird nicht bewertet.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/comparison" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/documents/01K6EXAMPLE0000000000000001/comparison"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "sample": "02-urteil-ag",
        "fields": [
            {
                "path": "document_type",
                "group": "document_type",
                "expected": "urteil"
            },
            {
                "path": "sender.type",
                "group": "sender",
                "expected": "gericht"
            },
            {
                "path": "sender.name",
                "group": "sender",
                "expected": "Amtsgericht München"
            },
            {
                "path": "sender.address",
                "group": "sender",
                "expected": "Pacellistraße 5, 80333 München"
            },
            {
                "path": "contact_person.name",
                "group": "sender",
                "expected": "Kaya"
            },
            {
                "path": "contact_person.role",
                "group": "sender",
                "expected": "Urkundsbeamtin der Geschäftsstelle"
            },
            {
                "path": "contact_person.phone",
                "group": "sender",
                "expected": null
            },
            {
                "path": "contact_person.email",
                "group": "sender",
                "expected": null
            },
            {
                "path": "court.name",
                "group": "sender",
                "expected": "Amtsgericht München"
            },
            {
                "path": "court.chamber",
                "group": "sender",
                "expected": "Abteilung 231"
            },
            {
                "path": "file_numbers.court",
                "group": "file_numbers",
                "expected": "231 C 4567/26"
            },
            {
                "path": "file_numbers.own",
                "group": "file_numbers",
                "expected": "0799/26"
            },
            {
                "path": "file_numbers.opponent",
                "group": "file_numbers",
                "expected": "HW-2026-118"
            },
            {
                "path": "file_numbers.authority",
                "group": "file_numbers",
                "expected": null
            },
            {
                "path": "file_numbers.prosecutor",
                "group": "file_numbers",
                "expected": null
            },
            {
                "path": "parties.claimant",
                "group": "parties",
                "expected": "Laura Seidl"
            },
            {
                "path": "parties.defendant",
                "group": "parties",
                "expected": "Tobias Wirth"
            },
            {
                "path": "parties.client",
                "group": "parties",
                "expected": "Tobias Wirth"
            },
            {
                "path": "parties.opponent",
                "group": "parties",
                "expected": "Laura Seidl"
            },
            {
                "path": "letter_date",
                "group": "dates",
                "expected": "2026-09-17"
            },
            {
                "path": "service.kind",
                "group": "dates",
                "expected": "eeb"
            },
            {
                "path": "service.date",
                "group": "dates",
                "expected": null
            },
            {
                "path": "deadlines",
                "group": "deadlines",
                "expected": "§ 517 ZPO · zustellung; § 520 Abs. 2 ZPO · zustellung"
            },
            {
                "path": "hearings",
                "group": "deadlines",
                "expected": null
            },
            {
                "path": "amounts",
                "group": "amounts",
                "expected": "2.180,00"
            },
            {
                "path": "amount_in_dispute_eur",
                "group": "amounts",
                "expected": "3.240,00"
            },
            {
                "path": "action_required",
                "group": "actions",
                "expected": "frist_notieren; mandant_informieren"
            },
            {
                "path": "existing_stamp.present",
                "group": "stamp",
                "expected": "nein"
            },
            {
                "path": "existing_stamp.received_date",
                "group": "stamp",
                "expected": null
            },
            {
                "path": "existing_stamp.initials",
                "group": "stamp",
                "expected": null
            },
            {
                "path": "handwritten_notes",
                "group": "stamp",
                "expected": null
            }
        ],
        "runs": [
            {
                "id": "01K6EXAMPLE0000000000000011",
                "extractor": "ollama_text",
                "dataLocation": "local",
                "status": "succeeded",
                "model": "qwen3.6:27b",
                "durationMs": 48210,
                "costUsd": 0,
                "error": null,
                "isActive": false,
                "matched": 20,
                "compared": 22,
                "values": [
                    {
                        "path": "document_type",
                        "value": "urteil",
                        "match": true
                    },
                    {
                        "path": "sender.type",
                        "value": "gericht",
                        "match": true
                    },
                    {
                        "path": "sender.name",
                        "value": "AMTSGERICHT  münchen",
                        "match": true
                    },
                    {
                        "path": "sender.address",
                        "value": "Pacellistraße 5, 80333 München",
                        "match": true
                    },
                    {
                        "path": "contact_person.name",
                        "value": "Kaya",
                        "match": true
                    },
                    {
                        "path": "contact_person.role",
                        "value": "Urkundsbeamtin der Geschäftsstelle",
                        "match": true
                    },
                    {
                        "path": "contact_person.phone",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "contact_person.email",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "court.name",
                        "value": "Amtsgericht München",
                        "match": true
                    },
                    {
                        "path": "court.chamber",
                        "value": "Abt. 231",
                        "match": false
                    },
                    {
                        "path": "file_numbers.court",
                        "value": "231 C 4567/26",
                        "match": true
                    },
                    {
                        "path": "file_numbers.own",
                        "value": null,
                        "match": false
                    },
                    {
                        "path": "file_numbers.opponent",
                        "value": "HW-2026-118",
                        "match": true
                    },
                    {
                        "path": "file_numbers.authority",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "file_numbers.prosecutor",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "parties.claimant",
                        "value": "Laura Seidl",
                        "match": true
                    },
                    {
                        "path": "parties.defendant",
                        "value": "Tobias Wirth",
                        "match": true
                    },
                    {
                        "path": "parties.client",
                        "value": "Tobias Wirth",
                        "match": true
                    },
                    {
                        "path": "parties.opponent",
                        "value": "Laura Seidl",
                        "match": true
                    },
                    {
                        "path": "letter_date",
                        "value": "2026-09-17",
                        "match": true
                    },
                    {
                        "path": "service.kind",
                        "value": "eeb",
                        "match": true
                    },
                    {
                        "path": "service.date",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "deadlines",
                        "value": "§ 520 Abs. 2 ZPO · zustellung; § 517 ZPO · zustellung",
                        "match": true
                    },
                    {
                        "path": "hearings",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "amounts",
                        "value": "2.180,00",
                        "match": true
                    },
                    {
                        "path": "amount_in_dispute_eur",
                        "value": "3.240,00",
                        "match": true
                    },
                    {
                        "path": "action_required",
                        "value": "frist_notieren; mandant_informieren",
                        "match": true
                    },
                    {
                        "path": "existing_stamp.present",
                        "value": "nein",
                        "match": true
                    },
                    {
                        "path": "existing_stamp.received_date",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "existing_stamp.initials",
                        "value": null,
                        "match": null
                    },
                    {
                        "path": "handwritten_notes",
                        "value": null,
                        "match": null
                    }
                ],
                "createdAt": "2026-10-01T09:30:00+02:00"
            }
        ]
    }
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diesen Eingang gibt es nicht."
}
 

Request      

GET api/v1/documents/{id}/comparison

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Eingangs. Example: 01K6EXAMPLE0000000000000001

Response

Response Fields

data   object     

Der Vergleich.

sample   string     

Sample mit Soll-Lösung; null, wenn der Eingang keins ist.

fields   object[]     

Bewertete Felder in fester Reihenfolge.

group   string     

Feldgruppe.

Must be one of:
  • document_type
  • sender
  • file_numbers
  • parties
  • dates
  • deadlines
  • amounts
  • actions
  • stamp
expected   string     

Soll-Wert lesbar; null, wenn leer oder ohne Soll-Lösung.

path   string     

Feldpfad, z. B. sender.name.

runs   object[]     

Je Weg der neueste Lauf.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
dataLocation   string     

Wohin die Daten gingen.

Must be one of:
  • local
  • eu
  • us
status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
model   string     

Modell.

durationMs   integer     

Dauer in Millisekunden.

costUsd   number     

Geschätzte Kosten in USD.

error   string     

Grund, wenn der Lauf fehlschlug.

matched   integer     

Getroffene Felder; null ohne Soll-Lösung.

compared   integer     

Bewertete Felder; null ohne Soll-Lösung.

values   object[]     

Werte je Feld, in der Reihenfolge von fields.

value   string     

Wert lesbar; null, wenn leer.

match   boolean     

Trifft die Soll-Lösung; null, wenn nicht bewertet.

path   string     

Feldpfad.

id   string     

ULID des Laufs.

isActive   boolean     

Der Lauf gilt gerade für den Eingang.

createdAt   string     

Angelegt am, ISO 8601.

Einstellungen

Die Einstellungen der Kanzlei: Stempel, Bundesland, Vorfrist, Wochenend-Regel und der Standard-Auslese-Weg. Es gibt genau einen Satz für die Kanzlei, nicht je Konto. Der Datenort von staged kommt aus der Server-Konfiguration und ist hier nur zu lesen.

Get settings

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/settings" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/settings"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "firmName": "Muster & Partner Rechtsanwälte",
        "stampInitials": "ao",
        "state": "BY",
        "preDeadlineDays": 7,
        "weekendRule": "move_earlier",
        "defaultExtractor": "staged",
        "stampCorner": "top_right",
        "stagedDataLocation": "local"
    }
}
 

Request      

GET api/v1/settings

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Response

Response Fields

data   object     

Die Einstellungen.

state   string     

Bundesland für die Landesfeiertage.

Must be one of:
  • BW
  • BY
  • BE
  • BB
  • HB
  • HH
  • HE
  • MV
  • NI
  • NW
  • RP
  • SL
  • SN
  • ST
  • SH
  • TH
weekendRule   string     

Wochenend-Regel für das notierte Fristende.

Must be one of:
  • move_earlier
  • move_later_legal
defaultExtractor   string     

Standard-Auslese-Weg; nie ein Cloud-Weg, staged folgt der Anbieter-Konfiguration.

Must be one of:
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
stampCorner   string     

Ecke des digitalen Stempels auf Seite 1.

Must be one of:
  • top_right
  • top_left
  • bottom_right
  • bottom_left
stagedDataLocation   string     

Wohin staged Daten schickt, aus der Anbieter-Konfiguration je Stufe (nur lesbar).

Must be one of:
  • local
  • eu
  • us
firmName   string     

Kanzleiname im Stempel.

stampInitials   string     

Kürzel im Stempel.

preDeadlineDays   integer     

Vorfrist in Tagen.

Update settings

requires authentication

Teil-Update: nur mitgeschickte Felder ändern sich. Cloud-Wege (claude, mistral) sind als Standard nicht erlaubt; staged schon, auch wenn seine Stufen per Konfiguration bei Mistral laufen.

Example request:
curl --request PATCH \
    "http://localhost:8310/api/v1/settings" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"firm_name\": \"Muster & Partner Rechtsanwälte\",
    \"stamp_initials\": \"ao\",
    \"state\": \"BY\",
    \"pre_deadline_days\": 7,
    \"weekend_rule\": \"move_earlier\",
    \"default_extractor\": \"staged\",
    \"stamp_corner\": \"top_right\"
}"
const url = new URL(
    "http://localhost:8310/api/v1/settings"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "firm_name": "Muster & Partner Rechtsanwälte",
    "stamp_initials": "ao",
    "state": "BY",
    "pre_deadline_days": 7,
    "weekend_rule": "move_earlier",
    "default_extractor": "staged",
    "stamp_corner": "top_right"
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": {
        "firmName": "Muster & Partner Rechtsanwälte",
        "stampInitials": "ao",
        "state": "BY",
        "preDeadlineDays": 14,
        "weekendRule": "move_earlier",
        "defaultExtractor": "staged",
        "stampCorner": "top_right",
        "stagedDataLocation": "local"
    }
}
 

Example response (422, Cloud als Standard):


{
    "message": "Cloud-Wege laufen nur auf Klick, nie als Standard.",
    "errors": {
        "default_extractor": [
            "Cloud-Wege laufen nur auf Klick, nie als Standard."
        ]
    }
}
 

Request      

PATCH api/v1/settings

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

firm_name   string  optional    

Kanzleiname im Stempel; staged erkennt daran den Mandanten. Must be at least 2 characters. Must not be greater than 120 characters. Example: Muster & Partner Rechtsanwälte

stamp_initials   string  optional    

Kürzel im Stempel. Must be at least 1 character. Must not be greater than 12 characters. Example: ao

state   string  optional    

Bundesland für die Landesfeiertage. Example: BY

Must be one of:
  • BW
  • BY
  • BE
  • BB
  • HB
  • HH
  • HE
  • MV
  • NI
  • NW
  • RP
  • SL
  • SN
  • ST
  • SH
  • TH
pre_deadline_days   integer  optional    

Vorfrist in Tagen vor dem notierten Fristende. Must be at least 1. Must not be greater than 30. Example: 7

weekend_rule   string  optional    

move_earlier zieht ein Ende auf Wochenende/Feiertag auf den Werktag davor, move_later_legal notiert das gesetzliche Ende. Example: move_earlier

Must be one of:
  • move_earlier
  • move_later_legal
default_extractor   string  optional    

Standard-Auslese-Weg für neue Eingänge; nie claude oder mistral. staged liest dort, wohin die Anbieter-Konfiguration seiner Stufen zeigt. Example: staged

Must be one of:
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
stamp_corner   string  optional    

Ecke des digitalen Stempels auf Seite 1. Example: top_right

Must be one of:
  • top_right
  • top_left
  • bottom_right
  • bottom_left

Response

Response Fields

data   object     

Die Einstellungen.

state   string     

Bundesland für die Landesfeiertage.

Must be one of:
  • BW
  • BY
  • BE
  • BB
  • HB
  • HH
  • HE
  • MV
  • NI
  • NW
  • RP
  • SL
  • SN
  • ST
  • SH
  • TH
weekendRule   string     

Wochenend-Regel für das notierte Fristende.

Must be one of:
  • move_earlier
  • move_later_legal
defaultExtractor   string     

Standard-Auslese-Weg; nie ein Cloud-Weg, staged folgt der Anbieter-Konfiguration.

Must be one of:
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
stampCorner   string     

Ecke des digitalen Stempels auf Seite 1.

Must be one of:
  • top_right
  • top_left
  • bottom_right
  • bottom_left
stagedDataLocation   string     

Wohin staged Daten schickt, aus der Anbieter-Konfiguration je Stufe (nur lesbar).

Must be one of:
  • local
  • eu
  • us
firmName   string     

Kanzleiname im Stempel.

stampInitials   string     

Kürzel im Stempel.

preDeadlineDays   integer     

Vorfrist in Tagen.

Get system status

requires authentication

Prüft live, ob die Werkzeuge der Auslese-Wege bereitstehen: OCR (ocrmypdf, Tesseract deu, Poppler), Ollama samt Modellen, der GLiNER-Sidecar und ob die Cloud-Keys gesetzt sind. Dazu je Stufe von staged der konfigurierte Anbieter (lokal oder Mistral) und der Datenort, der daraus folgt. Keys erscheinen nur als ja/nein, nie im Klartext. Braucht ein paar Sekunden.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/system/status" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/system/status"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "ocr": {
            "ocrmypdf": true,
            "ocrmypdfVersion": "17.13.0",
            "tesseractDeu": true,
            "poppler": true
        },
        "ollama": {
            "reachable": true,
            "textModel": "qwen3.6:27b",
            "textModelInstalled": true,
            "visionModel": "qwen3-vl:32b-instruct",
            "visionModelInstalled": true,
            "stagedTextModel": "qwen3.6:35b",
            "stagedTextModelInstalled": true,
            "stagedVisionModel": "qwen3.6:35b",
            "stagedVisionModelInstalled": true
        },
        "ner": {
            "enabled": true,
            "reachable": false,
            "model": null
        },
        "keys": {
            "anthropic": true,
            "mistral": false
        },
        "staged": {
            "dataLocation": "local",
            "configError": null,
            "stages": [
                {
                    "stage": "ocr",
                    "provider": "ocrmypdf",
                    "model": "tesseract deu",
                    "dataLocation": "local",
                    "ready": true
                },
                {
                    "stage": "llm",
                    "provider": "ollama",
                    "model": "qwen3.6:35b",
                    "dataLocation": "local",
                    "ready": true
                },
                {
                    "stage": "vision",
                    "provider": "ollama",
                    "model": "qwen3.6:35b",
                    "dataLocation": "local",
                    "ready": true
                },
                {
                    "stage": "ner",
                    "provider": "gliner",
                    "model": null,
                    "dataLocation": "local",
                    "ready": false
                }
            ]
        },
        "extractors": [
            {
                "name": "claude",
                "dataLocation": "us",
                "ready": true,
                "note": null
            },
            {
                "name": "mistral",
                "dataLocation": "eu",
                "ready": false,
                "note": "Nicht konfiguriert: MISTRAL_API_KEY fehlt."
            },
            {
                "name": "ollama_text",
                "dataLocation": "local",
                "ready": true,
                "note": null
            },
            {
                "name": "ollama_vision",
                "dataLocation": "local",
                "ready": true,
                "note": null
            },
            {
                "name": "staged",
                "dataLocation": "local",
                "ready": true,
                "note": "GLiNER-Sidecar aus: Regeln nur mit Regex."
            },
            {
                "name": "rules",
                "dataLocation": "local",
                "ready": true,
                "note": "GLiNER-Sidecar aus: nur Regex-Felder."
            },
            {
                "name": "fake",
                "dataLocation": "local",
                "ready": true,
                "note": null
            }
        ]
    }
}
 

Request      

GET api/v1/system/status

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Response

Response Fields

data   object     

Der Status.

ocr   object     

OCR-Werkzeuge.

ocrmypdfVersion   string     

Version von ocrmypdf, sonst null.

ocrmypdf   boolean     

ocrmypdf ist installiert.

tesseractDeu   boolean     

Tesseract hat die Sprachdaten deu.

poppler   boolean     

pdftotext und pdftoppm sind da.

ner   object     

GLiNER-Sidecar.

model   string     

Geladenes Modell, sonst null.

enabled   boolean     

Der Sidecar ist eingeschaltet (NER_ENABLED); sonst laufen die Regeln ohne ihn.

reachable   boolean     

Der GLiNER-Sidecar antwortet.

staged   object     

Anbieter der Stufen von staged.

dataLocation   string     

Wohin staged Daten schickt: local nur, wenn alle Stufen lokal laufen.

Must be one of:
  • local
  • eu
  • us
configError   string     

Unbekannter Anbieter in der Env; staged läuft dann nicht. Sonst null.

stages   object[]     

Je Stufe in Reihenfolge: OCR, Textmodell, Vision, NER.

stage   string     

Stufe.

Must be one of:
  • ocr
  • llm
  • vision
  • ner
provider   string     

Anbieter; none, wenn die Stufe abgeschaltet ist.

Must be one of:
  • ocrmypdf
  • ollama
  • mistral
  • gliner
  • none
model   string     

Modell der Stufe, sonst null.

dataLocation   string     

Wohin diese Stufe Daten schickt.

Must be one of:
  • local
  • eu
  • us
ready   boolean     

Die Stufe kann laufen (Key gesetzt, Werkzeug oder Modell da).

extractors   object[]     

Bereitschaft je Auslese-Weg.

name   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
dataLocation   string     

Wohin die Daten gehen.

Must be one of:
  • local
  • eu
  • us
note   string     

Was fehlt oder eingeschränkt ist, sonst null.

ready   boolean     

Alle Voraussetzungen sind erfüllt.

ollama   object     

Lokales LLM.

reachable   boolean     

Ollama antwortet.

textModel   string     

Eingestelltes Textmodell.

textModelInstalled   boolean     

Das Textmodell ist in Ollama vorhanden.

visionModel   string     

Eingestelltes Vision-Modell.

visionModelInstalled   boolean     

Das Vision-Modell ist in Ollama vorhanden.

stagedTextModel   string     

Modell der Stufe 3 von staged (Text ergänzen).

stagedTextModelInstalled   boolean     

Das Modell der Stufe 3 ist in Ollama vorhanden.

stagedVisionModel   string     

Modell der Stufe 4 von staged (Stempel und Handschrift auf Ausschnitten).

stagedVisionModelInstalled   boolean     

Das Modell der Stufe 4 ist in Ollama vorhanden.

keys   object     

Cloud-Keys, nur ob gesetzt.

anthropic   boolean     

ANTHROPIC_API_KEY ist gesetzt.

mistral   boolean     

MISTRAL_API_KEY ist gesetzt.

Fristenbuch

Alle Fristen und Vorfristen über alle Eingänge, mit Erledigt-Haken und CSV-Export für Excel und Numbers.

List deadlines

requires authentication

Das Fristenbuch: jede Frist mit Eingang, Absender, Dokumentart und Aktenzeichen, nach notiertem Ende sortiert; Fristen ohne Datum stehen am Ende.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/deadlines?status=open&from=2026-10-01&to=2026-12-31&document_type=beschluss" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/deadlines"
);

const params = {
    "status": "open",
    "from": "2026-10-01",
    "to": "2026-12-31",
    "document_type": "beschluss",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "id": "01K6EXAMPLE00000000000000D1",
            "documentId": "01K6EXAMPLE0000000000000001",
            "receivedAt": "2026-10-01T09:14:05+02:00",
            "senderName": "Landgericht Augsburg",
            "documentType": "beschluss",
            "fileNumber": "3 O 877/26",
            "documentStatus": "ready",
            "kind": "Sofortige Beschwerde",
            "norm": "§ 569 ZPO",
            "isNotfrist": true,
            "legalEnd": "2026-10-15",
            "notedEnd": "2026-10-15",
            "preDeadline": "2026-10-08",
            "daysLeft": 14,
            "doneAt": null
        }
    ]
}
 

Example response (422, Ungültiger Filter):


{
    "message": "Bis liegt vor Von.",
    "errors": {
        "to": [
            "Bis liegt vor Von."
        ]
    }
}
 

Request      

GET api/v1/deadlines

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

status   string  optional    

open nur offene, done nur erledigte Fristen; ohne Angabe alle. Example: open

Must be one of:
  • open
  • done
from   string  optional    

Notiertes Ende ab diesem Tag (YYYY-MM-DD). Fristen ohne Datum fallen dann heraus. Must be a valid date in the format Y-m-d. Example: 2026-10-01

to   string  optional    

Notiertes Ende bis zu diesem Tag (YYYY-MM-DD). Must be a valid date in the format Y-m-d. Must be a date after or equal to from. Example: 2026-12-31

document_type   string  optional    

Nur diese Dokumentart laut Extraktions-Schema. Must not be greater than 64 characters. Example: beschluss

Response

Response Fields

data   object[]     

Die Fristen.

receivedAt   string     

Eingang, ISO 8601.

senderName   string     

Absender.

documentType   string     

Dokumentart laut Extraktions-Schema.

fileNumber   string     

Gerichtliches Aktenzeichen, sonst das eigene.

documentStatus   string     

Status des Eingangs.

Must be one of:
  • queued
  • ocr
  • extracting
  • ready
  • failed
  • confirmed
kind   string     

Art der Frist.

norm   string     

Norm.

legalEnd   string     

Gesetzliches Ende, YYYY-MM-DD.

notedEnd   string     

Notiertes Ende (FA), YYYY-MM-DD.

preDeadline   string     

Vorfrist (VF), YYYY-MM-DD.

daysLeft   integer     

Tage bis zum notierten Ende, negativ wenn überschritten.

doneAt   string     

Erledigt am, ISO 8601.

id   string     

ULID der Frist.

documentId   string     

ULID des Eingangs.

isNotfrist   boolean     

Notfrist.

Export deadlines

requires authentication

Das Fristenbuch als CSV mit denselben Filtern wie die Liste: UTF-8 mit BOM, Semikolon als Trenner, Daten als TT.MM.JJJJ — öffnet sich in Excel und Numbers mit Umlauten.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/deadlines/export?status=open&from=2026-10-01&to=2026-12-31&document_type=beschluss" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/deadlines/export"
);

const params = {
    "status": "open",
    "from": "2026-10-01",
    "to": "2026-12-31",
    "document_type": "beschluss",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

Binary data -  Die CSV-Datei.
 

Example response (422, Ungültiger Filter):


{
    "message": "Bis liegt vor Von.",
    "errors": {
        "to": [
            "Bis liegt vor Von."
        ]
    }
}
 

Request      

GET api/v1/deadlines/export

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

status   string  optional    

open nur offene, done nur erledigte Fristen; ohne Angabe alle. Example: open

Must be one of:
  • open
  • done
from   string  optional    

Notiertes Ende ab diesem Tag (YYYY-MM-DD). Fristen ohne Datum fallen dann heraus. Must be a valid date in the format Y-m-d. Example: 2026-10-01

to   string  optional    

Notiertes Ende bis zu diesem Tag (YYYY-MM-DD). Must be a valid date in the format Y-m-d. Must be a date after or equal to from. Example: 2026-12-31

document_type   string  optional    

Nur diese Dokumentart laut Extraktions-Schema. Must not be greater than 64 characters. Example: beschluss

Update deadline

requires authentication

Setzt oder entfernt den Erledigt-Haken. Er bleibt beim Neuberechnen erhalten, solange Art und Norm der Frist gleich bleiben.

Example request:
curl --request PATCH \
    "http://localhost:8310/api/v1/deadlines/01K6EXAMPLE00000000000000D1" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"done\": true
}"
const url = new URL(
    "http://localhost:8310/api/v1/deadlines/01K6EXAMPLE00000000000000D1"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "done": true
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": {
        "id": "01K6EXAMPLE00000000000000D1",
        "documentId": "01K6EXAMPLE0000000000000001",
        "receivedAt": "2026-10-01T09:14:05+02:00",
        "senderName": "Landgericht Augsburg",
        "documentType": "beschluss",
        "fileNumber": "3 O 877/26",
        "documentStatus": "ready",
        "kind": "Sofortige Beschwerde",
        "norm": "§ 569 ZPO",
        "isNotfrist": true,
        "legalEnd": "2026-10-15",
        "notedEnd": "2026-10-15",
        "preDeadline": "2026-10-08",
        "daysLeft": 14,
        "doneAt": "2026-10-02T11:00:00+02:00"
    }
}
 

Example response (404, Unbekannte Id):


{
    "message": "Diese Frist gibt es nicht."
}
 

Request      

PATCH api/v1/deadlines/{id}

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID der Frist. Example: 01K6EXAMPLE00000000000000D1

Body Parameters

done   boolean     

Erledigt setzen (true) oder wieder öffnen (false). Example: true

Response

Response Fields

data   object     

Die Frist wie in der Liste.

receivedAt   string     

Eingang, ISO 8601.

senderName   string     

Absender.

documentType   string     

Dokumentart laut Extraktions-Schema.

fileNumber   string     

Gerichtliches Aktenzeichen, sonst das eigene.

documentStatus   string     

Status des Eingangs.

Must be one of:
  • queued
  • ocr
  • extracting
  • ready
  • failed
  • confirmed
kind   string     

Art der Frist.

norm   string     

Norm.

legalEnd   string     

Gesetzliches Ende, YYYY-MM-DD.

notedEnd   string     

Notiertes Ende (FA), YYYY-MM-DD.

preDeadline   string     

Vorfrist (VF), YYYY-MM-DD.

daysLeft   integer     

Tage bis zum notierten Ende, negativ wenn überschritten.

doneAt   string     

Erledigt am, ISO 8601.

id   string     

ULID der Frist.

documentId   string     

ULID des Eingangs.

isNotfrist   boolean     

Notfrist.

Vergleich

Ergebnisse von php artisan samples:benchmark: Trefferquote je Auslese-Weg und Feldgruppe, Median-Dauer und Kosten je 100 Seiten. Private Samples erscheinen nur pseudonymisiert.

List benchmarks

requires authentication

Alle Benchmark-Läufe, neueste zuerst.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/benchmarks" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/benchmarks"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "id": "01K6EXAMPLE00000000000000B1",
            "extractors": [
                "rules",
                "ollama_text"
            ],
            "includePrivate": false,
            "sampleCount": 2,
            "resultCount": 4,
            "createdAt": "2026-10-01T10:00:00+02:00",
            "finishedAt": "2026-10-01T10:04:12+02:00"
        }
    ]
}
 

Request      

GET api/v1/benchmarks

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

Response

Response Fields

data   object[]     

Die Benchmarks.

finishedAt   string     

Fertig, ISO 8601; null, solange er läuft oder abbrach.

id   string     

ULID des Benchmarks.

extractors   string[]     

Gewählte Auslese-Wege; staged:local/staged:mistral für eine feste Anbieter-Variante.

includePrivate   boolean     

Private Samples waren eingeschlossen (nur lokale Wege).

sampleCount   integer     

Anzahl der Samples.

resultCount   integer     

Anzahl der Läufe (Sample × Weg).

createdAt   string     

Gestartet, ISO 8601.

Get benchmark

requires authentication

Ein Benchmark verdichtet: je Auslese-Weg Trefferquote gesamt und je Feldgruppe, Median-Dauer, Kosten je 100 Seiten und Datenort; dazu die Matrix Sample × Weg. latest liefert den neuesten. Bewertet werden nur Felder, bei denen Soll oder Ist etwas enthält.

Example request:
curl --request GET \
    --get "http://localhost:8310/api/v1/benchmarks/latest" \
    --header "Cookie: eingang-session={SESSION_COOKIE}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8310/api/v1/benchmarks/latest"
);

const headers = {
    "Cookie": "eingang-session={SESSION_COOKIE}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "id": "01K6EXAMPLE00000000000000B1",
        "extractors": [
            "rules",
            "ollama_text"
        ],
        "includePrivate": false,
        "sampleCount": 2,
        "resultCount": 4,
        "createdAt": "2026-10-01T10:00:00+02:00",
        "finishedAt": "2026-10-01T10:04:12+02:00",
        "byExtractor": [
            {
                "extractor": "ollama_text",
                "variant": null,
                "dataLocation": "local",
                "runs": 2,
                "succeeded": 2,
                "matched": 41,
                "compared": 52,
                "rate": 0.7885,
                "groups": [
                    {
                        "group": "document_type",
                        "matched": 2,
                        "compared": 2,
                        "rate": 1
                    },
                    {
                        "group": "sender",
                        "matched": 11,
                        "compared": 14,
                        "rate": 0.7857
                    },
                    {
                        "group": "file_numbers",
                        "matched": 6,
                        "compared": 6,
                        "rate": 1
                    },
                    {
                        "group": "parties",
                        "matched": 6,
                        "compared": 8,
                        "rate": 0.75
                    },
                    {
                        "group": "dates",
                        "matched": 4,
                        "compared": 4,
                        "rate": 1
                    },
                    {
                        "group": "deadlines",
                        "matched": 3,
                        "compared": 4,
                        "rate": 0.75
                    },
                    {
                        "group": "amounts",
                        "matched": 3,
                        "compared": 4,
                        "rate": 0.75
                    },
                    {
                        "group": "actions",
                        "matched": 2,
                        "compared": 4,
                        "rate": 0.5
                    },
                    {
                        "group": "stamp",
                        "matched": 4,
                        "compared": 6,
                        "rate": 0.6667
                    }
                ],
                "medianDurationMs": 48210,
                "pages": 3,
                "costUsd": 0,
                "costPer100PagesUsd": 0
            },
            {
                "extractor": "rules",
                "variant": null,
                "dataLocation": "local",
                "runs": 2,
                "succeeded": 2,
                "matched": 24,
                "compared": 50,
                "rate": 0.48,
                "groups": [
                    {
                        "group": "document_type",
                        "matched": 2,
                        "compared": 2,
                        "rate": 1
                    },
                    {
                        "group": "sender",
                        "matched": 5,
                        "compared": 14,
                        "rate": 0.3571
                    },
                    {
                        "group": "file_numbers",
                        "matched": 5,
                        "compared": 6,
                        "rate": 0.8333
                    },
                    {
                        "group": "parties",
                        "matched": 1,
                        "compared": 8,
                        "rate": 0.125
                    },
                    {
                        "group": "dates",
                        "matched": 3,
                        "compared": 4,
                        "rate": 0.75
                    },
                    {
                        "group": "deadlines",
                        "matched": 2,
                        "compared": 4,
                        "rate": 0.5
                    },
                    {
                        "group": "amounts",
                        "matched": 2,
                        "compared": 4,
                        "rate": 0.5
                    },
                    {
                        "group": "actions",
                        "matched": 0,
                        "compared": 2,
                        "rate": 0
                    },
                    {
                        "group": "stamp",
                        "matched": 4,
                        "compared": 6,
                        "rate": 0.6667
                    }
                ],
                "medianDurationMs": 1840,
                "pages": 3,
                "costUsd": 0,
                "costPer100PagesUsd": 0
            }
        ],
        "bySample": [
            {
                "sample": "01-ladung-lg",
                "isPrivate": false,
                "results": [
                    {
                        "extractor": "ollama_text",
                        "variant": null,
                        "status": "succeeded",
                        "matched": 20,
                        "compared": 25,
                        "rate": 0.8,
                        "durationMs": 45120,
                        "error": null
                    },
                    {
                        "extractor": "rules",
                        "variant": null,
                        "status": "succeeded",
                        "matched": 12,
                        "compared": 24,
                        "rate": 0.5,
                        "durationMs": 1790,
                        "error": null
                    }
                ]
            },
            {
                "sample": "02-urteil-ag",
                "isPrivate": false,
                "results": [
                    {
                        "extractor": "ollama_text",
                        "variant": null,
                        "status": "succeeded",
                        "matched": 21,
                        "compared": 27,
                        "rate": 0.7778,
                        "durationMs": 51300,
                        "error": null
                    },
                    {
                        "extractor": "rules",
                        "variant": null,
                        "status": "succeeded",
                        "matched": 12,
                        "compared": 26,
                        "rate": 0.4615,
                        "durationMs": 1890,
                        "error": null
                    }
                ]
            }
        ]
    }
}
 

Example response (404, Unbekannte Id oder noch kein Benchmark):


{
    "message": "Diesen Benchmark gibt es nicht."
}
 

Request      

GET api/v1/benchmarks/{id}

Headers

Cookie        

Example: eingang-session={SESSION_COOKIE}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

ULID des Benchmarks oder latest. Example: latest

Response

Response Fields

data   object     

Der Benchmark.

finishedAt   string     

Fertig, ISO 8601.

byExtractor   object[]     

Verdichtung je Auslese-Weg.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
variant   string     

Anbieter-Variante von staged (local, mistral oder Anbieter je Stufe wie mistral/ollama/ollama); sonst null.

dataLocation   string     

Wohin die Daten gingen.

Must be one of:
  • local
  • eu
  • us
rate   number     

Trefferquote 0–1; null, wenn nichts bewertet wurde.

groups   object[]     

Je Feldgruppe.

group   string     

Feldgruppe.

Must be one of:
  • document_type
  • sender
  • file_numbers
  • parties
  • dates
  • deadlines
  • amounts
  • actions
  • stamp
rate   number     

Trefferquote 0–1.

matched   integer     

Getroffen.

compared   integer     

Bewertet.

medianDurationMs   integer     

Median-Dauer der gelungenen Läufe.

costUsd   number     

Geschätzte Kosten gesamt in USD.

costPer100PagesUsd   number     

Geschätzte Kosten je 100 Seiten in USD.

runs   integer     

Läufe.

succeeded   integer     

Davon gelungen.

matched   integer     

Getroffene Felder.

compared   integer     

Bewertete Felder.

pages   integer     

Seiten der gelungenen Läufe.

bySample   object[]     

Matrix Sample × Weg.

results   object[]     

Je Weg.

extractor   string     

Auslese-Weg.

Must be one of:
  • claude
  • mistral
  • ollama_text
  • ollama_vision
  • staged
  • rules
  • fake
variant   string     

Anbieter-Variante von staged, sonst null.

status   string     

Status des Laufs.

Must be one of:
  • running
  • succeeded
  • failed
rate   number     

Trefferquote 0–1.

durationMs   integer     

Dauer.

error   string     

Grund, wenn der Lauf fehlschlug.

matched   integer     

Getroffen.

compared   integer     

Bewertet.

sample   string     

Sample-Name; private als „privat-N“.

isPrivate   boolean     

Echte Post.

id   string     

ULID des Benchmarks.

extractors   string[]     

Gewählte Auslese-Wege; staged:local/staged:mistral für eine feste Anbieter-Variante.

includePrivate   boolean     

Private Samples waren eingeschlossen.

sampleCount   integer     

Anzahl der Samples.

resultCount   integer     

Anzahl der Läufe.

createdAt   string     

Gestartet, ISO 8601.