How to Build a Solid FinTech Architecture

Cover Image for How to Build a Solid FinTech Architecture
Gagan Bodduluru
Gagan Bodduluru

I recently spent a lot of time reviewing how real-world financial systems are built. When you are dealing with people's money, the stakes are incredibly high. The system has to be completely secure against attacks, fast enough to handle millions of requests, and above all, it can never accidentally process the same transaction twice.

I thought it would be helpful to share a high-level blueprint of how these systems are put together. Instead of just listing random components, let's walk through the architecture layer by layer, starting from the outside where the user connects, all the way down to the core database.


Layer 1: The Front Door (Gateways & BFFs)

Before a request ever touches our core financial logic, it has to get past the front door. In modern systems, we split this responsibility into two specific layers:

The API Gateway (The Bouncer)

This sits at the very edge of our network. It doesn't care about what data is in the request; its only job is protection. It blocks hackers, stops DDoS attacks, and routes the traffic to the right place inside our network.

The BFF Layer (Backend for Frontend)

Once past the bouncer, the request meets a "BFF" (Backend for Frontend). Think of it as a personal assistant tailored for a specific app. The mobile app has its own BFF, and the website has a different BFF. The BFF gathers data from all our internal services, cuts out the extra stuff the app doesn't need, and sends back one clean, simple response to the user.


Layer 2: Identity & Security (Authentication)

Now that the request is inside, how do we securely know who is making it? Keeping users logged in safely works differently depending on how they connect.

Authentication Flow

Mobile Apps

Mobile apps are relatively safe, so they can hold onto a raw security token (a JWT). When the mobile app makes a request, it hands the token to the API Gateway. The Gateway checks the signature, and if it's valid, lets the request through.

Web Browsers

Web browsers are dangerous places to store raw security tokens because malicious scripts can easily steal them. To fix this, we use the Token Handler Pattern:

  1. When you log in on the web, your browser only gets a standard, encrypted cookie that it can't read directly.
  2. When your browser makes a request, our Web BFF intercepts that cookie.
  3. The BFF looks up your real security token in a secure database, attaches it to the request, and forwards it to the rest of our internal services.

Because of this trick, the vulnerable web browser never actually gets to touch the real security token!


Layer 3: The Core Engine (Ingestion & Processing)

While user-facing requests (like you checking your balance on your phone) are handled by the BFF, heavy financial transactions (like a partner bank sending us 10,000 deposits at once) take a different path. These high-volume writes skip the BFF and go straight from the API Gateway to our Ingestion Service.

The Goal: Safely receive the transaction, reply to the bank instantly so their system doesn't freeze, and make absolutely sure we never process a duplicate deposit.

Ingestion Architecture
  • Ingestion Service: A very lightweight service. It takes the transaction, drops it into Kafka (our queue), and immediately tells the user "Got it!". It doesn't even try to write to the main database yet.
  • Kafka (The Buffer): This acts like a giant shock absorber. If a million requests come in at once, Kafka holds onto them so our database doesn't crash.
  • Processor Service: These are background workers that read messages from Kafka at a safe pace, do the complex math, and write the final result to the database.

How do we stop duplicates? In finance, you can never rely on a fast cache to stop duplicate transactions. Instead, we use a feature in our main database called a "Unique Constraint." If the exact same transaction ID tries to save twice, the database strictly rejects it.


Layer 4: Speed vs. Safety (Caching)

While we can't use caches to stop duplicates, we do need them to keep the system fast. The strict rule is: Never use a cache to store someone's actual account balance. Caches are only used to relieve pressure on the main database.

What it isWhere we put itWhy we use it
Spam FilterRedis (At the front door)We store recent transaction IDs for 24 hours. If we see the same ID again, we just drop it instantly before it even hits our queue.
Settings & ConfigsIn-Memory (Inside the app)Things that rarely change, like supported currencies. This saves us from asking the database the same question thousands of times a second.
Viewing BalancesRedis (Before the API)When you check your balance on your phone, we read it from a fast cache rather than the main database. We just update the cache quietly in the background whenever you spend money.

Layer 5: Talking to the Outside World (Webhooks)

Finally, how do we communicate securely with other banks and partners? Instead of having them constantly ask us, "Do you have new data?", we just push the data to them using Webhooks.

Outbound Webhook Delivery

When we need to send data out, we use a separate background worker to handle the delivery so our main servers don't get tied up.

If a partner's server is down, we don't just give up. We use a strategy called Exponential Backoff. We try to send the webhook again in 1 minute, then 5 minutes, then 15 minutes, up to 24 hours. We also use strict timeouts so our workers don't get stuck waiting forever if the partner's server completely freezes.

By structuring the system into these strict layers, we ensure that the core database is always protected, the user experience remains lightning-fast, and the entire platform stays completely secure!