Contents

When you have a product where your users fall into these two buckets — buyers or sellers — you have a marketplace.

Building a marketplace means, as a developer, you’ll have to think about to handle money when buyers pay sellers for goods/services. At first, it may seem like a simple accounting problem, but marketplaces have very specific money movement needs that makes a generic debit-minus, credit-plus approach insufficient.

You’ll want your system to track:

  • Who owns what and at what point in time
  • How money flows during deposits, purchases, withdrawals, escrow, refunds, chargebacks, etc.
  • Event-level accuracy per transaction, rather than just end of day balances.
  • Sync between your records and your payment processors, application logic, third-party analytics tools, etc.

So how do you build one?

Setting up your infrastructure

First things first, start with a ledger.

Before you start to think about money workflows, payment logic, etc., you need to think about the infrastructure that’ll power them. For this guide, we’ll use our open-source ledger, Blnk Core, as our starting point.

```

--CODE language-bash--

git clone https://docs.blnkfinance.com && cd blnk

```

‍

As a marketplace, there are always three first-class entities:

  • Buyer: Users making a purchase
  • Seller: Users offering goods & services in exchange for money
  • Organization (you): The platform making it all possible.

In your ledger (Blnk), you start by replicating this structure via ledger folders. Here, we’ll create two ledgers:

  • General Ledger (default): For the organization (you).
  • Customers Ledger: For the buyers and sellers. A customer can either be a buyer, seller, or both.

To create a ledger:

```

--CODE language-bash--

curl -X POST http://localhost:5001/ledgers \
   -H 'Content-Type: application/json' \
    -H 'X-blnk-key: YOUR_API_KEY' \
    -d '{
        "name": "Customers Ledger"
    }'

```

‍

You could apply this ledger design to larger, more complex products, e.g. a global marketplace like Fiverr could create customer ledgers per currency/country. A product like Fiverr could have Customers USD Ledger, Customers GBP Ledger, and Customers JPY Ledger for customers transacting in USD, GBP, and JPY respectively.

Tracking money owned with balances

Next, we need to solve for “who owns what?”

In real life, funds are not truly stored per user per vault somewhere. They’re typically pooled together into a kind of operational fund. Ownership is represented digitally, and this is where errors creep up on most developers.

So using our created ledger, we’ll create a balance for each user.

```

--CODE language-bash--

curl -X POST http://localhost:5001/balances \
-H 'Content-Type: application/json' \
-H 'X-blnk-key: YOUR_API_KEY' \
-d '{
"currency": "USD",
"ledger_id": "customers-ledger-id"
}'

```

‍

Here’s what happens:

  • A balance is created for the user with a balance_id.
  • This balance is grouped as being a part of the customers ledger. This means when you see a balance with the customers ledger id, it tells you that this balance belongs to a customer.
  • The balance is assigned a currency (by you). You could give it any currency you want.
Your balances table with newly created balances | Blnk Cloud

Now, you have your ledger all set up and ready for transactions.

Don’t worry about your organization balances yet, we’ll come back to that when we start recording transactions.

Implementing transaction workflows

In Blnk, transactions happen between balances. When User A sends money to User B, what happens in the ledger is a transaction from User A’s balance to User B’s balance.

However, transactions are not always that simple. You have a lot of things you want to solve for per transaction and your ledger needs to be able to work with it.

For this guide, we'll work on 3 common workflows:

  • Deposits
  • Purchases between a buyer and a seller
  • Withdrawals & settlements

Deposits

In some marketplaces, buyers are given a wallet to fund before they are able to buy while in other case, buyers directly pay from their card or bank account.

For this example, we’ll select the former scenario.

Simplified deposit money movement map for most marketplaces

This workflow is straightforward. All you need to do is add money to buyer’s balance in our ledger. However, Blnk is double-entry, i.e. if you’re adding money somewhere, it needs to be deducted elsewhere.

In this case, the “deduction” is happening from outside our marketplace. To represent this, we’ll create an internal balance (@World) belonging to our organization to represent money coming in from outside.

```

--CODE language-bash--

curl -X POST http://localhost:5001/transactions \
-H 'Content-Type: application/json' \
-H 'X-blnk-key: YOUR_API_KEY' \
-d '{
"amount": 1200.00,
"precision": 100,
"currency": "USD",
"source": "@World",
"destination": "buyer-balance-id",
"reference": "unique-reference",
"description": "Wallet deposit",
"allow_overdraft": true
}'

```

‍

