Case Study: Integrating Dwolla and Apex to Build Bank-to-Broker Rails

Case Study - Design System - Blog - 32
June 2, 2025
10 min
Bohdan Hlushko
Head of Growth
Bohdan Hlushko
The growth engine. Drives demand generation, marketing funnels, and new partnerships launch. He ensures INSART isn’t just building great products – it’s also scaling its market presence and startup portfolio.

Table of Contents

Chapter 1 — The Problem That Started It All

Every major fintech product begins with something that feels almost too simple.

In our story, the request was:

“Let our users move money from their bank account into an investment account without feeling any pain.”

No awkward forms.

No multi-day confusion about “pending transfers.”

No uncertainty about whether money has landed or whether investing is available.

Just a feeling of flow.

But behind that seemingly easy request lived two enormous ecosystems — the U.S. banking system, with its ACH rules, identity requirements, return codes and cutoff windows… and the brokerage world, with its compliance standards, account approvals, journals, settlements, and trading gates.

To build what the client imagined, we needed two powerful partners:

Dwolla, for bank account verification and ACH/RTP transfers.

Apex, for creating brokerage accounts and enabling real investing.

And between them, INSART had to build a bridge sturdy enough to handle compliance, information flow, errors, asynchronous events, and real users.

This case study is the story of that bridge.


Chapter 2 — The INSART Way of Beginning

The first thing INSART always does is slow down.

Before touching the keyboard, we gather product managers, compliance officers, engineers, and architects and ask a simple question:

“What does the user think is happening?”

Because the user doesn’t care that Dwolla calls them a “customer,” that Apex calls them an “account holder,” or that ACH transfers have return codes like R01, R02 or R29.

The user only cares whether money is moving.

We mapped the experience from their perspective:

A user:

  • signs up

  • verifies identity

  • connects a bank account

  • deposits money

  • is approved for investing

  • sees money in their brokerage account

  • starts buying and selling

But inside the platform, that single beautiful path involves dozens of state changes, validations, event notifications, retries, reconciliations and compliance decisions.

That’s where INSART’s architecture begins — by understanding that two worlds need to feel like one.


Chapter 3 — Designing the Financial Highway

We designed the system the same way one would design a highway: with lanes, guardrails, and clear direction.

The high-level architecture looked like this:

Frontend (Web/Mobile)
        |      
API Gateway
        |
   ┌──────────────────────────────┐
   |          Services            |
   |                              |
   | • Identity & Compliance      |
   | • Dwolla Funding Engine      |
   | • Wallet & Ledger            |
   | • Apex Brokerage Engine      |
   | • Event Gateway              |
   | • Orchestration Layer        |
   └──────────────────────────────┘
        |
   Dwolla API   ←→   Apex API

There is no “shared data model” between Dwolla and Apex, so INSART built an internal language — a normalized model describing:

  • a user

  • a funding source

  • a transfer

  • a brokerage account

  • a journal

  • a settlement

  • a notification

It allowed us to translate Dwolla’s world into Apex’s world and vice versa.


Chapter 4 — Dwolla: Building Trust With the Banking System

The first half of the journey lives in Dwolla’s ecosystem.

The moment a user signs up, INSART’s Identity Service creates a Dwolla Customer behind the scenes:

// dwollaCustomer.ts
export async function createDwollaCustomer(user: User) {
  return await dwollaClient.post('/customers', {
    firstName: user.firstName,
    lastName:  user.lastName,
    email:     user.email,
    type:      'personal',
    address1:  user.address1,
    city:      user.city,
    state:     user.state,
    postalCode:user.postalCode,
    dateOfBirth: user.dob,
    ssn: user.ssn4
  });
}

Dwolla responds with a URL like https://api.dwolla.com/customers/<uuid>.

We store that in the internal user profile and immediately monitor its status:

  • “verified”

  • “document”

  • “retry”

  • “suspended”

If Dwolla needs more documents, we request them.

If Dwolla flags something, we freeze funding.

Everything happens automatically.

Bank linking begins once identity is verified.

The user verifies their bank through Plaid or a similar provider.

We exchange the Plaid token for a Dwolla funding source:

// addFundingSource.ts
export async function attachBankAccount(dwollaCustomerUrl: string, processorToken: string) {
  return await dwollaClient.post(`${dwollaCustomerUrl}/funding-sources`, {
    plaidToken: processorToken
  });
}

Within seconds, the bank is connected.


Chapter 5 — Dwolla Transfers: Money On the Move

When a user chooses to deposit, say, $300, we create a Dwolla transfer:

// transferFunds.ts
export async function initiateDwollaTransfer(sourceUrl: string, destinationUrl: string, amount: string) {
  return await dwollaClient.post('/transfers', {
    _links: {
      source: { href: sourceUrl },
      destination: { href: destinationUrl }
    },
    amount: {
      currency: 'USD',
      value: amount
    }
  });
}

From here, Dwolla enters its own ecosystem:

  • ACH processing

  • settlement timing

  • potential return codes

  • cutoff windows

  • risk monitoring

