fin-infra

Building Fintech APIs with fin-infra + svc-infra

Status: Production Ready
Last Updated: November 2025

Overview

This guide shows you how to build production-ready fintech APIs by combining two complementary packages:

  • svc-infra: Backend infrastructure (API framework, auth, DB, cache, observability, jobs)
  • fin-infra: Financial data providers (banking, market data, credit, brokerage, tax)

Key Principle: Don't reinvent the wheel. Use svc-infra for all backend infrastructure, fin-infra only for financial-specific integrations.

Quick Start

Minimal Example

python
from fastapi import FastAPI
from svc_infra.logging import setup_logging
from svc_infra.obs import add_observability
from fin_infra.banking import add_banking
from fin_infra.markets import add_market_data
from fin_infra.obs import financial_route_classifier

# Setup backend infrastructure (svc-infra)
setup_logging()
app = FastAPI(title="Fintech API")
add_observability(app, route_classifier=financial_route_classifier)

# Add financial capabilities (fin-infra)
add_banking(app, provider="plaid")
add_market_data(app, provider="alphavantage")

# Done! All routes auto-instrumented with metrics

See examples/demo_api/ for a complete working demo.

Architecture Patterns

Layer Separation

code
┌─────────────────────────────────────────────────────┐
│ Your Application                                    │
│ - Business logic                                    │
│ - Custom endpoints                                  │
│ - Domain models                                     │
└────────────┬────────────────────────────────────────┘
             │
             ├────────────────────┬────────────────────
             │                    │
┌────────────▼──────────┐  ┌──────▼─────────────────┐
│ fin-infra             │  │ svc-infra              │
│ (Financial Layer)     │  │ (Infrastructure Layer) │
├───────────────────────┤  ├────────────────────────┤
│ ✅ Banking providers  │  │ ✅ FastAPI scaffolding │
│ ✅ Market data        │  │ ✅ Auth & sessions     │
│ ✅ Credit scores      │  │ ✅ Database & ORM      │
│ ✅ Brokerage          │  │ ✅ Caching (Redis)     │
│ ✅ Tax data           │  │ ✅ Observability       │
│ ✅ Cashflow calcs     │  │ ✅ Background jobs     │
│ ✅ Provider adapters  │  │ ✅ Webhooks            │
│                       │  │ ✅ Rate limiting       │
│                       │  │ ✅ Logging             │
└───────────────────────┘  └────────────────────────┘

Integration Patterns

Pattern 1: Direct Provider Usage

python
from fin_infra.banking import easy_banking

banking = easy_banking(provider="plaid")
accounts = await banking.get_accounts(access_token)

Pattern 2: FastAPI Integration

python
from fin_infra.banking import add_banking

# Mounts routes at /banking/*
banking = add_banking(app, provider="plaid", prefix="/banking")

Pattern 3: Custom Endpoints with Providers

python
from fin_infra.banking import easy_banking
from fin_infra.markets import easy_market

banking = easy_banking()
market = easy_market()

@app.get("/portfolio/summary")
async def get_portfolio(token: str):
    accounts = await banking.get_accounts(token)
    # Custom business logic combining multiple providers
    return {"accounts": accounts, ...}

Step-by-Step Setup

1. Install Packages

bash
pip install svc-infra fin-infra

# Or with Poetry
poetry add svc-infra fin-infra

2. Setup Backend Infrastructure (svc-infra)

python
from svc_infra.logging import setup_logging
from svc_infra.obs import add_observability
from svc_infra.security.add import add_security

# Logging
setup_logging()

# FastAPI app
from fastapi import FastAPI
app = FastAPI(title="My Fintech API")

# Observability (metrics, tracing)
add_observability(app)

# Security headers, CORS
add_security(app)

3. Add Financial Capabilities (fin-infra)

python
from fin_infra.banking import add_banking
from fin_infra.markets import add_market_data
from fin_infra.credit import add_credit_monitoring

# Banking
banking = add_banking(app, provider="plaid")

# Market Data
market = add_market_data(app, provider="alphavantage")

# Credit Scores (optional)
credit = add_credit_monitoring(app, provider="experian")

4. Add Custom Business Logic

python
@app.get("/dashboard")
async def get_dashboard(user_id: str):
    """Custom endpoint combining multiple providers."""
    # Use fin-infra providers
    accounts = await banking.get_accounts(user_id)
    credit_score = await credit.get_score(user_id)
    
    # Business logic
    total_balance = sum(a.balance for a in accounts)
    
    return {
        "balance": total_balance,
        "credit_score": credit_score,
        "last_updated": datetime.now(),
    }

5. Run the API

python
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Complete Production Example

python
from fastapi import FastAPI, Depends
from svc_infra.api.fastapi import setup_service_api, ServiceInfo, APIVersionSpec
from svc_infra.logging import setup_logging
from svc_infra.obs import add_observability
from svc_infra.security.add import add_security
from svc_infra.api.fastapi.ops.add import add_probes, add_maintenance_mode
from fin_infra.banking import add_banking
from fin_infra.markets import add_market_data
from fin_infra.credit import add_credit_monitoring
from fin_infra.obs import financial_route_classifier

