DATA CONSULTING SERVICES

Building Stay Steady for iOS — Our Experience with Open Banking in Belgium (and Why We Removed Bank Sync)

by Data Consulting Services
iOSOpen BankingPSD2BelgiumFinTechIndie DevSwiftUIStay Steady

When we set out to build Stay Steady — a privacy-first budgeting app for Belgian users — we thought open banking would be the easy part. PSD2 has been EU regulation since 2018. Aggregators promised one API for every bank. Belgian banks were “supported.” On paper it looked like a solved problem.

Our experience said otherwise. This is the story of what we actually went through, what worked, what didn’t, and why the version of Stay Steady you can download today on the App Store has no bank connection at all — by design.

What we wanted

The product idea was simple: a native iOS app where a Belgian user — a Belfius, KBC, ING Belgium, Fortis, Argenta, or Crelan customer — could connect their bank, see categorized transactions, set savings goals, and get real-time spending insights. All on-device, privacy-first, with optional iCloud sync. Trilingual EN/NL/FR because that’s how Belgium actually works.

The stack was modern: Swift 6.1, SwiftUI with the MV (Model-View) pattern, SwiftData for persistence, Core ML for on-device categorization. We trained our own classifier on real Belgian transaction patterns and got it to 99.8% accuracy. The AI piece worked beautifully.

The bank piece — that was the long story.

Attempt #1: Tink (the big-name option)

Tink is the biggest PSD2 aggregator in Europe, owned by Visa, with an SDK that supports most of the continent including Belgian banks. We integrated TinkLink (their iOS SDK), wired up the OAuth callback to staysteady://tink-callback, built a Supabase edge function (tink-transactions) to exchange the auth code server-side so the TINK_CLIENT_SECRET never touched the iPhone. We handled the Tink API v2’s quirky unscaledValue + scale decimal format. We made the demo bank work end-to-end.

Then we hit the wall every indie EU developer hits with PSD2 aggregators: production access is gated on sales, not self-service. We requested access. We got polite responses. We followed up. We requested again. We never got the green light. Tink — like most enterprise PSD2 providers — is built for banks, fintech scale-ups, and corporates with revenue projections. Not a two-person indie team in Belgium.

We deprioritized Tink and started looking for a self-service alternative.

Attempt #2: Yaxi Routex (the indie-friendly option)

Yaxi GmbH in Nürnberg runs a smaller EU PSD2 gateway with self-service onboarding. Their contact, Christopher Schramm, was responsive and human — refreshing after months of Tink silence. We rebuilt our bank-sync architecture around a BankSyncProviding protocol so the orchestrator was provider-agnostic, then implemented YaxiBankSyncProvider on top.

The Yaxi flow was clean: bank search → credentials form → client.accounts() to discover IBANs → per-IBAN client.transactions(). SCA (Strong Customer Authentication, mandatory under PSD2) went through ASWebAuthenticationSession with a staysteady://yaxi-callback redirect, and a single SCA prompt covered all the user’s accounts. We built another Supabase edge function, yaxi-ticket, to do HMAC-SHA256 JWT signing with a 10-minute TTL — secrets stayed in Supabase.

In Yaxi’s tenant we had Crelan, ING Belgium, and Deutsche Bank Belgium (test) enabled. Keytrade was “coming next week.” KBC and Argenta had no ETA. Belfius and BNP Paribas Fortis — the two biggest Belgian banks — were “long-term roadmap.” Our entire target market was waiting on someone else’s roadmap.

And then the bugs started. Crelan returned a server-side error after 2FA — correlation ID forwarded to Yaxi, never resolved. ING Belgium we couldn’t test end-to-end because we didn’t know anyone with an ING account who’d let us touch their credentials. Plumbing validated, real banks blocked.

Attempt #3: realize we were solving the wrong problem

We sat down and audited what we had after six months of bank-sync work:

  • A working AI categorizer (no banks needed)
  • A working CSV/OFX/CODA/MT940/PDF import pipeline (no banks needed)
  • A working receipt scanner using on-device Vision OCR (no banks needed)
  • Savings goals, budgets, insights, recurring detection, financial health scoring (no banks needed)
  • A bank-sync layer that worked end-to-end with one bank (Crelan, intermittently) and was blocked on partnerships, sales conversations, and other people’s roadmaps for the rest

The bank sync wasn’t a feature. It was a six-month dependency on third-party companies that didn’t see us as a priority. Meanwhile, every Belgian bank lets users export statements as CODA, MT940, or PDF. The “smart import” flow we’d built as a fallback was actually better than the API integration: faster, more reliable, with zero credentials to leak.

So in May 2026 we shipped Stay Steady 1.1.0 as a fully free, no-bank-sync app. We removed Tink. We removed Yaxi. We removed RevenueCat and the entire Pro tier that the bank sync was meant to justify. We kept everything that was genuinely ours: the on-device ML categorizer, the import pipeline, the savings tools, the insights.

The app got better.

What we learned

For other indie EU developers thinking about PSD2 integration, here’s the honest summary of our experience:

1. Production access is a moat, not a feature. Big aggregators (Tink, Plaid, Saltedge) gate production access on commercial conversations. If your business model doesn’t justify a six-figure ACV in their pipeline, you’ll get polite emails and no token. Plan for this from day one.

2. Self-service aggregators exist but have spotty coverage. Yaxi, Klippa, Nordigen/GoCardless — they’ll onboard you faster, but their bank coverage in any given country is the union of “what their other customers needed.” If your country’s top two banks aren’t on the list, you’re stuck.

3. Every bank’s PSD2 implementation is different. SCA flows vary. Token TTLs vary. Field shapes vary. Even within “PSD2 compliant” there’s a long tail of carve-outs and quirks per bank.

4. File-based import is underrated. CSV/PDF/CODA/MT940/OFX export is universal. The user is in control of what gets imported. There are no credentials to leak, no OAuth flows to break, no production-access gates. On the iOS side we used Vision OCR for PDFs and rolled our own column auto-detection for CSVs. The user experience is one extra click in their bank’s online portal — and that’s it.

5. Your differentiator probably isn’t the bank API. Ours was supposed to be “Belgian-bank PSD2 sync.” Our actual differentiator turned out to be on-device ML, privacy-first architecture, and trilingual UX. The PSD2 layer was a feature we wanted to want. Users wanted the budgeting workflow.

Where Stay Steady is today

Stay Steady on iOS is now free forever, no subscription, no bank connection, all data on-device. We’re on App Store version 1.1.0 with 1.1.1 in review at the time of writing. We’ve shipped the same approach to Android — that’s a separate story.

If you’ve been wrestling with PSD2 integration on iOS or Android and want to compare notes, we’d love to hear from you: apps@dataconsultingservices.net.

Sometimes the most useful thing you can ship is the thing you stopped building.