Building a Custom Wallet & Dynamic Pricing Engine
A technical deep-dive into engineering a production-grade financial microservice with FastAPI, PostgreSQL, and Atomic Transactions.

Repository: https://github.com/AkshayThoolkar/edtech_wallet_service.git


Context & Motivation

In the world of AI EdTech, "cost" is a variable, not a constant. Unlike traditional CRUD applications where database reads are cheap, every interaction in my platform involves LLM token consumption, vector database queries, and significant compute.

When building my AI EdTech platform, I faced a critical business and engineering challenge: How do I monetize micro-interactions effectively?

A user generating a 5-question quiz costs completely different money than a user generating a full semester's learning path. A flat monthly subscription (SaaS style) risks negative margins on power users. A simple "pay-per-use" model introduces too much friction (nobody wants to enter an OTP for a ₹5 charge).

I needed a system that offered:

This led to the design and development of the Wallet Service, a standalone microservice leveraging Python's FastAPI for high performance and PostgreSQL for transactional integrity.

System Overview

The Wallet Service sits at the absolute center of the platform's commercial logic. It exposes internal APIs that other services (like the Course Service or Learning Path Service) consume to authorize actions.

The Core Workflows

Project Structure

This microservice follows a standard FastAPI structure with clear separation of concerns:

wallet_service/

├── alembic/                 # Database migrations

├── routers/                 # API endpoints (wallets, payments, subscriptions)

├── services/                # Business logic layer

├── templates/               # HTML templates for invoice generation

├── config.py                # Environment configuration

├── crud.py                  # Database operations

├── database.py              # DB connection & session management

├── main.py                  # App entry point

├── models.py                # SQLAlchemy ORM models

├── schemas.py               # Pydantic data validation models

└── requirements.txt         # Dependencies

Architectural Decisions

1. Framework: FastAPI (Python)

I chose FastAPI over Django or Flask for three reasons:

2. Database: PostgreSQL & SQLAlchemy

Relational integrity is paramount in finance. I needed ACID compliance.

3. Payment Gateway: Razorpay

Chosen for its dominance in the Indian market, excellent webhook support, and native UPI integration.

4. Invoice Engine: WeasyPrint

I needed pixel-perfect PDF generation for invoices (a strict legal requirement). WeasyPrint allows me to design invoices using standard HTML/CSS and convert them to PDF on the fly.

Data Model Design

The database schema is designed to separate *value* (money) from *rules* (pricing) and *state* (subscriptions).

Key Tables:

The Dynamic Pricing Engine

This is the most technically interesting component. Instead of hardcoding costs, the `calculate_price` method performs a real-time lookup:

This architecture allows the business team to run "pricing experiments" simply by updating a row in SQL.

Solving Concurrency: The "Double-Spend" Problem

In a distributed system, a user might click a button twice, or two automated processes might trigger simultaneously. If a user has ₹10 and submits two requests for ₹10 each at the exact same millisecond, a naive read-modify-write approach would allow both.

The Solution: with_for_update

I implemented rigorous database locking using SQLAlchemy's with_for_update:

# Simplified Logic

async with db.begin():

    # LOCK the wallet row. No other transaction can read/write this 

    # until this block finishes.

    wallet = await db.query(Wallet).filter(id=user_id).with_for_update().first()

    

    if wallet.balance < cost:

        raise InsufficientFundsError()

        

    wallet.balance -= cost

    # Commit releases the lock

This ensures atomicity. Requests become serialized at the database level, guaranteeing that a balance can never go negative due to race conditions.

Security & Compliance

Financial services require a higher standard of security hygiene.

Localhost Binding: The production service is bound strictly to 127.0.0.1. It is not exposed to the public internet. It can only be reached by other authenticated microservices within the private network or via the API Gateway.

Mock Mode for Dev: I built a "Mock Payment Mode" that simulates Razorpay webhooks. This allows developers to test full subscription flows locally without using real credit cards.

Audit Logs: Every single change to the wallet_transactions table includes a transaction_type, reference_id (linking to the external Razorpay order), and timestamp.

Testing Strategy

You cannot "move fast and break things" with payments. I implemented a comprehensive test suite (48+ unit and integration tests) covering:

Future Roadmap: Multi-Tenancy

Currently, the system is designed for a single tenant (my B2C platform). The next evolution of this architecture is Multi-Tenancy. This will involve:

Business Impact: From Code to Revenue

This architecture didn't just solve a technical problem; it unlocked business capabilities:

Experimentation: We can now A/B test pricing models (e.g., "Discounted Weekends") by simply updating the database, zero deployment required.

Revenue Assurance: The "double-spend" protection effectively eliminated revenue leakage from race conditions, protecting an estimated 2-5% of potential transaction volume.

Support Reduction: Automated invoice generation reduced billing-related support tickets by over 40%, allowing the team to focus on feature development.

Final Thoughts

Building the Wallet Service was an exercise in *system design* over simple coding. It forced me to think about consistency boundaries, database isolation levels, and business logic decoupling.

The result is a monetization engine that is robust enough to handle real money, yet flexible enough to adapt to the rapidly changing landscape of AI economics.

Repository: https://github.com/AkshayThoolkar/edtech_wallet_service.git