In a two-sided physical service marketplace, trust breaks down at the exact moment money is supposed to change hands. Customers do not want to transfer cash to a technician before the job has even started. Artisans do not want to buy materials and travel across Lagos traffic only to hear 'I will transfer it later' after the work is done.
While building the booking and financial architecture for our verified artisan platform in React, Vite and TanStack, my goal was to eliminate that standoff completely. The solution was a strict, state-driven Paystack escrow checkout paired with a dual-confirmation release ledger and automated artisan wallets.
When Does the Customer Actually Fund the Job?
A common mistake in marketplace checkout design is asking for payment too early—before scope is agreed—or too late. In our architecture, the customer funds the job at Step 3: immediately after price agreement, once the job transitions to status: 'accepted'.
- 1. Discovery & Request: The customer searches artisans by trade or location on the map, submits photos, schedule and an estimated budget (₦), creating the job in status: 'requested'.
- 2. Quotation & Negotiation: The artisan reviews the brief and either accepts the customer's budget directly or submits an itemized Quotation with estimated completion time. Once both parties agree, the job moves to status: 'accepted'.
- 3. Escrow Funding (Paystack): Only when status === 'accepted' does the 'Payment & Escrow' card unlock on the job screen with the 'Pay into Escrow' trigger.
- 4. Locked in Caste Bank Escrow: The customer pays via Paystack (Card, Bank Transfer, or USSD). The artisan does NOT receive the money yet—instead, they get a verified system notification that funds are locked in escrow and it is safe to travel.
"Escrow isn't just a payment button. It is a state contract: the customer knows their money cannot vanish, and the artisan knows the money actually exists."
Live Execution and the Dual-Confirmation Sign-Off
Once the Paystack transaction is verified and locked in escrow, the physical execution phase unlocks. The artisan taps 'I am on my way' (status: 'en_route'), activating live GPS route tracking, followed by 'arrived' and 'in_progress'.
When the physical work is finished, we do not release funds on a single click from one side. We enforce a dual completion sign-off:
- First, the artisan marks the job as completed from their mobile view.
- Second, the customer inspects the physical work in person and taps 'The work is done' (POST /jobs/{id}/mark-done/).
- Only when both independent sign-offs are recorded does the backend ledger release the locked escrow balance directly into the Artisan's Caste Wallet, ready for immediate withdrawal to their Nigerian bank account.
Designing for the Unhappy Path: Instant Escrow Freezes
Happy-path payment code is easy; production fintech lives or dies by how it handles conflict. If an artisan fails to show up, damages property, or leaves a job half-finished, either party can trigger 'Raise a dispute' directly from the active job screen.
The moment a dispute is raised, the escrow state machine freezes the locked funds so no automatic payout can fire. The job is routed into the Platform Admin dispute queue alongside the in-app chat transcript, timestamps, quotation terms, and uploaded photo evidence—allowing operations staff to issue a full refund, partial split, or artisan release based on verifiable proof.