“Why not just send the PDF to a language model?” is a fair question — for many extraction jobs, that works well. Invoices are different: the values feed accounting systems and payments, the documents carry client financial data, and a confidently wrong number costs real money.
Figures verified July 2026 · sources linked below
Same invoice in, same fields out — OCR + rules, never sampled text. When a field is unreadable it returns null with a warning instead of inventing a value.
Processed in memory on EU infrastructure and gone the instant we respond — no 30–55-day provider logs, no new sub-processor on your GDPR paperwork.
Typed JSON with calibrated per-field confidence, and net + VAT = total cross-checked on every extraction — no prompt engineering, no parsing layer to maintain.
Flat per-page pricing whatever the layout — token spend varies with image detail, density and retries, and repricing can shift your unit economics mid-year.
| Zerodoc | A hosted LLM | |
|---|---|---|
| Extraction quality | ||
| Structured JSON output | Typed fields, tables and totals — guaranteed shape | ~JSON modes exist; shape and validity still need a checking layer |
| Per-field confidence scores | Calibrated OCR confidence — automate above a threshold, review below | Verbalized confidence clusters at 80–100% regardless of correctness² |
| Refuses to guess on unreadable fields | Returns null + extraction_warnings | Documented failure mode: fabricates plausible text under blur/occlusion¹ |
| Amount validation (net + VAT = total) | Cross-checked on every extraction | Only if you build and maintain it yourself |
| Arbitrary document types & handwriting | UK/EU invoices today — depth over breadth, on purpose | Genuinely better at unpredictable, free-form content |
| Reliability | ||
| Same document in, same result out | Deterministic pipeline — re-runs yield identical fields | Not guaranteed even at temperature 0; serving-stack changes shift outputs⁵ |
| Stable over time | No model deprecations to re-test your prompts against | Models retire on the provider’s schedule, not yours |
| Privacy & compliance | ||
| Zero retention by default | No storage code path exists; every response carries retention: { stored: false } | API logs typically kept 30–55 days; zero-retention is approval-gated, not self-serve⁵ |
| EU processing on every plan | One stateless EU server you can point to on a map | ~Gated, partial, or routed through a US hyperscaler |
| No new sub-processor in your DPIA | One EU processor, a DPA, nothing retained to disclose | The model provider joins your sub-processor list |
| Immune to prompt injection | Documents are data, not instructions — nothing in a PDF can steer the extractor | Document text enters the prompt — OWASP’s #1 LLM risk, with real zero-click CVEs³ |
| Cost | ||
| Cheapest possible raw call | £0.01–0.02 per page, flat | Flash-tier calls can genuinely cost less per page — we won’t pretend otherwise |
| Predictable spend | One number for the spreadsheet, whatever the layout | Varies with image detail, density, retries — and repricing |
¹ ² ³ ⁵ — sourced below. Retention, residency and training policies vary by provider and change; verify against current provider documentation for your DPIA.
One request replaces the pipeline you'd otherwise build and maintain around a model.
curl -X POST https://api.zerodoc.io/v1/extract \
-H "X-API-Key: zk_your_api_key" \
-F "file=@invoice.pdf"
# → typed fields, confidence, validation — done
{
"fields": {
"supplier": { "value": "ACME Trading Ltd", "confidence": 0.98 },
"total": { "value": 1275.00, "confidence": 0.97 }
},
"extraction_warnings": [],
"retention": { "stored": false }
}# 1. Render each PDF page to an image, base64-encode
# 2. Write (and forever maintain) the extraction prompt
# 3. Send your client's invoice to the model provider
# 4. Hope the response is valid JSON; parse defensively
# 5. Build your own amount validation & review routing
# 6. Re-test everything when the model version retires
# 7. Add the provider to your sub-processor list & DPIAWhen OCR can't read a smudged total, Zerodoc returns null and a warning — one failure is visible and cheap. When a generative model can't read it, it tends to produce a well-formed value anyway, because generating plausible text is what it's built to do.
A real-world scan: the one field that matters is the one the toner missed.
"total_amount": null,
"extraction_warnings": [
"total_amount unreadable; net + VAT = 1275.00"
]Your pipeline routes it to a human. Cost: one review.
"total_amount": 1725.00Well-formed, plausible, wrong — and nothing flags it. Found at reconciliation, or after payment.
This is not hypothetical: research on multimodal models shows they fabricate rather than abstain on degraded text¹, and misdirected authorised payments cost UK customers £576 million in 2025, with only around six in ten pounds reimbursed⁴. For financial documents, refusing to guess is a feature.
The pipelines differ before a single field is extracted. One path never leaves a machine you can point to on a map; the other adds a company to your GDPR paperwork.
Where an LLM is genuinely the better tool: arbitrary document types you can’t predict, messy free-form layouts, handwriting, and one-off extractions where you’d rather write a prompt than an integration. And at flash-tier pricing, the raw model call can cost less per page than we charge — if your documents aren’t sensitive and your fields don’t feed payments, that’s a fine trade.
Zerodoc makes the opposite trade on purpose: one document family (UK/EU invoices, more on the roadmap), done deterministically and privately, with validation built in and a flat price — and no third-party model in the path, ever.
200 pages every month, no card, no trial expiry.
Run them through Live Extraction and compare the fields to your current pipeline — nothing you upload is ever stored.
One curl to /v1/extract — no SDK, no prompt, no parsing layer. Most teams switch in an afternoon.
200 pages free every month. Compare the output to your current pipeline — nothing you upload is ever stored.
Start for free