Why I built Temlavo
Temlavo extracts invoice data and tells your code which invoices not to trust. Here is why I built it that way, and what it deliberately does not do.
On this page
Temlavo is an invoice extraction API. You send one supplier invoice, a PDF or a photo, and get back structured JSON: supplier and customer, invoice number and dates, totals, taxes and line items. With the data comes a list of checks and one plain answer: completed, needs_review or failed.
This post is about why I built it, and why it works the way it does.
Where it started
I started the obvious way: send an invoice to a strong OCR service and a language model, ask for JSON, and read what comes back. Across a few hundred public invoices, most fields came back right. The failures were the problem. Some invoices print the word “None” where an invoice number would go, and that came back as the invoice number. On invoices that print no total, the amount due was copied into the total. Running the same invoice twice could give different payment terms. Every one of those answers was valid JSON, and nothing in it said which ones were wrong.
That’s the gap Temlavo fills: the model reads the invoice, and code checks what it read.
Checks instead of confidence scores
Many extraction APIs return a confidence number for each field. I decided not to. A score of 0.83 doesn’t tell your code what to do next, and I didn’t want your workflow to depend on how sure a model says it is.
Temlavo runs declared checks on the extracted data instead:
- Do the quantity and price on each line give its total?
- Do the rows add up to the subtotal, and the tax lines to the total tax?
- Does the amount due follow from the total and what was already paid?
- Do the dates and currencies agree?
- Have you sent this invoice before?
Each check and its exact rule is on the Checks page.
Then you get one outcome. completed means no blocking check failed. needs_review means the data is there, with the reasons someone should look. failed means there is no usable result, and it isn’t billed.
Here’s a result for a synthetic sample invoice whose printed total doesn’t match its subtotal plus tax, trimmed to the check that failed:
{
"status": "needs_review",
"validation": {
"review_required": true,
"checks": [
{
"code": "total_consistency",
"status": "fail",
"severity": "review",
"message": "The invoice total does not equal the subtotal less discount, plus shipping, other charges and any tax the subtotal does not already include.",
"paths": ["/data/totals/total"],
"details": {
"equation": "subtotal - discount + shipping + other_charges + tax = total",
"actual_total": { "amount": "1006.80", "currency": "USD" },
"calculated_total": { "amount": "1036.8", "currency": "USD" },
"difference": { "amount": "-30", "currency": "USD" }
}
}
]
},
"data": {
"totals": {
"subtotal": { "amount": "960.00", "currency": "USD" },
"tax": { "amount": "76.80", "currency": "USD" },
"total": { "amount": "1006.80", "currency": "USD" }
}
}
}You decide per request how strict to be: whether missing line items need review, and which extra fields you require, such as a PO number. See Review policy.
What the checks can’t do
Checks compare the extracted values with each other. They don’t read the invoice again. If a number is wrong in the same way everywhere on the page, every check can pass. completed means no declared check stopped the invoice. It doesn’t mean the invoice was verified, is tax compliant or is safe to pay. Your own approval rules still decide that.
What Temlavo deliberately doesn’t do
Temlavo is one step in your workflow, not a whole accounts-payable system. There’s no invoice inbox, approval screen or review team. It doesn’t connect to QuickBooks or Xero, make payments, read receipts or handle e-invoicing compliance. You send the invoice in from wherever it arrives, and you post the JSON wherever it needs to go.
It’s built for US, English-language invoices first. Others may work, but I don’t promise they will.
How I run it
I’m building Temlavo on my own, and that shapes a few choices.
Uploaded files are deleted within a day and results within a week by default. The OCR and model providers run with zero data retention. Details are on the Security page.
Every change you can notice goes in the changelog.
I won’t publish an accuracy number without the method, the sample size and the uncertainty behind it. The first one, measured on 36 held-out invoices, is the next post.
Try it
You can run one of your own invoices in the playground without an account. To build with it, the docs get you to a first result with the TypeScript SDK or plain HTTP. If something doesn’t work the way you expect, write to me at support@temlavo.com.
Try the API in the playground
Compare sample invoices with their extracted fields, checks and full API responses. No account needed.
More from the blog
Extract invoices from Claude with the Temlavo MCP server
Connect Temlavo to Claude or another MCP client and ask in plain language: extract this invoice, does it need review, how many pages are left.
How to validate extracted invoice totals: rounding, tolerances and tax
The rules I use to check that extracted invoice amounts add up: lines, subtotal, tax rounding, total tax, total and amount due, with code to copy.
36 held-out real invoices: what we measured, and what we didn't
We measured Temlavo on 36 held-out 2020 US TV-station invoices from FCC filings: the method, the numbers with their uncertainty, and what they do not show.