Every Tuesday and Thursday, the accounting team at one of our clients sat down for what they called "invoice day." Two people, roughly four hours each, manually processing incoming invoices from about 40 different vendors.
The process looked like this: open an email, download the PDF attachment, open the invoice, manually key in the line items and totals into their accounting software, cross-reference against the original purchase order to make sure the amounts matched, flag anything that looked off, and move on to the next one. Eighty to a hundred invoices a week, every week.
They'd been doing it this way for years. It worked, in the sense that invoices got processed. But the error rate was running around 8%, mostly typos and transposition errors from manual data entry. Every error meant someone had to go back, find the discrepancy, fix it, and sometimes contact the vendor for clarification. That follow-up work was eating another several hours a week.
The client asked us if there was a better way. There was.
Understanding the Real Problem First
Before we wrote a single line of code, we spent a day with the accounting team. We wanted to understand not just what they did, but why they did it that way.
It turned out the process had more nuance than "type numbers into a system." Some vendors sent invoices as PDFs with perfectly structured tables. Others sent scanned images of paper invoices that were slightly crooked and occasionally smudged. A few vendors still sent invoices as Excel attachments. One particularly old-school supplier sent them by fax (yes, in 2025), and someone in the office scanned those into PDFs.
The validation step was also more complex than a simple number comparison. The team was checking line item descriptions against purchase orders, verifying that quantities matched what was actually received (which sometimes differed from what was ordered), and applying different tax rules depending on the vendor's location.
Any automation system that ignored these details would have been useless. So we designed around them.
What We Built
The system has four main stages, and Python was the right tool for every one of them.
Stage 1: Intake. A Python script monitors the shared email inbox and a designated folder on the company's file server. When a new invoice arrives (PDF, image, or Excel), it gets picked up automatically and dropped into a processing queue. No more manually downloading attachments.
Stage 2: Data extraction. This is where things get interesting. For well-structured PDF invoices, we used a combination of pdfplumber and some custom parsing logic to pull out vendor name, invoice number, date, line items, quantities, unit prices, and totals. For scanned or image-based invoices, we used Tesseract OCR through Python's pytesseract wrapper to convert the image to text first, then applied the same extraction logic. Excel files were the easiest, handled with openpyxl.
We didn't try to build a universal parser that could handle any invoice format on earth. Instead, we built a template system. For each vendor, we created a simple configuration that told the system where to find the key data points on their specific invoice layout. Setting up a new vendor template takes about 15 minutes.
Stage 3: Validation. Once the data is extracted, the system compares it against existing purchase orders in the client's database. It checks quantities, unit prices, and totals. It applies the correct tax calculations based on vendor location. If everything matches within tolerance (we allowed for rounding differences of up to $0.02), the invoice is automatically marked as verified.
If something doesn't match, the invoice gets flagged with a specific reason: "Unit price differs from PO by $3.50 on line item 4" or "Quantity received (45) doesn't match invoice quantity (50)." This is a huge improvement over the old process, where the team had to manually figure out what was wrong.
Stage 4: Integration. Verified invoices are pushed directly into the client's accounting system through its API. Flagged invoices go into a review queue with all the context the team needs to resolve them quickly.
The Technical Decisions
We went with Python for a few specific reasons, not just because it's popular.
First, Python has the strongest ecosystem for document processing. Libraries like pdfplumber, pytesseract, and openpyxl are mature and well-maintained. We didn't have to reinvent any wheels for the extraction work.
Second, the client's accounting system had a REST API, and Python's requests library (combined with some retry logic using tenacity) made the integration straightforward.
Third, and this matters more than people think, Python is readable enough that the client's in-house IT person (who isn't primarily a developer) can understand and maintain the code. We weren't going to be the only people touching this system forever, so we chose clarity over cleverness. We used type hints throughout, wrote docstrings for every function, and kept the architecture flat enough that you don't need a PhD in software engineering to follow it.
The whole system runs as a set of scheduled tasks on a Windows server the client already had. No cloud infrastructure needed, no monthly service fees beyond what they were already paying. We used Python's built-in logging module to write detailed logs, so when something does go wrong, the team can see exactly what happened.
What We Didn't Do
We intentionally kept machine learning out of this project. Could we have trained a model to automatically recognize invoice layouts without templates? Probably. But it would have taken three times as long to build, been harder to debug when it made mistakes, and given the client a system they couldn't understand or maintain.
The template-based approach is less glamorous, but it's predictable. When the system processes a Vendor X invoice, the client knows exactly what rules it's applying. If a new vendor starts sending invoices, adding a template takes 15 minutes, not a retraining cycle.
There's a time and place for ML-based document processing. For 40 vendors with consistent invoice formats, templates were the right call.
The Results
The system went live on a Monday. By Wednesday, the accounting team's invoice processing time had dropped from roughly 16 person-hours per week to about 2 hours, and those 2 hours were spent reviewing the flagged exceptions, not doing data entry.
Here are the numbers after the first three months:
- Processing time: Down from 16 hours/week to 2 hours/week. That's 14 hours returned to the team every week, or roughly 728 hours over the first year.
- Error rate: Down from 8% to under 0.5%. The remaining errors were almost entirely from OCR misreads on particularly low-quality scanned invoices, which the system correctly flagged for human review.
- Processing speed: An invoice that used to take 8-10 minutes of manual work now takes about 12 seconds from intake to accounting system entry.
- Vendor onboarding: Adding a new vendor template takes about 15 minutes. The client's IT person has added six new ones on their own since we delivered the system.
The cost savings paid for the entire development project within the first four months.
What We Learned (Again)
This project reinforced something we keep relearning: the best automation projects start small and target a specific, painful, repetitive task. The client didn't ask us to "automate their finance department." They asked us to fix one process that was eating two people's time every week.
That focused scope is what let us deliver something useful in about six weeks. If we'd tried to boil the ocean and automate every accounting workflow simultaneously, we'd still be in the requirements phase.
The other lesson: spend more time understanding the current process than you think you need to. That day we spent watching the team work revealed the edge cases (faxed invoices, quantity discrepancies, vendor-specific tax rules) that would have derailed the project if we'd discovered them during testing instead of during planning.
Is This Relevant to Your Business?
Invoice processing is just one example. We've built similar Python automation systems for purchase order matching, employee onboarding paperwork, report generation, and data migration between systems that don't talk to each other.
The pattern is always the same: a team spending hours on repetitive, rules-based work that a well-built script can do in minutes. If your team has a process like that, one where someone sighs every time it's their turn to do it, there's probably a straightforward automation opportunity.
We'd be happy to take a look and tell you honestly whether it's worth automating. Sometimes the answer is yes, sometimes it's "not yet." Either way, let's talk about it.
