All notes

How Money Transfer Apps (e.g. Western Union) Actually Move Your Money

When you tap 'Send $100', your money doesn't magically travel across the internet. Here's what actually happens behind the scenes.

6 min read

When you press "Send $100" on a money transfer app, many people imagine that $100 instantly moves from one bank account to another.

That's not what actually happens.

In most cases, what moves first is information, not money.

The actual settlement between banks may happen minutes or even hours later.

Let's understand the journey.

Step 1: User Initiates Transfer

The mobile application sends a request to the backend.

POST /transfer
 
{
  "sender":"John",
  "receiver":"Alex",
  "amount":100,
  "currency":"USD"
}

This request first reaches an API Gateway, which authenticates the user before forwarding it to the Transfer Service.

Mobile App
      |
API Gateway
      |
Transfer Service

Step 2: Validation

Before moving any money, several checks happen.

If any validation fails, the transfer is rejected immediately.

Step 3: Create a Transaction

The system now creates a transaction.

Transfer transfer = new Transfer(
    UUID.randomUUID(),
    sender,
    receiver,
    amount,
    Status.PENDING
);
 
transferRepository.save(transfer);

Notice that the transaction is PENDING.

No money has actually moved yet.

This allows the system to recover safely if something fails later.

Step 4: Debit the Sender

The sender's balance is reduced.

This operation is usually wrapped inside a database transaction.

@Transactional
public void debit(Account account,double amount){
 
    if(account.getBalance()<amount){
        throw new InsufficientFundsException();
    }
 
    account.setBalance(
        account.getBalance()-amount
    );
}

Using @Transactional ensures that either everything succeeds or everything rolls back.

Partial money transfers are unacceptable.

Step 5: Publish an Event

Instead of immediately notifying every downstream system, modern applications publish an event.

MoneyDebited Event

The event is pushed to Kafka or RabbitMQ.

Transfer Service
 
        |
 
      Kafka
 
   /      |      \
 
Ledger  Notification  Audit

Now different services can process the transaction independently.

This keeps services loosely coupled.

Step 6: Settlement

This is where most people get confused.

The receiving bank doesn't instantly receive physical money.

Instead, financial institutions maintain settlement accounts and periodically reconcile transactions.

Sender Bank
      ↓
Money Transfer Platform
      ↓
Payment Network (SWIFT / ACH / SEPA / RTP / UPI, etc.)
      ↓
Receiver Bank
      ↓
Receiver Account

From the user's perspective, the receiver gets paid (confused how? Skip to Step 7).

Behind the scenes, banks later settle the net balances between themselves through established financial networks.

This separation between customer experience and interbank settlement is one reason large payment systems can scale efficiently.

Step 7: How Does the Money Reach the Receiver's Bank?

At this point, our platform has successfully processed the transfer.

But here's an important question.

If John's account was debited in our system, how does Seth's actual bank account receive the money?

The answer is simple.

Our database never updates the bank's database directly.

Banks are independent institutions with their own infrastructure.

Instead, we send a payment instruction through a financial payment network.

John
 
      |
 
Money Transfer Platform
 
      |
 
Payment Network
(SWIFT / ACH / SEPA / UPI / RTP)
 
      |
 
Receiver's Bank
 
      |
 
Seth's Bank Account

The payment instruction contains information like:

{
    "sender":"John",
    "receiver":"Seth",
    "receiverBank":"ABC Bank",
    "amount":100,
    "currency":"USD"
}

The receiver's bank validates the instruction and credits Seth's account.

Only the receiver's bank can update Seth's balance.

UPDATE accounts
SET balance = balance + 100
WHERE account_id = 'Seth';

This update happens inside the bank's own systems, not ours.

But Where Does The Actual Money Come From?

Another common misconception is that $100 is instantly transferred from one bank to another.

In reality, banks maintain settlement accounts with each other or with central banks.

Imagine these transfers happen throughout the day.

John  -> Seth     $100
 
Alice -> Bob      $200
 
Mike  -> Emma      $50

Instead of moving money after every transaction, the payment network keeps track of all obligations.

At the end of a settlement cycle, only the net difference is transferred.

Bank A owes Bank B
 
$18,450

Only this final amount is settled between the banks.

This makes payment systems significantly faster and more efficient.

How Does The Platform Know The Transfer Succeeded?

After crediting Seth's account, the receiving bank sends a response.

POST /payment-status
 
{
    "transactionId":"TXN12345",
    "status":"SUCCESS"
}

or

{
    "transactionId":"TXN12345",
    "status":"FAILED"
}

Our platform updates the transaction accordingly.

transfer.setStatus(Status.SUCCESS);
transferRepository.save(transfer);

If the transfer fails, compensation logic or a refund workflow is triggered depending on the business rules.

Why Event Driven Architecture Helps Here

Notice something interesting.

Our Transfer Service doesn't wait for the receiving bank to finish everything.

Instead, it publishes an event.

MoneyDebited
 
        |
 
     Kafka
 
        |
 
Settlement Service
 
        |
 
Payment Network
 
        |
 
Receiver Bank

This allows the user to immediately see:

"Your transfer is being processed."

instead of waiting several seconds for multiple external systems to respond.

This asynchronous architecture is one of the reasons modern payment platforms can process millions of transfers every day while remaining responsive.

Handling Millions of Requests

Imagine thousands of users sending money every second.

Creating a new Java thread for every request would quickly exhaust system resources.

Instead, applications use thread pools.

ExecutorService executor =
        Executors.newFixedThreadPool(200);
 
executor.submit(() ->
        transferService.transfer(request));

Worker threads are reused, allowing the system to process a massive number of concurrent requests efficiently.

Preventing Duplicate Transfers

Suppose a user's internet connection drops after clicking Send.

They press the button again.

Without protection, the backend might process the payment twice.

Modern payment systems use Idempotency Keys.

Idempotency-Key:
4a12b6d9-f51d

If the same request arrives again with the same key, the server simply returns the previous response instead of processing the transfer again.

This prevents accidental duplicate payments.

Why Event Driven Architecture?

Payment systems involve many independent tasks.

Doing all of these synchronously would make transfers slow.

Instead, only the critical path executes immediately.

Everything else happens asynchronously using events.

This improves scalability while keeping the user experience fast.

Technologies Commonly Used

Final Thoughts

At first glance, sending money looks like a simple API call.

In reality, every transfer passes through multiple stages involving validation, transactions, messaging systems, fraud detection, notifications, and settlement between financial institutions.

The money itself doesn't instantly fly across the internet. What moves first is trusted information, while reliable distributed systems ensure that every transaction is processed exactly once, remains consistent, and eventually reaches its destination safely.