Here’s what happens:

  • The buyer’s balance increases by the amount, e.g. $1,200.00 USD.
  • You have a clear idea of where that amount came from. You can use metadata to add even more context like bank name, payment type, external reference, etc.
User (buyer) balance reflecting the deposit in your ledger | Blnk Cloud

Purchases

Purchases could be prepaid, postpaid, or escrow, depending on your business model. For most products, it is usually a transaction from the buyer (source) to the seller (destination).

For an escrow model, here's a simplified workflow:

  • Buyer initiates payment.
  • Platform holds the transaction until purchase conditions are met (e.g. buyer confirms receipt).
  • Seller sees the incoming payment, but can’t access it yet. Buyer can’t spend any funds held in escrow either.

We’ll create another transaction, but we’ll specify that we want it to be inflight. This tells the ledger that a transaction has happened but it shouldn’t be finalized yet.

```

--CODE language-bash--

curl -X POST http://localhost:5001/transactions \
-H 'Content-Type: application/json' \
-H 'X-blnk-key: YOUR_API_KEY' \
-d '{
"amount": 500.00,
"precision": 100,
"currency": "USD",
"source": "buyer-balance-id",
"destination": "seller-balance-id",
"reference": "unique-reference",
"description": "Payment for design proposal",
"inflight": true
}'

```

‍

Here’s what happens:

  • You can see the total balance being held inflight for the buyer and seller.
  • You can see the inflight state of the transaction in your transactions table, and you can show that in your application.

Let’s assume the conditions for finalizing the transaction are:

  • Seller confirms delivery.
  • Buyer confirms receipt and all is good to go.

Your code may look something like this:

```

--CODE language-javascript--

async function finalizePurchase(transaction_id, buyer_confirmed, seller_confirmed) {
if (buyer_confirmed && seller_confirmed) {
// Commit transaction in Blnk
} else {
// Void transaction in Blnk
}
}

```

‍

This logic says that:

  • Commit the transaction only after both buyer and seller confirm that everything is complete. This ensures you only settle the seller when the buyer confirms receipt of the package.
  • If confirmation is missing from either party or a dispute is raised, void the transaction and release the funds back to the buyer.

To commit the funds in your ledger:

```

--CODE language-bash--

curl -X PUT http://localhost:5001/transactions/inflight/{transaction_id} \
-H 'Content-Type: application/json' \
-H 'X-blnk-key: YOUR_API_KEY' \
-d '{
"status": "commit"
}'

```

‍

Applied (finalized) transaction after commit action | Blnk Cloud

What happens:

  • The funds held in inflight is finally deducted from the buyer and added to the seller’s balance.
  • Since it’s impossible for the buyer to access those held funds, you can always be sure that the transaction will always go through. Blnk handles insufficient fund checks for you.
Seller balance after commit, amount now available for withdrawal | Blnk Cloud

Settlements

Next, users need to be able to withdraw their money. Some products do this automatically once the seller gets paid, while others allow sellers to hold money in their wallet and withdraw any time they want to.

Simplified withdrawals/settlement money movement map for marketplace

The implementation for both workflows are the same. You simply reverse the deposits money movement. This time, money is deducted from the user balance and added to “@World.”

```

--CODE language-bash--

curl -X POST http://localhost:5001/transactions \
-H 'Content-Type: application/json' \
-H 'X-blnk-key: YOUR_API_KEY' \
-d '{
"amount": 400.00,
"precision": 100,
"currency": "USD",
"source": "seller-balance-id",
"destination": "@World",
"reference": "unique-reference",
"description": "Settlement/withdrawals",
"inflight": true
}'

```

‍

Remember, “@World” is how we represent “outside” in our ledger, i.e. for withdrawals, we’re sending money outside of our product.

What else can you build?

Like you’ve seen, your money movement cannot be solved by just setting up simple accounting tables in your database. If you hope to grow your business or add creative features that affect how users pay in your app, an expert ledger is a no-brainer.

So what else can your marketplace ledger (Blnk) have:

  • Overdrafts: Offer and manage instant settlements to sellers based on their pending receivables.
  • Refunds: Safely handle reversals when requested with full auditability.
  • Split payments and fees: Most marketplace fees charge a fee per purchase. Track your organization’s take with full transparency to the user.
  • Delayed settlements and payouts: Track third-party payment processing in your ledger, e.g. Use inflight to model ACH settlements and only commit once the payout is confirmed.

Get started with Blnk to try it out yourself.

‍