Mewzo · June 2021
First time handling other people's money
A marketplace app with full Paystack checkout — the project where payment integration stopped being theoretical.
- Role
- Sole developer
- Team
- Solo
- Timeline
- June 2021
The problem
A marketplace is only a marketplace once money can move through it. Everything else — listings, search, profiles — is a catalogue until checkout works, and checkout is the one part where being approximately right is the same as being wrong.
Constraints
- Real payments, so failure states matter more than the happy path
- Payment provider APIs that assume a server you may not have
- Mobile network conditions where a request can succeed while the response never arrives
Approach
Checkout was built against Paystack's API with the failure cases treated as the primary design problem rather than an afterthought — what the app does when a payment succeeds but the confirmation is lost, when the user backgrounds the app mid-flow, and when a retry might double-charge.
What I rejected, and why
Treating a successful HTTP response as the source of truth
The response is the least reliable part of the flow on mobile data. The provider's record of the transaction is the truth; the app's job is to reconcile with it.
The hard part
Not double-charging anyone. On a flaky connection, an app can genuinely not know whether a payment went through, and the naive reaction — let the user tap again — is how people get charged twice. Making the flow idempotent, so that a retry reconciles against the transaction that may already exist rather than creating a new one, was the lesson that has carried into every payments integration since.
What I'd do differently
Payments taught me to design for the ambiguous state first. In most software, an unclear result is an inconvenience; in payments it's someone's money. That instinct — assume the response is lost, make the retry safe — is the single most transferable thing I've learned.
Stack
- FlutterFlow
- Firebase
- Paystack
- Payments
- REST APIs