| 4 min read

How to Build an AI-Powered SaaS from Scratch

SaaS AI product Stripe FastAPI startup product development

Building an AI SaaS Is More Than Wrapping an API

The most common mistake I see in AI SaaS products is treating the AI as the product. It is not. The AI is a component. The product is the experience around it: the interface, the reliability, the billing, the support, the value it creates for users. I learned this building my document analysis SaaS, and I want to share the complete picture of what it takes.

Start with the Problem, Not the Technology

Before writing any code, I spent two weeks talking to potential users. The pattern I kept hearing was: "We have too many documents and not enough time to read them properly." That is a clear, painful problem with a measurable impact (time wasted, decisions made without full information).

Your AI SaaS should solve a problem that people already know they have. If you have to explain why they need it, you are in trouble.

The Minimum Viable Stack

For an AI SaaS, you need less infrastructure than you think:

  • Backend: FastAPI on a VPS (I use Hetzner, roughly 5 euros/month)
  • Database: PostgreSQL with pgvector
  • AI: Claude API (Anthropic)
  • Payments: Stripe Checkout and Billing
  • Frontend: Server-rendered templates or a simple React/Next.js app
  • Auth: Simple JWT-based authentication

Total infrastructure cost at launch: under 20 pounds per month. You do not need Kubernetes, microservices, or a complex cloud setup to start.

Authentication and User Management

Keep authentication simple at first. I use a straightforward email/password flow with JWT tokens:

from fastapi import Depends, HTTPException
from fastapi.security import HTTPBearer
import jwt

security = HTTPBearer()

async def get_current_user(credentials = Depends(security)) -> User:
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=["HS256"])
        user = await get_user_by_id(payload["user_id"])
        if not user:
            raise HTTPException(status_code=401)
        return user
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401)

You can add OAuth (Google, GitHub) later when you have paying users. Do not over-invest in auth before you have validated the product.

Billing with Stripe

Stripe is the obvious choice for billing, but the implementation has nuances. Here is what I learned:

Use Stripe Checkout

Do not build your own payment form. Stripe Checkout handles the entire payment UI, PCI compliance, and even sends receipts. You redirect users to Stripe, and they redirect back when payment is complete.

Webhook-Based Subscription Management

Never rely on redirect callbacks for subscription status. Use webhooks as the source of truth:

@app.post("/webhooks/stripe")
async def handle_stripe_webhook(request: Request):
    payload = await request.body()
    sig = request.headers.get("stripe-signature")
    
    try:
        event = stripe.Webhook.construct_event(payload, sig, WEBHOOK_SECRET)
    except stripe.error.SignatureVerificationError:
        raise HTTPException(status_code=400)
    
    handlers = {
        "checkout.session.completed": handle_checkout_complete,
        "customer.subscription.updated": handle_subscription_update,
        "customer.subscription.deleted": handle_subscription_cancelled,
        "invoice.payment_failed": handle_payment_failed,
    }
    
    handler = handlers.get(event["type"])
    if handler:
        await handler(event["data"]["object"])
    
    return {"status": "ok"}

Usage-Based Limits

Each subscription tier has a monthly usage limit (number of documents, API calls, etc.). Track usage in your database and enforce it server-side:

async def check_usage_limit(user: User) -> bool:
    current_usage = await get_monthly_usage(user.id)
    tier_limit = TIER_LIMITS[user.subscription_tier]
    return current_usage < tier_limit

AI Cost Management

This is where many AI SaaS products fail financially. Every API call costs money, and if you are not tracking and controlling costs, margins can evaporate quickly.

Cost Per User Action

Calculate the exact cost of every user-facing action. For my document analysis:

  • Average document: 5,000 tokens input, 1,000 tokens output
  • Claude Sonnet cost: approximately 2p per analysis
  • Cheapest subscription tier: 10 pounds/month for 100 documents
  • AI cost for 100 documents: 2 pounds
  • Gross margin: 80%

Model Routing

Not every request needs the most expensive model. Route simpler tasks to cheaper models:

def select_model(document_complexity: float) -> str:
    if document_complexity < 0.3:
        return "claude-haiku-4-20250414"  # ~0.2p per analysis
    elif document_complexity < 0.7:
        return "claude-sonnet-4-20250514"  # ~2p per analysis
    else:
        return "claude-sonnet-4-20250514"  # same, with longer context

The User Experience Layer

The AI is invisible to users. What they see is the interface. Invest time in:

  • Upload experience: Drag-and-drop with progress indicators and clear file type/size requirements
  • Processing feedback: Show users that something is happening. A progress bar or status updates during analysis
  • Clear results: Present AI output in a structured, scannable format. Not a wall of text
  • Error messages: When something fails, tell users what happened and what to do next

Launch Checklist

Before launching, make sure you have:

  • Error monitoring (Sentry or similar)
  • Usage logging and cost tracking
  • Rate limiting on all endpoints
  • Input validation on all user-submitted data
  • Backup strategy for your database
  • Privacy policy and terms of service
  • Email notification system for billing events
  • A way for users to contact you when things go wrong

Lessons from Launch

Three things I wish I had known before launching:

  1. Edge cases dominate support: The AI handles 95% of documents perfectly. The other 5% generate 90% of support requests. Invest in handling edge cases early.
  2. Pricing is hard: I changed my pricing three times in the first month. Start simple and adjust based on usage patterns.
  3. Free tiers attract the wrong users: I switched from a free tier to a low-cost entry tier and the quality of users improved dramatically. People who pay even a small amount are more serious and provide better feedback.

Building an AI SaaS is fundamentally a product engineering challenge, not an AI challenge. Get the product basics right, and the AI amplifies your value proposition. Get them wrong, and even brilliant AI cannot save you.