Case Study · Payments · 2023 — Present

Digopay — reliable card & mobile-money collection

End-to-end payment pipeline that stays correct under failure — safe retries, recovery points, and a consistent ledger.

Spec Sheet

Role

Full-stack engineer (lead)

Timeline

2023 — present

Status

In production

Surface

Merchant dashboard + API

Stack

Next.js · Node.js

Data

PostgreSQL · Redis

01

Problem


Merchants needed to accept both card and mobile-money payments through one integration. The hard part was not the happy path — it was failure. A request could time out after the customer was charged, webhooks could arrive late or out of order, and a naive retry could double-charge. Merchants were losing trust and spending hours manually reconciling.

02

Context & constraints


Built for the Ghanaian market, where mobile money is the dominant rail and connectivity is uneven. The system had to treat the payment processor as unreliable and the network as hostile, while still feeling instant to the merchant.

Idempotencyevery charge must be safe to retry
Eventual settlementPSPs confirm late and out of order
Auditabilityevery state change must be explainable
03

Architecture


Request path

Client

API gateway

backend

Validation

layer

Processor

card / momo

Webhook

handler

Ledger

DB update

Failure recovery & consistency

Webhook

retry

Idempotency

dedupe key

Recovery

point

Ledger

consistent

04

Implementation


Frontend

  • ·Merchant dashboard in Next.js (server components)
  • ·Payment states: optimistic → reconciled
  • ·Client-side idempotency keys + validation

Backend

  • ·Idempotent charge endpoint with dedupe keys
  • ·Webhook ingestion + signature verification
  • ·Reconciliation worker converges PSP state

APIs

  • ·POST /charges (idempotent)
  • ·POST /webhooks/psp
  • ·GET /transactions/:id
  • ·Card + mobile-money adapters
05

Key decisions


01

Idempotency keys on every charge

Network retries must never double-charge. The key makes a charge safe to repeat; the ledger stays the single source of truth.

02

Asynchronous reconciliation worker

Processors settle late and out of order. Combining webhooks with a polling worker lets state converge safely instead of trusting one signal.

03

Append-only ledger

Auditability and dispute resolution matter more than write convenience. Nothing is mutated in place — every transition is a new, explainable record.

06

Tradeoffs


Chose

·A well-bounded modular monolith

·Strong consistency on the ledger

·Boring, observable technology

Gave up

·Independent service scaling (not needed yet)

·Some raw write throughput, for correctness

·Newer, less proven tooling

07

Outcome


~0

double-charges after idempotency rollout

days → min

reconciliation time per cycle

100%

transactions traceable in the ledger