Why use AI for invoice data extraction?
Traditional OCR + regex approaches break on layout variations. Every vendor formats their invoice differently. AI-based extraction reads invoices the way a human does: understanding context and structure rather than matching fixed patterns. Claude API is particularly well-suited because of its strong instruction following, structured JSON output, and ability to handle both digital and scanned PDFs.
Build an AI invoice extraction pipeline with Claude API
Step 1: Extract text from the PDF
import pdfplumber
def get_invoice_text(pdf_path):
with pdfplumber.open(pdf_path) as pdf:
return "\n".join(page.extract_text() or "" for page in pdf.pages)
Step 2: Extract structured data with Claude API
import anthropic, json
client = anthropic.Anthropic()
def extract_invoice(pdf_path):
text = get_invoice_text(pdf_path)
prompt = (
"Extract invoice data. Return ONLY valid JSON, no markdown.\n"
"Fields: invoice_number, vendor_name, vendor_address, invoice_date (YYYY-MM-DD), "
"due_date, po_number, currency, subtotal, tax_amount, total_amount, "
"line_items (array of description/quantity/unit_price/amount)\n\n"
"Invoice text:\n" + text
)
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1500,
messages=[{"role": "user", "content": prompt}]
)
raw = response.content[0].text.strip()
if raw.startswith("```"):
raw = raw.split("\n", 1)[1].rsplit("```", 1)[0]
return json.loads(raw)
Step 3: Validate the extraction
def validate_invoice(data):
errors = []
for field in ["invoice_number", "vendor_name", "invoice_date", "total_amount"]:
if not data.get(field):
errors.append(f"Missing: {field}")
if data.get("line_items"):
line_total = sum(i.get("amount", 0) for i in data["line_items"])
if abs(line_total - data.get("subtotal", 0)) > 0.02:
errors.append(f"Line sum {line_total:.2f} != subtotal {data['subtotal']:.2f}")
calc = data.get("subtotal", 0) + data.get("tax_amount", 0)
if abs(calc - data.get("total_amount", 0)) > 0.02:
errors.append(f"Subtotal+tax {calc:.2f} != total {data['total_amount']:.2f}")
return errors
Step 4: Batch processing for high-volume AP
from pathlib import Path
import pandas as pd
def process_folder(folder, output="invoices.xlsx"):
results = []
for f in Path(folder).glob("*.pdf"):
try:
data = extract_invoice(f)
errs = validate_invoice(data)
data["file"] = f.name
data["status"] = "OK" if not errs else "; ".join(errs)
results.append(data)
print(f"OK {f.name}: {data.get('total_amount')}")
except Exception as e:
print(f"ERR {f.name}: {e}")
pd.DataFrame(results).to_excel(output, index=False)
print(f"Saved {len(results)} invoices to {output}")
Accuracy benchmarks
- Digital PDFs: 97-99% field accuracy on headers. Line items 92-95% depending on table complexity.
- Scanned PDFs at 300 DPI+: 88-94% accuracy. OCR quality is the limiting factor.
- Traditional regex on consistent formats: 95%+ for known layouts, near 0% on new vendor formats.
The AI approach wins on vendor variety -- no retraining or new patterns needed for new invoice formats.
When to use Claude API vs Power Automate AI Builder
Use Claude API when: varied invoice formats, line-item extraction needed, or portability outside Microsoft required. Use Power Automate AI Builder when: already on Microsoft 365 and formats are consistent. The hybrid approach -- Python extraction feeding into a Power Automate approval flow -- gives the best of both.
We implement both. Get a free audit of your invoice workflow and we will recommend the right approach.
Want this built for you?
We implement end-to-end finance automation for teams globally. Free 30-minute audit — no commitment.
Get a free automation audit →