Case study

Replacing manual invoice entry with AI extraction at Omni Logistics

Staff at Omni Logistics spent six to seven hours a day working through more than a thousand invoices, typing figures into a spreadsheet and entering them again into NetSuite. We built a pipeline that extracts the data automatically using OpenAI models, handles the fact that every vendor formats invoices differently, and pushes it through to NetSuite on its own. That daily work is now thirty minutes to an hour of checking totals and reviewing flagged entries.

  • OpenAI
  • AWS
  • NetSuite
  • Step Functions
  • AWS Batch
  • DynamoDB
  • SOAP/XML
Overview

At a glance

Client
Omni Logistics
Industry
Logistics and supply chain
Engagement
3 months, 3 engineers
Scale
Over 1,000 invoices a day. Millions of invoice line items in the weekend processing run.
Result
Daily invoice handling reduced from 6 to 7 hours to under an hour. Weekend processing window cut from 6 to 7 hours to around 3.
Stack
PDF text extraction, OpenAI models for structured extraction, AWS (S3, SQS, Lambda, Step Functions, Batch, DynamoDB, CloudWatch, IAM, API Gateway), NetSuite SuiteTalk, SOAP and XML
The problem

The problem

Omni Logistics ran on enterprise systems that had grown up separately. NetSuite held the business records. Logistics and operational data sat elsewhere. The two had no reliable connection between them.

So people filled the gap, and the clearest example was invoices.

A member of the team would open an invoice, read the figures off it, and type them into a spreadsheet. Then the spreadsheet contents were entered into NetSuite. Every invoice, one at a time, more than a thousand a day, for six to seven hours.

The part that made it genuinely hard to automate with ordinary rules is that every vendor formats invoices differently. Different layouts, different labels, different places for the total, different ways of listing line items. A template that works for one supplier fails on the next one, which is why this kind of work tends to stay manual long after everything around it has been automated.

That has two costs. The obvious one is most of a working day, every day, spent on data entry. The less obvious one, and usually the more expensive, is that people make mistakes when they read numbers off a document and retype them twice. Those mistakes surface weeks later, when someone is trying to work out why two systems disagree about the same invoice.

Separately, there was a processing problem in the pipeline underneath. The weekend run handled millions of invoice line items and took around seven hours, largely in sequence, so a single failure could compromise the batch with little room to rerun it.

What we built · 01

Reading invoices with AI, whatever format they arrive in

The first step was getting the data off the invoice without a person reading it.

We used AI extraction rather than templates or fixed rules, because templates are what fail here. The system reads an invoice it has not seen the layout of before and pulls out the fields that matter: totals, line items, vendor details, dates, reference numbers. It does not need a new template every time a supplier changes their invoice design or a new vendor comes on board.

How it works in practice: we extract the raw text from the invoice PDF, then pass it to OpenAI models with instructions to return the fields we need as structured JSON. That JSON is what moves through the rest of the pipeline. Because the model is reading the document rather than matching a template, a layout it has never seen is not a special case.

The extracted data is written into the spreadsheet layer the business already worked with, then flows automatically into NetSuite. The step where someone retyped figures from one place to another is gone.

What we built · 02

Keeping people on the part that needs judgement

The pipeline does not silently accept everything it reads. Totals are checked. Entries that look wrong, or that the extraction is not confident about, are flagged rather than pushed through.

So the job changed rather than disappeared. Instead of entering every invoice by hand, the team verifies totals and reviews the exceptions the system raises. That is a much smaller amount of work and it is the part where a person is actually adding something.

This is deliberate and we build it the same way now. A system that quietly makes a decision it should not have made is worse than one that asks. The aim is to remove the routine ninety percent, not to pretend the last ten percent does not exist.

What we built · 03

Connecting the systems

NetSuite was the system of record for much of the business data, and it speaks SOAP rather than REST. We built integrations against NetSuite SuiteTalk covering the operations the business actually needed: creating, updating, deleting, searching and upserting records, including batched list operations for volume.

That meant working with WSDL and XSD definitions, XML request and response structures, and NetSuite's internal and external ID model, which is how records get matched across systems that each think they own the data.

The business processes this supported were invoice processing, reconciliation, record synchronisation and logistics data updates. In other words, the things people had been doing by hand.

What we built · 04

Reconciling records across systems

The reconciliation logic that lived in people's heads and spreadsheets became part of the pipeline. Records are matched across systems on their identifiers, differences are resolved by defined rules rather than case by case judgement, and anything genuinely ambiguous is raised for review.

What we built · 05

Event-driven processing on AWS

We moved the processing to an event-driven model, so work is broken into independent units that can be processed, retried and recovered on their own rather than as one long sequential run.

Data lands in S3. Arrivals push messages onto SQS. Lambda functions process them. Results are written to DynamoDB. Anything that fails goes to a dead letter queue where it can be inspected and reprocessed without disturbing the rest of the run.

In the previous design, one bad record could compromise a batch and cost a weekend. Now a failure is a single message someone looks at on Monday, while everything else has already finished.

What we built · 06

Orchestration and batch compute

Some flows needed several stages in a defined order with proper failure handling, which is more than one Lambda should be doing. We used Step Functions state machines to coordinate those, including retries, sequencing and parallel execution where the data allowed it.

Some workloads were too large or too long-running for Lambda's limits at all. Those moved to AWS Batch, where each job declares the CPU and memory it needs and gets scheduled against available compute, which kept heavy processing from competing with everything else.

What we built · 07

The weekend processing window

This is a separate piece of work from the invoice extraction, on the pipeline underneath it.

The optimisation was not a single change. We traced the pipeline end to end and measured where the time was actually going rather than where we assumed it was, then restructured how work was batched, sequenced and distributed.

Around seven hours became roughly three, across millions of line items.

The result

What changed

Invoice handling went from six to seven hours a day to somewhere between thirty minutes and an hour, on a volume of more than a thousand invoices daily. The work changed from opening and typing every invoice twice to checking totals and handling the entries the system flagged.

Errors from reading figures off a document and retyping them stopped being a source of downstream problems, because extraction and matching behave the same way every time and anything uncertain gets flagged instead of guessed.

New vendors and changed invoice formats stopped being a problem to solve. The extraction handles layouts it has not seen rather than needing a template built for each one.

Separately, the weekend processing window went from around seven hours to three, which left real room to rerun if something went wrong instead of losing the window entirely.

Failures became recoverable in isolation rather than requiring a full rerun.

The architecture handles more volume by distributing it rather than taking proportionally longer.

Why it matters

Why this matters if you are reading it

Most of the operations automation work we do now looks like this at a smaller scale. Two systems that were never designed to talk to each other, a person or a weekly job bridging them, and a process that works until the person is on leave or the volume grows.

This project is also why we talk about AI the way we do. The extraction is the part people find interesting, but it was worth nothing on its own. It mattered because the data it produced could reach NetSuite reliably, because failures were visible, and because a person still checked the things worth checking. AI on top of a broken pipeline is a demo. AI on top of a working one removes a job nobody wanted to do.

Tell us what you're trying to build

Fifteen minutes, no deck. Bring us a workflow that's eating your team's time, or a product idea you want built, and we'll tell you what we think it takes, what it roughly costs, and whether it's worth doing at all. Sometimes the answer is no, and we'll say so.

+91 8910704554(WhatsApp available)
ask@yeasitech.comMon-Fri, 10AM-7PM IST (Overlaps with UK, EU, Middle East & Australia)

Or send us the details