Work Confety
Event ticketing · iOS, Android and web
₦1.31M in tickets processed, on a platform I shipped alone.
Confety is an event-ticketing platform I founded and lead, built for the Nigerian events market. Attendees discover and book events; organisers sell tickets and verify them at the door with signed QR codes. I own the product, the codebase and the release pipeline across the App Store, Play Store and web, and wrote 387 of its 394 commits.
- Role
- Founder & Lead Developer
- Organisation
- Confety
- Period
- Jan 2026–present
- Status
- Live
- Live
- confety.app
Built with
- React Native (Expo)
- React
- Node
- Supabase (Postgres + RLS)
- Edge Functions
- Paystack
- PostHog
₦1.31M
Ticket value processed across 161 orders, Feb–Aug 2026
57.9%
Of paying buyers bought again (11 of 19)
21.9%
Of accounts converted to a paid purchase (33 of 151)
1.5%
Over-deduction on every transaction, found and corrected
The problem
Nigerian event organisers were selling tickets through bank transfers and WhatsApp threads. That works until the door, where there is no reliable way to tell a paid ticket from a screenshot of one. Organisers absorbed the losses, and attendees queued while someone scrolled a chat history looking for a payment receipt.
Confety closes that gap: a ticket that is cryptographically signed when it is sold, and verifiable in a second when it is scanned.
What I built
I founded the product and lead development end to end. That covers the React Native (Expo) apps for iOS and Android, the React web app, and the Supabase and Postgres backend behind both. Since January 2026 that has been 387 of the project's 394 commits, 106 database migrations, 15 edge functions and roughly 107,000 lines of TypeScript.
- Signed QR tickets. Every ticket carries a signature issued at purchase. Verification at the door checks the signature rather than doing a database lookup, so the scanner stays fast and keeps working when the venue's connection does not.
- Apple and Google Sign-In. Account creation is the first thing between a person and a ticket, so it had to be a single tap. Apple Sign-In was also a store requirement, not a preference.
- Gifting and private events. A ticket can be bought for someone else, and an invite link opens the event in the app when it is installed and the web app when it is not, so a shared link never dead-ends.
- Payments through Paystack, including the fee handling described below, which turned out to be where the interesting bug lived.
- The full release pipeline. App Store, Play Store and TestFlight, including review submissions, signing and ongoing maintenance. There is no one else to hand a build to.
What it has done
Queried from the production database, not estimated.
- ₦1,311,013 in ticket value processed across 161 orders, 23 February to 8 August 2026.
- 57.9% of paying buyers bought again, 11 of 19, at an average of 6.74 orders each.
- 21.9% of accounts converted to a paid purchase, 33 of 151.
- 121 tickets issued, 112 still active. 43 gifts sent to 16 people.
Decisions worth showing
Each of these is a place where the obvious implementation would have worked, and cost something later.
1. The pricing page was the spec, and the code was wrong
Confety quotes hosts a flat 7% plus ₦100. The code computed the platform's cut as its own rate, which meant three surfaces stated three different fees, and the host's total drifted outside the quoted number whenever Paystack capped or waived its charge. The effect was an over-deduction of about 1.5% on every transaction, ₦3,675 across 30 orders on ₦245,000 of gross sales.
The fix was to stop treating the platform fee as a rate at all. It is now a residual: the host fee minus whatever the processor actually took. Every pricing quirk lands on Confety's margin and never on the host's payout. The tests assert that invariant rather than the two rates, so the property that matters is the thing under test.
2. A migration avoided by reusing a derivation
Hiding a venue's exact address until someone holds a ticket needed a
coarser public label. The obvious route was a public_locality
column, a backfill across 40 existing events, and a new field for hosts to
fill in.
Instead event_public_location_label() composes the existing
event_canonical_city(), already powering Discover, with the
country parsed off the end of the address. An event resolves to
"Abuja, FCT / Nigeria" with no new column, no backfill and nothing asked of
the host, and the label agrees with Discover by construction rather than by
someone remembering to keep them in step.
3. The privacy gate lives in the service, not the screens
Checking canSeeExact at each render site would have worked
and would have leaked. fetchEventDetail overwrites venue,
address and coordinates before it returns, so the calendar export and the
session timeline were both gated without either being touched. A
per-screen approach would have missed exactly those two.
4. It fails closed
If the can_see_exact_location RPC errors, the client falls
back to hidden rather than visible. An unapplied migration produces
over-hidden events, never leaked addresses. The failure mode is
embarrassing rather than harmful, which is the correct way round.
5. The processor's real fee moves margin, never the payout
When Paystack's actual charge differs from the estimate,
apply_actual_paystack_fee adjusts Confety's side of the
ledger. Recomputing the host's net from the actual fee would have been the
natural implementation, and would have meant a host who happened to sell to
an overseas buyer quietly received less than they were quoted.