A web app that automatically checks every dental invoice against official tariffs
Notacheckers reads Dutch dental invoices from a PDF or photo, converts the billing lines into structured data and checks each one against 772 official 2026 NZa tariffs. Possible overcharges are highlighted immediately. I built the complete privacy-first, serverless application in approximately four and a half weeks.

The challenge.
Official dental tariffs are public, but they are spread across separate documents and an invoice contains codes such as C11, M03 or V30 with little explanation. The goal was a free tool where a consumer could upload a PDF or photo and quickly understand whether the amounts appeared correct.
The system had to turn an unstructured document into reliable billing lines, reconcile imperfectly extracted codes with an official catalogue, and apply rule-specific checks including variable tariffs and required code combinations. It also had to remain anonymous and inexpensive under unpredictable public traffic.
The approach.
The core flow keeps a person in the loop: upload, extraction, confirmation and result. AI proposes structured invoice data, but the user confirms or corrects it before validation. Only then does the deterministic rule engine compare every line with the tariff catalogue.
Privacy is built into the data model. Checks are anonymous, expire after 30 days and are deleted by a scheduled cleanup. An append-only event log preserves state transitions and the audit trail. The application was developed test-first, with 249 cases covering extraction, rules, payment, retention and security.
Architecture and decisions.
- ·
SvelteKit on Cloudflare Workers. A public tool with unpredictable traffic runs at the edge without a server fleet or idle infrastructure cost.
- ·
Neon Postgres and Drizzle. A relational state machine tracks uploaded, review-required, validated and failed states with strong integrity; Hyperdrive manages edge database connections.
- ·
Vision AI with a strict JSON schema. Invoice layouts vary widely. Amounts as integer cents, uppercase codes and explicit nullable fields produce cleaner input for deterministic validation.
- ·
Worker-native Stripe and PDF code. Webhook verification uses Web Crypto and the report PDF is generated directly, avoiding Node-only libraries that do not fit the runtime.
The hardest problems, solved.
- 1
Separating codes from quantities. Extraction sometimes returned M03X6 when the six was a quantity. Longest-match canonicalisation against the 772-code catalogue restores the code and quantity independently.
- 2
Refusing false precision. Forty-nine orthodontic codes have several valid tariffs depending on context. The tool marks these as requiring context instead of guessing and producing a false warning.
- 3
Privacy by design. No account, name, address or IP is attached to a check. Records expire after 30 days, while rate limiting controls abuse without storing the IP in the invoice record.
The result.
Notacheckers runs in production with 772 official codes across three care categories, supported by 249 automated tests and 651 assertions. Users see the status and possible difference for each line and can optionally unlock a detailed PDF report.
The architecture transfers directly to other document-heavy work: purchase invoices against contract prices, claims against policy rules, declarations or compliance checks. AI extracts the document; a deterministic engine applies the organisation's own rules.
Under the hood.
Frequently asked questions.
Is your question not listed? Email me directly.
Can this approach work for our invoices or documents? +
Yes. The pattern is generic: AI extracts structured fields and a rule engine compares them with your data or policy. The document schema and rules change; the architecture remains the same.
How long did this take to build? +
Approximately four and a half weeks by one developer, including upload, AI extraction, user review, validation, results, payment, report email and privacy logic, with 249 automated tests.
What would a system like this cost? +
A focused first release usually starts in the low four figures. Document types, rule complexity, payments, reporting and integrations determine the final fixed scope.
Is AI extraction reliable enough? +
The application does not trust the model blindly. A strict schema constrains its output, the user confirms the extracted data and unknown codes are explicitly marked rather than forced into a match.
How is privacy handled? +
There is no account, name, address or IP in a check. Anonymous records expire after 30 days, and email is stored only when a user requests delivery of the PDF report.