Engineering Challenges & Solutions
Designing Financial Infrastructure with External Liquidity
Since funds are stored in PSP merchant wallets rather than directly on the platform, I had to design an internal accounting structure that still provided accurate financial visibility.
I introduced:
- platform equity accounts for revenue tracking
- asset accounts representing funds held with processors
- campaign-level liability accounts
This allowed us to maintain financial correctness while operating as a payment aggregator rather than a licensed processor.
Settlement Timing & Payout Safety
Because PSP settlements occur on a T+1 basis, I introduced a rule that fundraisers can only withdraw funds 24 hours after campaign closure.
This protects liquidity, reduces payout failure risk, and aligns internal balances with processor settlement timelines.
I also implemented nightly reconciliation jobs that compare platform transactions with PSP settlement records.
Multi-Provider Payment Abstraction
One major complexity was supporting multiple payment providers without tightly coupling business logic to any single integration.
To solve this, I designed a provider contract interface requiring each integration to expose standardized methods such as:
- initiate checkout
- verify payment status
- perform payouts
- fetch balances
I also built a resolver layer that determines which provider implementation should be used at runtime. This enables failover strategies and future provider switching without rewriting core payment logic.
Canonical Bank & Payment Channel Normalization
Different PSPs expose inconsistent bank and telco identifiers. This created risks when users save payout accounts.
I solved this by introducing a canonical bank registry. Users interact only with canonical bank identities, while internal mappings translate these into provider-specific shortcodes during payout requests.
This abstraction ensures provider switching does not break user payout configurations.
Handling Missing Payment Metadata from Providers
Some providers did not return explicit payment channel information during webhook callbacks. However, payment channel selection was necessary for accurate fee computation.
I implemented provider-specific inference logic that determines the channel by comparing returned identifiers against known telco, card, and bank lists.
This ensured the platform could still compute fees correctly even when integrations were incomplete.
Building a Robust Fee Calculation Engine
I designed and implemented a flexible fee configuration engine that supports:
- percentage fees
- fixed fees
- combined percentage + fixed models
- minimum fee caps
- maximum fee caps
- aggregation of platform and PSP fees
This engine ensures deterministic fee computation across providers and improves financial transparency for donors and campaign organizers.
Database Performance & Data Access
To support campaign browsing and transaction monitoring, I implemented pagination and search using Prisma ORM.
I optimized database queries through indexing strategies and eager loading to avoid N+1 query patterns. The system is deployed on GCP in a single region to reduce latency and maintain consistency.
Security & Risk Controls
I implemented role-based access control for campaign management and payouts.
Basic fraud-risk signals such as transaction velocity monitoring were introduced to flag suspicious activity patterns.
The platform uses hosted checkout solutions to offload PCI compliance responsibilities.
What I Learned
Working on LiftMyCause significantly improved my understanding of:
- ledger design and balance aggregation strategies
- double-entry accounting principles in software systems
- settlement timing risks in payment integrations
- building provider-agnostic payment infrastructure
- designing financial state machines
- mentoring engineers across stack boundaries
- building systems that balance technical correctness with user trust
Improvements I Plan to Make
One area I am actively planning to improve is how campaign balances are computed.
Currently, campaign balances are updated incrementally alongside ledger entries. As transaction volume grows, this approach may become a bottleneck.
A future improvement involves:
- fully deriving campaign balances from ledger aggregation
- backfilling historical transactions into normalized ledger entries
- improving caching strategies for high-volume financial reporting
This will make the system more scalable and audit-friendly.