~/$ mbaurin's blog

building a personal finance app: a journey through open banking hell

i thought building a personal finance app would be straightforward. connect to my bank, pull transactions, categorize spending, done. maybe add some charts, track my ridiculous coffee expenses, finally understand where my money actually goes.

then i met open banking APIs.

turns out "open" is like saying a maze is "accessible." technically true, but you might die trying to find the exit.

the naive plan

the idea was simple: build a dashboard to track my spending patterns. nothing fancy, just something that would automatically categorize transactions and show me trends over time.

open banking promised exactly what i needed. standardized APIs to access account data, transaction history, real-time balances. the european PSD2 directive made it mandatory for banks to provide this access. regulatory compliance creating developer opportunities, what could go wrong?

everything, as it turns out.

choosing the battlefield

first decision: which aggregator to use? there are dozens of providers, each claiming the best coverage, most reliable uptime, clearest documentation. i went with Powens because they covered french banks and their docs did not make me want to quit programming.

after years of working with distributed systems at my company, i have learned to appreciate tools that just work. this would not be one of them.

authentication: a journey through hell

connecting to my bank account should have been simple. click connect, enter credentials, done.

instead i got a journey that would make Dante weep:

  1. redirect to Powens
  2. redirect to my bank
  3. two-factor authentication via SMS (but the SMS takes 3 minutes to arrive)
  4. another redirect
  5. consent screen that looked like it was designed during the dot-com bubble
  6. back to Powens (maybe, if the session did not timeout)
  7. back to my app (hopefully)

the whole flow took longer than ordering coffee and involved more domains than a DNS lookup gone wrong. i started to understand why most people just screenshot their bank statements.

but it worked. i had access to my transaction data.

the reality of "standardized" data

here is what i expected from my transaction data: clean, structured information with consistent categorization and merchant names.

here is what i got:

VIR SEPA RECU /DE THEO VIRMONT /MOTIF REMBOURSEMENT /REF 20231201-ABCD

this was my friend paying me back for dinner.

every bank formats transaction descriptions like they are trying to win an obfuscation contest. some include merchant category codes, others do not. some have clean merchant names, others give you raw payment processor references that look like serial numbers.

"standardized" apparently means "we all send JSON but the content is pure chaos."

building transaction categorization became an exercise in digital archaeology, digging through layers of banking legacy to find actual meaning.

the parsing nightmare

at the company i work at we deal with marketplace data from hundreds of different sellers, each with their own product catalog formats. this was worse.

at least sellers want their products to be understood. banks seem actively hostile to comprehension.

i ended up with regex patterns that looked like incantations:

// Detect friend payments (because apparently this is rocket science)
const friendPaymentRegex = /VIR\s+SEPA.*\/DE\s+([A-Z\s]+).*\/MOTIF\s+([^\/]+)/i;

// Parse merchant names from card transactions
const merchantRegex = /CARTE\s+\d+.*?\s+([A-Z\s]+)\s+LE\s+\d{2}\/\d{2}/i;

each bank had different formats. each transaction type had different structures. edge cases had edge cases.

what actually worked (eventually)

despite feeling like i was reverse-engineering financial hieroglyphs, the core functionality came together. i could sync transactions, categorize spending, and see trends over time.

the most valuable insight was not technical: i spend way too much money on random online purchases. seeing "miscellaneous internet shopping" as my second-largest expense category was sobering.

the hidden complexity

what i thought would be a weekend project became a month-long journey through financial data archaeology. every integration took three times longer than expected because you are not just building software, you are translating between decades of banking legacy and modern expectations.

but here is the thing that surprised me: once you understand the chaos, patterns emerge. banks might format data differently, but the underlying financial flows are consistent. money moves in predictable ways, even when the data describing those movements looks like it was encrypted by a drunk robot.

lessons from the trenches

first, "open" does not mean "easy." regulatory compliance creates access, but does not guarantee sanity.

second, financial data is messy by design. banks are not tech companies. their systems reflect decades of regulatory requirements, legacy decisions, and the fundamental truth that moving money is hard.

third, building fintech products requires the patience of a saint and the debugging skills of a detective. every integration is an adventure in digital archaeology.

but most importantly: the infrastructure is clunky, but the value is real. my little finance dashboard now pulls data from multiple accounts, categorizes transactions, and shows me spending patterns i never noticed before.

understanding how money moves through these systems makes me appreciate the complexity behind every tap-to-pay transaction. we complain about banking UX, but the fact that any of this works at all feels like a minor miracle.

sometimes the best way to understand a system is to try building on top of it. even if that system was apparently designed by people who hate developers.