Case Study: Rewriting What Parsing Can Do

nau!’s mission fits in one sentence: help people in Spain find the best mortgage deal, and flag the moment switching lenders is actually worth the paperwork. To do that, nau! needs to know exactly what someone is paying right now: outstanding balance, rate, margin, term, monthly payment, and who they’re paying it to.
LLM
document parsing
production
agents
customer story
Published

September 18, 2026

Where We Started

nau!’s mission fits in one sentence: help people in Spain find the best mortgage deal, and flag the moment switching lenders is actually worth the paperwork. To do that, nau! needs to know exactly what someone is paying right now: outstanding balance, rate, margin, term, monthly payment, and who they’re paying it to. All of that sits in a mortgage statement the user already has on their phone.

Reading that statement automatically was always the plan. Nobody should have to retype numbers they’re already holding in their hand.

The problem: Forty Banks, Zero Patience

Here’s the catch. Every bank writes its statement differently and calls the same number three different things. On top of that, most people don’t hand over a clean PDF. They upload a photo taken on the kitchen table, or a screenshot from their banking app, and both come out messier than any clean document would.

When the reading failed, the app fell back to asking people to type the numbers in by hand, right in the middle of signing up for something they hadn’t even tried yet. A lot of them just stopped there.

There’s no soft failure mode here, either. Get a number wrong, and you’re not looking at a typo. You’re handing someone bad financial advice.

Our solution: Split the Job, Trust the Answer

We redesigned nau!’s reading pipeline on Claude and rebuilt it around two simple steps.

The first step answers a single question: which bank issued the statement. The second step reads the actual numbers, using a template built for that specific bank. Each template spells out what shows up on that bank’s statement, what each field is called, and roughly where it sits on the page. There are about forty of these, one per lender, plus a generic fallback for anything that doesn’t match.

We split the work this way because asking one pass to do both jobs is asking too much of it. It would have to figure out which bank’s statement it’s looking at while also hunting for numbers whose names depend on that answer. Once the bank is known, the second step already knows exactly what it’s looking for.

The reason there are forty separate templates, instead of one that covers every bank, comes down to precision. A template built for one bank can be exact: this field is called this, and it sits here. A template meant to cover every bank can only say “look for something that means outstanding balance,” and that vagueness is exactly where most misreadings came from. Before the redesign, 29% of statements were falling through to that generic template, and those were the readings the system trusted the least.

Both steps also require the model to answer in a fixed format: a form with named fields it has to fill in, nothing else. An empty field is something the code can handle. A paragraph of explanation sitting where a number should be is what used to break things downstream.

Three checks stand between a reading and the database. Is this even a mortgage statement? (Over sixty days, the system turned away twenty-one files that had nothing to do with a mortgage.) Does the bank the model guessed match what the IBAN itself says? (If not, the reading gets thrown out and redone.) And then there’s the user: every reading is saved next to whatever they later correct by hand, so the team always knows exactly what to fix next. Nothing irreversible happens without the user confirming it first.

The real impact: Reading With a Little Bit of Judgment

Here’s the part that actually makes this different, and it’s not really about reading at all. It’s parsing. Parsing itself isn’t new, it’s been around for years. What’s new is how fast and how easy it’s gotten.

The old way meant a couple of developers and a few weeks to hardcode every field for every bank format. Once that code existed, it was rigid. A bank tweaks its layout, moves a field, changes a label, and the whole thing breaks until someone goes back in and rewrites it.

This version was built in under a week by someone with no technical background, and it kept getting better with input directly from nau!’s own team, no dev cycle required.

The real difference is that the model behind it can make small decisions on its own. It doesn’t need every single field hardcoded to work. If a bank makes a small change, a slightly different layout, a relabeled field, the agent can still adapt and read it correctly. Traditional code doesn’t have that option. If the statement didn’t match exactly, that was it: a developer had to go back in and rewrite it. Here, a small variation just doesn’t break anything.

There’s also a second agent running quietly every night, going through every statement the system has seen and getting a little sharper each time. Fifteen nights in, it had read 210 mortgage statements on its own and built a fingerprint catalog covering 21 different banks, with no one checking its work and not a single mistake.

We designed three levels of autonomy for this agent and deliberately started it at the most cautious one: observe and accumulate. It doesn’t write anything a client will ever see. Since these statements carry someone’s name, ID number, and IBAN, the catalog it builds is limited to a fixed set of fields, verified against the database, not just whatever it decided to ask for in a prompt. We’d rather an error cost us an empty table than have someone find it in their own mortgage.

That’s the real shift here. We used to save the documents themselves, because that was the only way for the system to learn. Now we save what it learned, and we can delete the documents.

The Numbers Don’t Lie

The biggest gain showed up on the hardest input: a photo taken on a phone. Before the redesign, the system picked the wrong bank template for roughly half of those. Right after we shipped the fix, that number dropped to under a third, and it keeps shrinking as the system teaches itself a little more with every statement it reads. Outright failures, where the reading breaks and nothing comes back at all, now sit at 1.2%, twelve out of every thousand statements. Before we rebuilt it, that number couldn’t even be measured, because those failures weren’t being logged in the first place. Today, the system has read 1,873 statements for 1,008 users.

In our client’s own words

Automating this one step didn’t just cut down on manual data entry, it took away the single biggest point where people were dropping out of signup, and gave the nau! team the confidence to keep building faster on top of it.

“This agent has been working alone for fifteen nights now: it’s read 210 mortgage statements and built a fingerprint catalog of 21 banks, with no one checking its work and not a single mistake. (…) The hardest part wasn’t deciding what it could do. It was deciding what we wouldn’t let it do.(…) The real shift is we used to save documents because that was the only way to learn. Now we save what we learned, and we can delete the documents, increasing our customer’s data safety”

Sergio Carbajal, CEO of nau!

There’s more to build here, and we’re glad to be building it with the team at nau!.