Batch invoice processing in n8n: upload multiple invoices via a form, extract the data in one go [Workflow included]

:waving_hand: Hey n8n Community,

I’ve built a lot of finance workflows over the last few weeks and months for a couple of friends who run small businesses. Going back through my n8n library the other day, I realised I’d never actually shared the most basic one people keep asking me for: a simple batch invoice processing flow.

So I put one together. You upload multiple invoices through a single form (JPG, PNG, or PDF), and it extracts the data from all of them in one go, instead of dragging every invoice in one by one.

Here’s what it does:

The form takes one or many files. Each invoice gets read and the key fields come out structured: invoice number, date, vendor, customer, total, currency, payment status, and so on. Every result lands as a row in a Google Sheet, so your invoice data extraction ends up somewhere you can actually filter and sort.

The part I find most useful day to day is the error log. When the upload finishes, the form shows a summary listing every file with a :white_check_mark: or :cross_mark:. If an invoice was blurry, cropped, or just missing a core field like the invoice number or total, it gets flagged so you know exactly which one to re-check. No silently dropped invoices.

A couple of build notes for anyone who wants to take it apart:

It uses the easybits Extractor node for the actual extraction. The flow loops one file at a time on purpose, since the extractor bundles everything you hand it into a single request, so looping is what gives you one clean result per invoice.

Workflow JSON:

And the rest of my finance and invoice processing workflows are on my n8n creator page: easybits | n8n Creator

Curious how others here handle the failures. Do you flag bad invoices for manual review like this, or route them somewhere else entirely?

Best,
Felix

2 Likes

Solid share - the Loop One File at a Time pattern is the right approach here to keep memory usage flat regardless of batch size. For failures, the pattern I use is routing flagged invoices into a separate Google Sheet tab (“needs review”) with the original filename, the raw AI output, and the specific field that failed validation, then sending a daily summary email with those rows. That way nothing is silently dropped and the human reviewer has all the context they need to fix and re-run just those files.

Hey @nguyenthieutoan, thank you for the feedback! Flagging failed invoices in a separate Sheets tab is a great idea. In my current setup, I usually send those cases to a human reviewer via Slack instead. The reviewer then gets a simple button-based option to either process the invoice manually or route it through a fallback extraction process powered by a different model (we already have this fallback option in the Extractor I’m using internally, and it will be rolled out within the next few weeks).

That said, I really like your approach as well, especially the idea of daily summary emails. I’ll definitely consider implementing something similar for my own use cases.

In my case, I would also extend it slightly to show which invoices were reprocessed via the fallback route and how many were handled manually. That would make it easy to provide a clear daily or weekly overview and add more transparency to the whole process.