- Accepts multipart/form-data PDF, streams LLM extraction via SSE - Uses libllmorbiter (OpenRouterProvider) with API key from companysetting keys.openrouter - Extracts manifest basedata, notes, and line items from invoices/delivery notes - Events: status, llm_call, tool_call, usage, progress, result, error - Extends generateApiDocs.js: multipart field table + x-sse-events table support - Docs: docs/api/routes/delivery/parsePDF.md (auto-generated)
2.8 KiB
POST /delivery/parsePDF
Protected. Requires a valid session cookie (credentials: 'include').
Parse PDF (SSE)
Accepts a PDF invoice or delivery note (multipart/form-data, field pdf)
and streams extraction results as Server-Sent Events until parsing is complete.
The PDF is read via pdftotext -layout and fed page-by-page to an LLM
(OpenRouter) which fills a structured manifest of header data and line items.
The OpenRouter API key is read from the authenticated user's company setting
keys.openrouter; the endpoint returns 400 if the key is not configured.
The stream ends after the final result event (or an error event on failure).
Body (multipart/form-data)
| Field | Required | Type | Description |
|---|---|---|---|
pdf |
yes | file | PDF file to parse (max 50 MB, application/pdf) |
SSE Events
The response is a text/event-stream. Events are emitted in order until the stream closes.
| Event | Description | Payload |
|---|---|---|
status |
PDF parse confirmation and LLM status messages | { "message": "…" } |
llm_call |
Fired before each LLM request | { "model": "…", "promptSize": 0, "messages": 0 } |
tool_call |
Fired when the output_manifest tool is invoked | { "name": "output_manifest" } |
usage |
Token usage after each LLM response | { "input": 0, "cached": 0, "output": 0, "cost": 0 } |
progress |
Intermediate accumulated extraction state (basedata / notes / items) | ManifestResult |
result |
Final accumulated extraction — emitted just before the stream closes | ManifestResult |
error |
Emitted on PDF parse or LLM failure; stream closes immediately after | { "message": "…" } |
Response 200
text/event-stream — emits status, llm_call, tool_call, usage,
progress, result (and error on failure). See SSE Events table below.
ManifestResult shape (used by progress and result):
{
"basedata": {
"date": "2026-01-15",
"kLieferant": 42,
"lieferantName": "Muster GmbH",
"manifestNr": "LS-2026-001",
"manifestType": "lieferschein"
},
"notes": ["Pos. 3: VPE-Angabe fehlte, Standardwert 1 angenommen."],
"items": {
"pagesFrom": 1,
"pagesTo": 2,
"items": [
{
"position": 1,
"count": 10,
"vpe": 1,
"unit": "Stk.",
"articleName": "Einhängesieb Stahl",
"liefArtNr": "ES-100",
"mwst": "19",
"eknetto": 450,
"page": 1
}
]
}
}
Errors
| Status | Description |
|---|---|
| 400 | No PDF uploaded or OpenRouter key not configured — {"error":"…"} |
| 401 | Unauthorized — {"error":"…"} |
Generated from @openapi JSDoc. Do not edit by hand — run npm run docs:api.