# 1. Logging
setup_logging()

# 2. Create production-grade FastAPI app
app = setup_service_api(
    service=ServiceInfo(
        name="fintech-api",
        description="Production fintech API",
        release="1.0.0",
    ),
    versions=[
        APIVersionSpec(tag="v1", routers_package="myapp.api.v1"),
    ],
)

# 3. Add svc-infra infrastructure
add_observability(app, route_classifier=financial_route_classifier)
add_security(app)
add_probes(app)  # Kubernetes health checks
add_maintenance_mode(app)  # Graceful degradation

# 4. Add fin-infra providers
banking = add_banking(app, provider="plaid")
market = add_market_data(app, provider="alphavantage")
credit = add_credit_monitoring(app, provider="experian")

# 5. Custom endpoints
@app.get("/v1/dashboard")
async def get_dashboard():
    """Combined financial dashboard."""
    return {
        "banking": banking.get_summary(),
        "market": market.get_indices(),
        "credit": await credit.get_score(),
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Feature Matrix

What Each Package Provides

FeaturePackageStatus
API Frameworksvc-infra✅ Use setup_service_api or easy_service_app
Auth & Sessionssvc-infra✅ Use add_auth_users
Database & Migrationssvc-infra✅ Use svc-infra db CLI
Cachingsvc-infra✅ Use init_cache
Observabilitysvc-infra✅ Use add_observability
Background Jobssvc-infra✅ Use easy_jobs
Webhookssvc-infra✅ Use add_webhooks
Rate Limitingsvc-infra✅ Middleware available
Loggingsvc-infra✅ Use setup_logging
Security Headerssvc-infra✅ Use add_security
Bankingfin-infra✅ Use add_banking or easy_banking
Market Datafin-infra✅ Use add_market_data or easy_market
Credit Scoresfin-infra✅ Use add_credit_monitoring or easy_credit
Brokeragefin-infra✅ Use add_brokerage or easy_brokerage
Tax Datafin-infra⚠️ Coming soon
Cashflow Calculationsfin-infra✅ Direct functions: npv, irr, etc.
Financial Route Classificationfin-infra✅ Use financial_route_classifier

Common Patterns

Pattern: Personal Finance App (Mint Clone)

python
from svc_infra.api.fastapi import setup_service_api, ServiceInfo
from svc_infra.obs import add_observability
from fin_infra.banking import add_banking
from fin_infra.markets import add_market_data
from fin_infra.credit import add_credit_monitoring
from fin_infra.obs import financial_route_classifier

app = setup_service_api(service=ServiceInfo(name="mint-clone"))
add_observability(app, route_classifier=financial_route_classifier)

# Financial features
add_banking(app)  # Connect bank accounts, transactions
add_market_data(app)  # Stock/crypto prices for investments
add_credit_monitoring(app)  # Track credit score

# Custom endpoints for budgeting, spending analysis, etc.

Pattern: Investment Platform (Robinhood Clone)

python
from svc_infra.api.fastapi import setup_service_api, ServiceInfo
from svc_infra.obs import add_observability
from fin_infra.brokerage import add_brokerage
from fin_infra.markets import add_market_data
from fin_infra.obs import financial_route_classifier

app = setup_service_api(service=ServiceInfo(name="trading-app"))
add_observability(app, route_classifier=financial_route_classifier)

# Financial features
add_brokerage(app, provider="alpaca")  # Paper/live trading
add_market_data(app)  # Real-time quotes

# Custom endpoints for portfolio, watchlists, etc.

Pattern: Credit Monitoring (Credit Karma Clone)

python
from svc_infra.api.fastapi import setup_service_api, ServiceInfo
from svc_infra.obs import add_observability
from fin_infra.credit import add_credit_monitoring
from fin_infra.banking import add_banking
from fin_infra.obs import financial_route_classifier

app = setup_service_api(service=ServiceInfo(name="credit-monitor"))
add_observability(app, route_classifier=financial_route_classifier)

# Financial features
add_credit_monitoring(app)  # Credit scores, reports
add_banking(app)  # Financial profile

# Custom endpoints for credit alerts, recommendations, etc.

Testing

Unit Tests

python
import pytest
from fin_infra.banking import easy_banking

def test_get_accounts():
    banking = easy_banking(provider="fake")
    accounts = banking.get_accounts("test_token")
    assert len(accounts) > 0

Integration Tests (with svc-infra patterns)

python
from fastapi.testclient import TestClient
from myapp import app

client = TestClient(app)

def test_banking_endpoint():
    response = client.get("/banking/accounts")
    assert response.status_code == 200
    data = response.json()
    assert "accounts" in data

Acceptance Tests (with real providers)

python
import pytest
import os

@pytest.mark.acceptance
@pytest.mark.skipif(not os.getenv("PLAID_CLIENT_ID"), reason="Plaid not configured")
def test_plaid_integration():
    from fin_infra.banking import easy_banking
    
    banking = easy_banking(provider="plaid")
    # Test with sandbox credentials
    ...

Configuration

Environment Variables

env
# svc-infra
APP_ENV=production
LOG_LEVEL=INFO
METRICS_ENABLED=true
SQL_URL=postgresql://...
REDIS_URL=redis://...

# fin-infra
PLAID_CLIENT_ID=...
PLAID_SECRET=...
ALPHAVANTAGE_API_KEY=...
EXPERIAN_USERNAME=...

Settings Pattern (Pydantic)

python
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    # svc-infra
    app_env: str = "local"
    log_level: str = "INFO"
    
    # fin-infra
    plaid_client_id: str
    plaid_secret: str
    alphavantage_api_key: str
    
    class Config:
        env_file = ".env"

settings = Settings()

Deployment

Docker

dockerfile
FROM python:3.11-slim

WORKDIR /app

# Install dependencies
COPY pyproject.toml poetry.lock ./
RUN pip install poetry && poetry install --no-dev

# Copy app
COPY . .

# Run
CMD ["poetry", "run", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

Kubernetes

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fintech-api
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: api
        image: fintech-api:latest
        env:
        - name: APP_ENV
          value: "production"
        - name: PLAID_CLIENT_ID
          valueFrom:
            secretKeyRef:
              name: fintech-secrets
              key: plaid-client-id
        ports:
        - containerPort: 8000
        livenessProbe:
          httpGet:
            path: /health/live
            port: 8000
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 8000

Observability

Metrics

promql
# Financial endpoint request rate
sum(rate(http_server_requests_total{route=~".*\\|financial"}[5m]))

# Financial endpoint P95 latency
histogram_quantile(0.95,
  rate(http_server_request_duration_seconds_bucket{route=~".*\\|financial"}[5m])
)

# Error rate by route class
sum(rate(http_server_requests_total{code=~"5..", route=~".*\\|financial"}[5m]))
/ sum(rate(http_server_requests_total{route=~".*\\|financial"}[5m]))

Logs

json
{
  "timestamp": "2025-11-06T12:34:56.789Z",
  "level": "INFO",
  "message": "Banking request completed",
  "provider": "plaid",
  "method": "get_accounts",
  "duration_ms": 234.56,
  "user_id": "u-123"
}

Best Practices

1. Always Use svc-infra for Backend Infrastructure

python
# ✅ GOOD: Use svc-infra for logging
from svc_infra.logging import setup_logging

# ❌ BAD: Don't create custom logging (fin-infra doesn't provide it)
import logging
logging.basicConfig(...)  # NO!

2. Use fin-infra Only for Financial Integrations

python
# ✅ GOOD: Use fin-infra for banking
from fin_infra.banking import add_banking

# ❌ BAD: Don't use fin-infra for generic caching (use svc-infra)
from fin_infra.cache import ...  # Doesn't exist!

3. Compose with Route Classification

python
# ✅ GOOD: Compose financial classifier with custom classifiers
from fin_infra.obs import financial_route_classifier, compose_classifiers

def admin_classifier(path, method):
    return "admin" if path.startswith("/admin") else "public"

classifier = compose_classifiers(
    financial_route_classifier,
    admin_classifier,
)

add_observability(app, route_classifier=classifier)

4. Use Easy Builders for Development

python
# ✅ GOOD for development: Use easy_* builders
from fin_infra.banking import easy_banking
banking = easy_banking()

# ✅ GOOD for production: Use add_* FastAPI helpers
from fin_infra.banking import add_banking
banking = add_banking(app)

5. Handle Provider Errors Gracefully

python
from fin_infra.banking import easy_banking, ProviderError

banking = easy_banking()

try:
    accounts = await banking.get_accounts(token)
except ProviderError as e:
    logger.error(f"Banking provider error: {e}")
    # Fallback logic or user-friendly error

Troubleshooting

Issue: Missing svc-infra Features

Problem: Looking for feature X in fin-infra

Solution: Check svc-infra first! fin-infra only provides financial-specific integrations.

Issue: Provider Not Configured

Problem: ProviderNotConfiguredError: Missing PLAID_CLIENT_ID

Solution: Add credentials to .env file or environment variables.

Issue: Metrics Not Showing Route Class

Problem: Metrics show route="/banking/accounts" instead of route="/banking/accounts|financial"

Solution: Pass route_classifier to add_observability:

python
from fin_infra.obs import financial_route_classifier
add_observability(app, route_classifier=financial_route_classifier)

Summary

Use svc-infra for all backend infrastructure (API, auth, DB, cache, jobs, webhooks)
Use fin-infra for financial data integrations (banking, market, credit, brokerage)
Compose both for production-ready fintech APIs
Follow patterns in examples/demo_api/ and svc-infra/examples/