Skip to main content
HP
Back to All Projects

Global Billing Service

Production-ready billing microservice powering multi-currency payments

PythonFastAPIPostgreSQLStripeAWSDocker

The Problem

SaaS platforms need billing systems that handle subscription lifecycle, multi-currency payments, and invoice generation, but most solutions are either too simple or too complex. This microservice hits the sweet spot: a clean, production-ready billing engine that supports 39 currencies, full subscription management, and Stripe integration out of the box.

Architecture

HTTPSTCPRESTLogsClient AppsWeb / MobileALBHTTPS :443FastAPIAPI → Service → DataPostgreSQLRDSStripe APIPaymentsECS FargateContainer RuntimeCloudWatchLogs & Metrics

Technical Decisions

Why FastAPI over Flask?

FastAPI gives me automatic request validation via Pydantic, async support out of the box, and auto-generated OpenAPI docs. For a billing service where every request must be validated strictly (you don't want a malformed currency code hitting Stripe), Pydantic models are non-negotiable. Flask would have meant writing all that validation manually.

How do you handle 39 currencies correctly?

Each currency has a minimum charge amount (e.g., $0.50 USD, ¥50 JPY). I built a validation layer that checks every payment against currency-specific minimums before it ever reaches Stripe. Because charging someone in Japanese yen the way you'd charge in US dollars is a good way to lose money.

Why idempotent payment operations?

Network failures happen. If a client retries a payment request, you can't charge them twice. Every payment operation uses an idempotency key. If Stripe sees the same key twice, it returns the original result instead of processing a new charge. This is table-stakes for production payment systems but something most portfolio projects skip entirely.

How is the subscription lifecycle managed?

Subscriptions move through states: created → active → upgraded/downgraded → canceled → reactivated. Each transition has webhook-driven status updates from Stripe, so the system is always in sync with Stripe's state. No polling, no cron jobs. Just real-time webhooks.

Code Spotlight

billing/services/currency.py
CURRENCY_MINIMUMS: dict[str, int] = {
    "usd": 50, "eur": 50, "gbp": 30,
    "jpy": 50, "cad": 50, "aud": 50,
    # ... 39 currencies total
}

def validate_charge_amount(
    amount: int, currency: str
) -> None:
    """Validate charge meets currency minimum."""
    currency = currency.lower()
    if currency not in CURRENCY_MINIMUMS:
        raise InvalidCurrencyError(
            f"Unsupported currency: {currency}"
        )
    minimum = CURRENCY_MINIMUMS[currency]
    if amount < minimum:
        raise AmountTooSmallError(
            f"Minimum for {currency.upper()}: "
            f"{minimum} (got {amount})"
        )

Every payment hits this validation before touching Stripe. Currency-specific minimums prevent failed charges and protect revenue integrity.

Key Features

Payment Processing

  • 39 currencies with per-currency minimum validation
  • Idempotent payment operations via Stripe idempotency keys
  • Stripe Checkout session integration
  • Webhook-driven real-time payment status updates

Subscription Management

  • Full lifecycle: create → upgrade → downgrade → cancel → reactivate
  • Automated invoice generation with sequential numbering (INV-YYYYMM-XXXX)
  • Plan comparison and prorated billing support

Infrastructure

  • API Key Authentication with JWT
  • Health monitoring endpoint
  • Structured JSON logging with structlog
  • CORS configuration for cross-origin access

Testing

27 tests across 5 categories covering every critical path in the billing system.

27 tests across 5 categories

  • SQLite in-memory database for fast, isolated test runs
  • Mocked Stripe API for deterministic tests without real API calls
  • Separate test categories: Customers (7), Plans (5), Subscriptions (6), Invoices & Payments (6), Currencies & Health (3)

CI/CD Pipeline

Push to main
Lint (Ruff)
Test (PostgreSQL service container)
Build Docker image
Push to ECR
Deploy to ECS Fargate via GitHub Actions

Results

01

39 currencies supported with proper minimum charge validation

02

27 tests with full mocked Stripe coverage

03

Automated invoice generation with sequential numbering

04

Production-ready Docker deployment on AWS ECS Fargate