Fintech Engineering Case Study

Everytransfer,ontherightinvoice.

PaidUp gives every invoice its own bank account, so a Nigerian SME never matches a transfer by hand again. Built on Nomba virtual accounts, running in production, proven with real money.

My RoleSolo Full-Stack Engineer & Product Designer
ContextNomba × DevCareer Hackathon 2026 (Cresio Labs)
StackNext.js 14, TypeScript, MongoDB, Nomba API
Launch the live appRead the source
Live on production Nomba rails
The PaidUp landing page: Every transfer, on the right invoice.

The problem

Nigerian SMEs get paid by bank transfer, and a bank transfer arrives with a narration the customer types themselves — or does not. The business ends up with a statement full of credits and no way to tell which invoice each one settles. So someone sits down at midnight with a spreadsheet and matches them by hand, every night, forever.

“Payment, no invoice ref”

— the narration on a real transfer, and the whole reason this exists

The insight

Stop asking the customer for a reference. The account number is the reference.

Every invoice gets its own virtual account. The customer just sends money to a number — the thing they already know how to do — and the destination itself carries the identity of the invoice. Matching stops being a guess and becomes a lookup.

How money finds its invoice

01

Provision

An invoice is created and PaidUp mints a dedicated Nomba virtual account that belongs to that invoice alone.

02

Customer pays

They transfer to that account number from any Nigerian bank app — no portal, no login, no reference to type.

03

Webhook

Nomba fires payment_success. The signature is verified, the event deduped, and the money matched on its virtual-account reference.

04

Reconcile

The engine marks the invoice paid, partial, overpaid or unmatched — live, with a refundable surplus where one exists.

Treating money as a correctness problem

A reconciliation engine is only worth as much as its worst failure mode. The interesting work here was not the happy path — it was making sure a replayed webhook, a dropped event, a clawback or a forged signature could not corrupt the ledger.

Webhook authenticity

HMAC-SHA256 over Nomba's nine-field colon-joined string — not an HMAC of the raw body. The implementation reproduces the documented test vector exactly, compares in constant time, rejects events older than ±5 minutes, and fails closed in production rather than silently accepting unsigned money.

A ledger that cannot double-credit

Every money mutation — invoice, feed event, dedupe claim, audit entry — commits all-or-nothing in one MongoDB transaction. Replays collide with a unique index on the transaction id, so a webhook retry racing itself can never credit twice.

Never trusting the webhook alone

A reconciliation backstop requeries the credits Nomba actually recorded and re-runs them through the same dedupe-and-reconcile path. It is idempotent and safe to run at any time, so a webhook that never arrived repairs itself instead of quietly losing money.

Reversals as first-class events

A payment reversal un-reconciles: the clawed-back amount is subtracted and the status re-derived from what is actually left. Reversing an already-reversed payment is a no-op, so the ledger survives duplicate clawbacks.

Tamper-evident audit trail

Each money event chains a SHA-256 hash over the entry before it. Verifying the chain re-checks every link back to genesis — the difference between an audit log and an audit log you can prove was not edited.

Multi-tenant auth, fail-closed

Self-serve signup with scrypt password hashing, stateless HMAC-signed session cookies that are revocable via a token version, middleware that denies by default, and tenant isolation enforced server-side on every route — the webhook being the one exception, because it authenticates with its own HMAC.

AI that is never in the money path

Three features lean on a language model: a resolver that suggests which invoice an unmatched transfer belongs to, plain-English recommended actions for each anomaly flag, and a written brief over the whole ledger. Each one is grounded — the model only ever sees computed figures and can only pick a real, still-open invoice — so it cannot invent money, and it only ever suggests. A human still confirms.

The part I care about is the seam. The AI client returns null on a missing key, an HTTP error, a bad status, an eight-second timeout or unparseable output — and every caller falls back to its deterministic engine. A rate-limited API key degrades the product; it never breaks it. Because that seam is injectable, the fallbacks are unit-tested offline with no network and no key at all.

Proven with real money

Sandbox virtual accounts are not reachable from real banks, so the only honest test was production. On 4 July 2026 I sent real bank transfers from a live OPay account into minted Nomba virtual accounts, watched the signed webhooks arrive and reconcile as paid, partial and overpaid, and settled a real ₦100 surplus refund back out over Nomba’s transfer rails. The sub-account balance tied out to the naira.

147unit tests over the reconcile, HMAC and ledger core
1:1virtual account minted per invoice — the reference is the account
₦100real surplus refund settled on production rails
0invoices matched by hand

Designing against the dashboard default

Fintech dashboards all look the same: dark chrome, neon chart, cold. PaidUp goes the other way. The visual system is called “The Ledger” — editorial financial print, warm paper and cream, ink black, with emerald reserved almost entirely for money that has actually landed.

Fraunces sets the display type, Hanken Grotesk carries the body, and every figure on screen is set in JetBrains Mono so amounts and account numbers align down the column and stay scannable. It reads like something a business would trust with its books rather than a crypto terminal.

Walkthrough

Captured from the live production app. Tap any frame to enlarge.

Landing — the thesis in one line
Landing — the thesis in one line
The problem: “Payment, no invoice ref”
The problem: “Payment, no invoice ref”
How money finds its invoice — four steps
How money finds its invoice — four steps
Live collections — money landing and reconciling itself
Live collections — money landing and reconciling itself
Invoice workspace — per-invoice virtual accounts, flags, statuses
Invoice workspace — per-invoice virtual accounts, flags, statuses
Payouts to any Nigerian bank, with a write-ahead reserve
Payouts to any Nigerian bank, with a write-ahead reserve
Printable, audit-grade ledger report
Printable, audit-grade ledger report

The same engine, on the phone it actually gets used on

Landing on mobile
Landing on mobile
Invoice workspace on mobile
Invoice workspace on mobile
Available for hire

Let's buildsomethinglegendary.

Have a vision in mind? I'm here to translate your ideas into cutting-edge digital reality. Let's talk about your next big move.

Start a Project