Line item extraction from invoices
6 min read
Line item extraction pulls the repeating table from an invoice — each product or service line with its description, SKU, quantity, unit price and amount — into structured rows, rather than just the header fields like vendor, date and total. It is what makes PO matching, spend analysis and inventory reconciliation possible, and it is the part most OCR tools get wrong.
Header fields versus line items
Every invoice has a handful of header fields — vendor, invoice number, date, due date, currency, total — that appear once and are easy to locate. Then it has a table. The table can be three lines or three hundred; it can span pages; it can have a different set of columns from every other supplier's table. Extracting the header tells you how much to pay. Extracting the lines tells you what you are paying for, which is the question every downstream process actually asks.
Spend analysis needs line categories. PO matching needs line quantities and prices. Inventory needs line SKUs. Tax needs line-level rates. An invoice extracted without its lines is a payment instruction with no content.
Why tables are the hard part
A total is a single value in a predictable neighbourhood of the page. A table is a structure, and the structure is different everywhere. Classic OCR reads characters and positions; it does not know that the number under "Qty" belongs to the description two cells to its left, or that the description wrapped onto a second line, or that the last three rows are subtotals rather than items.
- Column sets vary per supplier: some have SKU and description, some have only description, some split unit price into net and gross.
- Multi-line descriptions wrap, and the second line looks like a new row to a position-based parser.
- Tables span pages, with headers repeated or not, and running totals at the bottom of each.
- Non-item rows — subtotals, discounts, freight, tax, "continued" — sit inside the table and must be classified, not extracted as products.
- Merged cells, right-aligned numbers drifting into the next column, and scanned skew all break coordinate-based parsing.
- Units and pack sizes hide in the description ("per case of 12") rather than in their own column.
Template-based versus template-free extraction
Template-based tools solve tables by having you draw the table region and columns for each supplier's layout. It works — for that supplier, until they change their invoice format, at which point it silently produces wrong rows until someone notices. The maintenance cost scales with your supplier count, which is why teams with hundreds of vendors abandon these tools.
Template-free extraction uses a model that understands what an invoice line is, in the same way a person does, and returns rows against a schema you define once — description, quantity, unit price, amount — regardless of the layout. The trade-off is that a model can misread, which is why the output should be verified rather than trusted: arithmetic checks on each row, and human review when a check fails.
What good line-item output looks like
The output should be a table, not text: one row per item, one typed column per field, with numbers as numbers and dates as dates. Each row should carry the fields your downstream process needs and nothing that belongs to the header. Non-item rows should be excluded or flagged, not mixed in. And the output should be verifiable: if unit price times quantity does not equal the line amount, that row is wrong and should say so.
- Description — verbatim, because it is what any later matching or categorisation is derived from.
- SKU or part number — the supplier's, plus your own if a lookup can resolve it.
- Quantity and unit of measure — as separate fields.
- Unit price and line amount — both, so the arithmetic can be checked.
- Tax rate or code per line, where the jurisdiction requires it.
- A row-level verification status: arithmetic passed, or flagged with the reason.
Where Tavnit fits
In Tavnit, line items are table fields on a flow: you name the columns once, and every invoice from every supplier is extracted into those columns as typed rows, with no per-vendor template. A formula Cleaner verifies unit price times quantity per row; a lookup Cleaner resolves supplier part numbers to your SKUs; a category Cleaner assigns spend categories. Rows that fail a check route the run to a reviewer. Results land in a Bucket you can query or chart, or go straight to your systems by API or webhook.
Common questions
- Can OCR extract line items from invoices?
- Plain OCR extracts characters and their positions; it does not understand table structure, so it produces text that still has to be parsed into rows. Reliable line-item extraction needs a layer that understands what an invoice line is, either a per-supplier template or a model that generalises across layouts.
- How do I extract invoice tables without a template per supplier?
- Use an extraction model that returns rows against a schema you define — description, quantity, unit price, amount — regardless of layout, then verify each row with an arithmetic check and route failures to a reviewer. This is what Tavnit's table fields do.
- How should multi-page invoice tables be handled?
- The extraction should treat the table as one logical table across pages, ignoring repeated headers and per-page running totals, and return a single set of rows. Check that the rows sum to the invoice total to confirm nothing was dropped at a page break.
More guides
Try it on one document
Build a flow, send a real document through it, and see what comes back. Free credits to start.
Start free