How to Integrate FastAPI for lending with PostgreSQL for startups

By Cyprian AaronsUpdated 2026-04-21
fastapi-for-lendingpostgresqlstartups

Combining FastAPI for lending with PostgreSQL gives you a clean way to expose lending workflows as APIs while keeping loan data, customer profiles, repayment schedules, and audit history in a durable relational store. For startups building AI agent systems, this is the difference between a demo and a system that can actually track applications, score borrowers, and persist decisions across services.

Prerequisites

  • Python 3.10+
  • A running PostgreSQL instance
  • fastapi
  • uvicorn
  • psycopg2-binary or asyncpg
  • sqlalchemy
  • Access to your FastAPI for lending service credentials or local project
  • A PostgreSQL database and user with write permissions

Install the Python packages:

pip install fastapi uvicorn sqlalchemy psycopg2-binary pydantic

Integration Steps

  1. Set up your PostgreSQL connection

Use SQLAlchemy for connection management. This keeps your FastAPI app clean and makes it easy to swap sync/async drivers later.

from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker, declarative_base

DATABASE_URL = "postgresql+psycopg2://loan_user:loan_pass@localhost:5432/loan_db"

engine = create_engine(DATABASE_URL, pool_pre_ping=True)
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
Base = declarative_base()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

Create your base tables for loans and applicants:

from sqlalchemy import Column, Integer, String, Numeric, DateTime
from datetime import datetime

class LoanApplication(Base):
    __tablename__ = "loan_applications"

    id = Column(Integer, primary_key=True)
    applicant_name = Column(String(255), nullable=False)
    email = Column(String(255), nullable=False, unique=True)
    amount_requested = Column(Numeric(12, 2), nullable=False)
    status = Column(String(50), nullable=False, default="pending")
    created_at = Column(DateTime, default=datetime.utcnow)
  1. Initialize the FastAPI lending API

This is where you expose endpoints for application intake and loan decisioning. In many startup systems, this API becomes the entry point for an AI agent that gathers data and submits it downstream.

from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel, EmailStr
from sqlalchemy.orm import Session

app = FastAPI(title="Lending API")

class LoanRequest(BaseModel):
    applicant_name: str
    email: EmailStr
    amount_requested: float

@app.on_event("startup")
def startup_event():
    Base.metadata.create_all(bind=engine)

@app.post("/loans/apply")
def apply_for_loan(payload: LoanRequest, db: Session = Depends(get_db)):
    existing = db.query(LoanApplication).filter(LoanApplication.email == payload.email).first()
    if existing:
        raise HTTPException(status_code=409, detail="Application already exists")

    application = LoanApplication(
        applicant_name=payload.applicant_name,
        email=payload.email,
        amount_requested=payload.amount_requested,
        status="pending",
    )
    db.add(application)
    db.commit()
    db.refresh(application)

    return {
        "application_id": application.id,
        "status": application.status,
        "email": application.email,
    }
  1. Persist loan decisions from your AI agent

Your agent can call the lending endpoint after scoring an applicant. Store the decision in PostgreSQL so it can be audited later.

class LoanDecision(Base):
    __tablename__ = "loan_decisions"

    id = Column(Integer, primary_key=True)
    application_id = Column(Integer, nullable=False)
    decision = Column(String(20), nullable=False)  # approved / rejected / review
    reason = Column(String(500), nullable=True)
    created_at = Column(DateTime, default=datetime.utcnow)

@app.post("/loans/{application_id}/decision")
def save_decision(application_id: int, decision: str, reason: str | None = None, db: Session = Depends(get_db)):
    application = db.query(LoanApplication).filter(LoanApplication.id == application_id).first()
    if not application:
        raise HTTPException(status_code=404, detail="Application not found")

    row = LoanDecision(
        application_id=application_id,
        decision=decision,
        reason=reason,
    )
    application.status = decision
    db.add(row)
    db.commit()

    return {"application_id": application_id, "decision": decision}
  1. Call the FastAPI lending service from an AI agent

If your startup has an orchestration layer or agent service, it should submit applications through HTTP rather than writing directly to the database. That keeps business logic centralized.

import requests

payload = {
    "applicant_name": "Amina Patel",
    "email": "amina@example.com",
    "amount_requested": 25000.0,
}

response = requests.post("http://localhost:8000/loans/apply", json=payload)
response.raise_for_status()

application_data = response.json()
print(application_data)

Then record a decision after scoring:

decision_payload = {
    "decision": "approved",
    "reason": "Stable income and low debt-to-income ratio",
}

decision_response = requests.post(
    f"http://localhost:8000/loans/{application_data['application_id']}/decision",
    params=decision_payload,
)
decision_response.raise_for_status()

print(decision_response.json())
  1. Run the API server

Start FastAPI with Uvicorn:

uvicorn main:app --reload --host 0.0.0.0 --port 8000

At this point you have:

  • An API layer for loan intake and decisions
  • PostgreSQL-backed persistence for applications and audit records
  • A clean boundary for your AI agent to interact with lending workflows

Testing the Integration

Use a simple script to verify both submission and persistence work end-to-end.

import requests

base_url = "http://localhost:8000"

create_resp = requests.post(
    f"{base_url}/loans/apply",
    json={
        "applicant_name": "John Mensah",
        "email": "john.mensah@example.com",
        "amount_requested": 10000,
    },
)
print("Create:", create_resp.status_code, create_resp.json())

app_id = create_resp.json()["application_id"]

decision_resp = requests.post(
    f"{base_url}/loans/{app_id}/decision",
    params={"decision": "review", "reason": "Needs manual verification"},
)
print("Decision:", decision_resp.status_code, decision_resp.json())

Expected output:

Create: 200 {'application_id': 1, 'status': 'pending', 'email': 'john.mensah@example.com'}
Decision: 200 {'application_id': 1, 'decision': 'review'}

You can also verify rows directly in PostgreSQL:

SELECT id, applicant_name, email, amount_requested, status FROM loan_applications;
SELECT id, application_id, decision, reason FROM loan_decisions;

Real-World Use Cases

  • AI-assisted loan intake

    • An agent collects applicant details from chat or forms.
    • FastAPI validates input.
    • PostgreSQL stores the full request trail for compliance and retries.
  • Automated credit decisioning

    • The agent scores applicants using bank statements or transaction summaries.
    • Decisions are posted back through FastAPI.
    • PostgreSQL stores approvals, rejections, and reasons for auditability.
  • Repayment tracking and collections

    • Store repayment schedules in PostgreSQL.
    • Expose endpoints in FastAPI for payment updates.
    • Let agents trigger reminders when installments are overdue.

This stack works because each layer has one job. FastAPI handles request/response boundaries for lending workflows; PostgreSQL holds the source of truth; your AI agent sits on top and orchestrates decisions without owning persistence logic.


Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides