Payment systems
A marketplace with escrow, built end to end
An auto-parts marketplace in Kenya with escrow built into the middle of it, not bolted to the side.
- Our role
- Engineer on the product team — backend and front-end
- Built with
- Next.js · Express · MongoDB · M-Pesa · Delivery APIs
- Where it got to
- Live, in production
- Open it
- dalemarketplace.com

The idea
A place to buy car parts online in Kenya. Sellers list what they have, buyers find the part that fits their car and pay for it.
What it actually needed
The reason a marketplace like this does not already exist everywhere is not software. It is that neither side will go first. A buyer will not send money to a stranger they cannot find again, and a seller will not put a gearbox on a bus for someone who might never pay. So the product being asked for was a catalogue, and the product that had to be built was a way to make a stranger's promise safe.
What got built
- A storefront that knows your car
- Parts are organised by make, model and year, and matched against the vehicle a buyer has saved. A listing that will not fit their car is never shown to them at all.
- Checkout that holds the money
- Buyers pay from their phone by mobile money. The payment does not go to the seller. It is held, and the buyer can see that it is held.
- Delivery, quoted before you commit
- A real delivery price appears at checkout, not after it, and the rider is trackable on a map afterwards. A second courier was added beside the first, so an address one cannot reach can still be served.
- A business for the seller, not just a listing page
- Sellers are verified before they can sell, then manage their stock, answer buyers' part requests with offers, dispatch deliveries, watch a balance build up as orders complete, and withdraw against it.
- An operations console
- Staff approve sellers, mediate disputes, release or refund a held payment, approve withdrawals, and, when someone reports a problem nobody else can reproduce, see the platform exactly as that user sees it.
- Money that reports on itself
- Sales reporting across the platform, and a service fee shown to the buyer as its own line at checkout instead of folded into a total and discovered later.
The decisions that shaped it
Hold the money instead of forwarding it
This is the entire product, and it is expensive. Holding funds means the platform now owns a state that belongs to neither party, and the buyer, seller and admin screens all have to agree about which state that is at every moment. Forwarding payments straight through would have been a fortnight's work and would have produced a listings site nobody would risk using.
Show the buyer's fee as its own line
Rolling a service fee into a displayed total is easier, converts better in the short term, and produces a customer who feels quietly overcharged the first time they do the arithmetic. On a platform whose only asset is trust, that trade is not worth making.
Change the checkout contract additively, never in place
The storefront and the API deploy independently, which is good for shipping speed and a genuine hazard: for a few minutes at a time the two halves of the system can be running different versions of the same agreement. So anything checkout depends on is added alongside and retired later, never swapped. It is unglamorous, and it is the difference between a deploy being a non-event and a deploy being an incident for whoever happens to be paying at that moment.
In production
Live, with buyers, sellers and staff using it. Ten months of continuous work alongside other engineers, and still shipping.
What this is worth
A system that was already taking money kept taking it while it changed. Escrow, mobile-money payouts, a second delivery provider and three separate products, added over ten months.
Dale is a marketplace for car parts in Kenya, and the reason it exists is trust. Buying an alternator from a stranger online means sending money to someone you cannot find again. So the money does not go to the seller. It goes into escrow: Dale holds it, the seller ships, the buyer confirms the part arrived and is right, and only then does it become the seller's.
That single sentence is most of the engineering. Everything else on the platform exists to make it work.
Three products wearing one name
A marketplace is not one application. It is at least three, and they have to agree with each other at every moment.
Buyers search a catalogue organised by vehicle: make, model, year, category. Parts are matched against a saved car, so a listing that will not fit is never shown. They pay by mobile money, get a live delivery quote at checkout, and track the rider on a map afterwards.
Sellers are onboarded by hand and verified before they can list: business permit, incorporation certificate, tax registration, proof of address. They manage stock, respond to buyers' part requests with offers, dispatch deliveries, watch their balance accrue as orders complete, and request payouts against it.
Admins approve sellers, mediate disputes, release or refund escrow, approve withdrawals, and, when a user reports something they cannot reproduce, view the platform as that user, with a banner making it obvious they are doing so.
What we built into it
Working alongside the rest of the team on a codebase that was already running: the escrow lifecycle and the payout system behind it, including both consumer and business mobile-money disbursement. A second delivery provider added beside the first, with coverage routing to decide which one can serve an address, parcel calculations from product weights, and a geocoder that stopped refusing addresses outside the country it assumed.
Also: the sales reporting engine, the fitment matching that pairs parts to a saved vehicle, catalogue visibility rules, cart and stock behaviour, and the buyer-facing service fee shown as its own line so nobody discovers it at the end.
Two services, one checkout
So changes to anything checkout depends on are made additively and retired later, never swapped. Whichever side deploys first, a buyer mid-purchase does not get stranded. It is unglamorous and it is the difference between a deploy being a non-event and a deploy being an incident.