INSART built a Funding Engine that listens to every Transfer Event Dwolla emits:

// dwollaWebhook.ts
router.post('/dwolla/webhook', async (req, res) => {
  const event = req.body;
  await fundingService.handleDwollaEvent(event);
  res.status(200).send('OK');
});

Inside handleDwollaEvent we interpret events like:

  • transfer_created

  • transfer_completed

  • transfer_failed

  • customer_suspended

We update our internal ledger, notify the user, and decide whether the money is now ready to be pushed toward Apex.


Chapter 6 — Apex: Turning Dollar Amounts Into Investing Power

Once money arrives on the platform, the second world begins — Apex.

Apex requires detailed investor profiles, so we built a structured onboarding flow:

// createApexAccount.ts
export async function createApexAccount(user: User) {
  const payload = {
    accountType: 'INDIVIDUAL',
    personalInfo: {
      name: user.fullName,
      address: user.fullAddress,
      ssn: user.ssn,
      dob: user.dob
    },
    disclosures: {
      employmentStatus: user.employment,
      industryAffiliation: user.industryAffiliation,
      investmentExperience: user.experience
    }
  };
  
  return await apexClient.post('/accounts', payload);
}

Once Apex approves the account, they issue an accountNumber.

From this point onward, the user has:

  • a verified Dwolla customer

  • a verified funding source

  • a funded wallet

  • a brokerage account on Apex

  • money waiting to enter that account

Which brings us to the most delicate part.


Chapter 7 — Bridging Dwolla Money Into Apex Accounts

Dwolla settles money into the platform wallet.

But money must reach the Apex account before the user can trade.

INSART built a Journal Transfer Service:

// journalTransfer.ts
export async function sendFundsToApex(brokerageAccount: string, amount: number) {
  return await apexClient.post('/journals', {
    accountNumber: brokerageAccount,
    amount: amount.toFixed(2),
    currency: 'USD'
  });
}

Before initiating a journal, our Orchestration Layer checks:

  • has the user passed all compliance checks?

  • has the Dwolla transfer fully settled?

  • has the ledger confirmed available balance?

  • is the Apex account active?

  • are there any freezes or restrictions?

Only when everything is green do we push the funds to Apex.

Once the journal is posted, Apex sends a webhook:

// apexWebhook.ts
router.post('/apex/webhook', async (req, res) => {
  await brokerageService.processApexEvent(req.body);
  res.status(200).send('OK');
});

When we receive JOURNAL_POSTED, we notify the user:

“Your funds are now available for investing.”

Because that is the moment everything becomes real.


Chapter 8 — Event-Driven Reality

In financial systems, everything meaningful happens asynchronously.

Dwolla and Apex both send event streams — dozens of messages for every user action.

INSART built a unified Event Gateway to handle both worlds:

// eventGateway.ts
export async function processEvent(event: any) {
  if (event.source === 'dwolla') {
    return fundingService.handleDwollaEvent(event);
  }
  if (event.source === 'apex') {
    return brokerageService.handleApexEvent(event);
  }
}

This is how we maintain a single truth, even though the outside world is noisy and asynchronous.

The Event Gateway keeps:

  • ledger balances updated

  • account statuses accurate

  • notifications real-time

  • compliance logs complete

  • reconciliation predictable

It is the heartbeat of the system.


Chapter 9 — Launch: When The System Met Real Users

When the first batch of users entered the platform, they experienced what we hoped they would:

  • They connected their bank.

  • Added money.

  • Opened an investment account.

  • Saw money arrive.

  • Started trading.

Not a single one realized how many conditions had been checked behind the scenes.

They never saw a Dwolla return code.

They never encountered an Apex rejection payload.

They never saw the internal ledger.

They never realized that half the operations were asynchronous.

All they felt was flow.

That’s the magic of a system designed to hide the machinery and show only the outcome.


Chapter 10 — What This Integration Meant for INSART

This project wasn’t “two integrations.”

It was building a financial highway.

Dwolla controlled where money starts.

Apex controlled where money becomes investable.

INSART controlled everything that makes the experience coherent.

We learned that building for the user means:

  • translating complexity into clarity

  • turning delays into notifications

  • turning events into state

  • turning compliance into design

  • turning multiple systems into one story

And this is exactly what INSART specializes in.


Conclusion — The Highway Is Built, and It Works

Today, the rails we built handle:

  • identity verification

  • bank linking

  • ACH transfers

  • wallet management

  • brokerage account creation

  • funds journaling

  • real-time event syncing

  • portfolio readiness

  • and eventually trading

The beauty of it?

Users don’t think about any of this.

They just trust that when they click “Deposit,” the money shows up.

And when they click “Invest,” the trade flows.

That trust — invisible, silent, earned — is the highest compliment any fintech builder can receive.

INSART built the rails that made that trust possible.

SUBSCRIBE

Whether you are a founder, investor or partner – we have something for you.

Home
Get in touch
Explore on signals.MAG