TL;DR
Invoice data extraction converts a supplier invoice (PDF, scan, CSV, or Excel) into structured line items your system can import: identifiers, quantities, unit costs, totals. In 2026 the method that handles real supplier variety is LLM-based extraction against a defined JSON schema, followed by arithmetic validation. Never let extracted rows into inventory without a totals check and a human-visible review step.
Invoice data extraction takes the document a supplier sends and produces machine-readable rows. The goal shape is always the same: a header (supplier, document number, date, currency, totals) and line items (what was billed, how many, at what price). What varies wildly is the input. The same distributor might send a clean CSV one week and a three-page scanned PDF with merged table cells the next.
This tutorial walks through the extraction methods available in 2026, the JSON format that holds up for line-item work, and the validation that separates a usable pipeline from a liability. The examples come from fashion wholesale, where invoices carry size-color variant rows with EAN barcodes, but the structure applies to any line-item-heavy domain.
The Three Extraction Methods
Template-based OCR. Classic invoice OCR: define zones or anchors per supplier layout, extract text positionally. Works when you receive thousands of identical invoices from few senders. Fails at exactly the point fashion wholesale lives: dozens of suppliers, each with a different layout that changes without notice. Every new layout is setup work.
Rule-based parsing for structured files. CSVs and Excel exports do not need OCR, but they still need interpretation: which column is the EAN, whether "colore" and "col." are the same field, what to do with subtotal rows embedded mid-table. Hand-written parsers per supplier ossify quickly. Useful as a fast path, not as the strategy.
LLM extraction against a schema. A multimodal model reads the document (native PDF, scan, or spreadsheet text) and returns JSON conforming to a schema you define. No per-supplier templates. Layout changes do not break it. Column-name variants ("qty", "q.tà", "pcs") resolve from context. This is the method that finally matches the diversity of real supplier documents, and it is how Agilo extracts every document type it ingests.
The catch with LLM extraction is that it fails politely: wrong numbers arrive in perfectly valid JSON. That moves the engineering effort from parsing to validation, which is the right trade because validation is checkable arithmetic.
Classify Before You Extract
A pipeline that receives "whatever the supplier sent" cannot assume every file is an invoice. The same email attachment batch typically mixes an order confirmation, a delivery note, a price catalog, and the invoice itself, and each answers a different question. An order confirmation carries ordered quantities and agreed costs; a delivery note carries shipped quantities; a catalog carries no quantities at all, only the assortment and list prices.
Classification is therefore the first extraction call: given the document, return its type and role. It is a cheap, reliable model task, and it determines which schema the real extraction uses and how the resulting rows are allowed to affect inventory. Rows from a catalog should never create stock; quantities from an order are expectations, not arrivals. Skipping classification and extracting everything as "an invoice" is how a price list becomes 4,000 phantom units.
The JSON Format That Works
Ask for the smallest structure that answers your business question, not a transcript of the page. For line-item invoices:
{
"documentType": "invoice",
"supplier": "Example Fashion Srl",
"documentNumber": "2026/0417",
"documentDate": "2026-06-11",
"currency": "EUR",
"lines": [
{
"sku": "KMS26167",
"ean": "8051234560011",
"description": "Boxy Wool Overshirt",
"colorName": "Camel",
"size": "M",
"quantity": 4,
"unitCost": 62.5,
"lineTotal": 250.0
}
],
"declaredUnits": 96,
"declaredTotal": 6120.0
}
Design notes that pay off later:
- Ask for
lineTotaland the declared document totals even though they are redundant. Redundancy is what makes validation possible. - Keep identifiers separate (
skuvsean); suppliers use them inconsistently and you will match on either. - Extract attribute fields (
colorName,size) as the document writes them. Normalization ("IT 50" to "50") is a separate, deterministic step; mixing it into extraction hides errors. - One schema per document type. An invoice, an order confirmation, and a packing list share the line structure but differ in header semantics, so classify the document first, then extract with the matching schema.
Validate with Arithmetic, Not Vibes
Extracted JSON is a claim. Before it touches inventory, check the claims against each other:
- Line math:
quantity × unitCost ≈ lineTotalper line, within rounding tolerance. - Document math: sum of line quantities vs
declaredUnits; sum of line totals vsdeclaredTotal. - Identifier sanity: EAN-13 check digits actually validate. A transposed digit fails the checksum and gets caught for free.
- Cross-document checks: invoice quantities vs delivery note quantities vs order quantities, matched per EAN.
Step 4 is where extraction becomes operationally valuable. A shipment that bills 100 units while the packing list shows 96 is a real dispute worth catching on day zero. Agilo's import pipeline runs exactly this comparison and emits anomalies (short shipment, over shipment, shipped-but-not-ordered, totals mismatch) that a human resolves before stock posts; the receiving side of that workflow is described in Wholesale Inventory Management Software for Fashion.
A totals mismatch is not an extraction failure; it is the pipeline doing its job. Half the time the model read correctly and the documents genuinely disagree. The review step exists to tell those cases apart.
Handling Scans and Low-Quality PDFs
Native PDFs carry a text layer worth checking first: if the text layer has reasonable density, extract from text and skip image processing entirely. Scans and photo PDFs go to the multimodal model as images.
Practical thresholds from production use: treat a PDF page with under a couple hundred characters of extractable text as a scan, and cap file sizes so one 40MB photographed invoice does not stall the queue. Chunk long multi-page documents with overlapping rows so table rows split across page breaks are not lost between chunks.
Expect a residual error rate on genuinely bad scans regardless of model quality. The system design assumption should be "extraction is 95 percent, validation catches the rest", never "extraction is perfect". When a supplier's scans fail repeatedly, the cheapest fix is usually upstream: ask them for the CSV export their own system already produces.
Using an Extraction API
If you are wiring extraction into your own system, the integration shape is the same across providers: send the document, receive JSON against your schema. A minimal flow looks like this:
result = extract(
file="fattura_2026_0417.pdf",
schema=INVOICE_SCHEMA,
prompt="Extract the invoice header and every line item. "
"Report quantities and prices exactly as printed.",
)
errors = validate(result) # line math, totals, EAN checksums
if errors:
queue_for_review(result, errors)
else:
stage_rows(result.lines)
Three implementation details decide whether this works in production:
- Temperature zero, schema-constrained output. Extraction is transcription, not creativity. Constrained decoding against a JSON schema removes the "almost valid JSON" failure class entirely.
- Prompt for fidelity, not interpretation. "Exactly as printed" matters: you want the model to report a suspicious quantity, not to fix it silently. Interpretation belongs in your validation layer where it is testable.
- Log the raw model output alongside the parsed result. When a number is wrong three weeks later, the stored evidence answers whether the document, the model, or your matching logic is at fault.
Measure accuracy on your own documents, not vendor benchmarks. Twenty representative invoices, hand-verified once, give you a per-field error rate that tells you where validation must be strict and where sampling is enough.
From Extracted Rows to Inventory
Extraction is the first half. The second half is matching lines to your catalog:
- EAN matches an existing variant: attach, carry the cost.
- EAN unknown, SKU known: probable new variant of an existing product (a new size or colorway).
- Both unknown: create product and variants, flagged for review.
This matching step is why extraction belongs inside the inventory system rather than in a standalone tool that emails you a spreadsheet. The output of a good pipeline is not JSON; it is draft catalog rows with per-row status a human can approve. The data model those rows land in is covered in Fashion Inventory Management Software: A Buyer's Guide.
Build or Buy in 2026
Building a solid invoice extraction pipeline means: document classification, per-type schemas, a multimodal extraction call, arithmetic validation, cross-document reconciliation, catalog matching, and a review UI. Each piece is tractable; the integration is the project.
Buying makes sense when extraction is a means, not your product. For fashion and apparel businesses, that is the reason we built the pipeline directly into Agilo: the deliverable is not extracted JSON but a verified shipment ready to close into stock.
Whichever route you take, hold it to the same bar: real documents in, validated variant rows out, every discrepancy visible, nothing entering inventory unreviewed.