Building SaaS with AI Agents: Architecture Guide
How to build a SaaS product powered by AI agents β from architecture to launch.
AI agents are transforming SaaS products. Instead of static features, your SaaS can have intelligent agents that automate tasks, answer questions, and provide personalized experiences. This guide covers the complete architecture for building AI-powered SaaS.
SaaS + AI Agent Architecture
ββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend (React/Next.js) β
β ββββββββββββββββββββββββββββββββββββββ β
β β User Interface + Chat β β
β ββββββββββββββββ¬ββββββββββββββββββββββ β
βββββββββββββββββββββΌβββββββββββββββββββββββββββ€
β βΌ β
β ββββββββββββββββββββββββββββββββββββββ β
β β API Gateway (Next.js API) β β
β β Auth β’ Rate Limit β’ Validation β β
β ββββββββββββββββ¬ββββββββββββββββββββββ β
βββββββββββββββββββββΌβββββββββββββββββββββββββββ€
β βΌ β
β ββββββββββββββββββββββββββββββββββββββ β
β β Agent Orchestration Layer β β
β β Route β Plan β Execute β Respond β β
β ββββββββ¬βββββββββββ¬βββββββββββ¬ββββββββ β
β βΌ βΌ βΌ β
β ββββββββββββββββββββββββββββββββββββ β
β β LLM ββ MCP ββ Memory β β
β β Router ββ Tools ββ Store β β
β ββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββ€
β PostgreSQL β’ Redis β’ Pinecone β’ S3 β
ββββββββββββββββββββββββββββββββββββββββββββββββ
Core Components
1. Frontend (Next.js)
// app/chat/route.ts
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(request: Request) {
const { messages, userId } = await request.json();
const result = streamText({
model: openai("gpt-4o"),
messages,
tools: await getUserTools(userId),
system: await getSystemPrompt(userId),
onFinish: async (result) => {
await saveConversation(userId, messages, result);
},
});
return result.toDataStreamResponse();
}
2. Agent Orchestration
class SaaSAgent {
constructor(private userId: string, private tier: string) {}
async process(message: string): AsyncGenerator<string> {
// 1. Check permissions
const perms = await this.getPermissions(this.userId, this.tier);
// 2. Get user context
const context = await this.getUserContext(this.userId);
// 3. Select appropriate tools
const tools = await this.selectTools(message, perms);
// 4. Execute with streaming
const stream = await this.llm.stream({
model: this.selectModel(this.tier),
messages: [
{ role: "system", content: this.systemPrompt(context) },
...context.history,
{ role: "user", content: message },
],
tools,
});
// 5. Handle tool calls
for await (const part of stream) {
if (part.type === "tool_call") {
yield* this.handleToolCall(part, perms);
} else {
yield part.text;
}
}
}
}
3. Multi-Tenancy
class MultiTenantAgent:
async def get_user_context(self, user_id):
"""Load user-specific data and configuration."""
user = await self.db.get_user(user_id)
return {
"profile": user.profile,
"preferences": user.preferences,
"organization": user.org,
"tier": user.subscription_tier,
"usage": await self.get_usage(user_id),
"limits": self.get_limits(user.subscription_tier),
"history": await self.load_conversation_history(user_id),
"custom_tools": await self.get_user_tools(user_id),
}
def get_limits(self, tier):
limits = {
"free": {"messages_per_day": 20, "tools": ["basic"], "model": "gpt-4o-mini"},
"pro": {"messages_per_day": 500, "tools": ["basic", "advanced"], "model": "gpt-4o"},
"enterprise": {"messages_per_day": float("inf"), "tools": "all", "model": "gpt-4o"},
}
return limits.get(tier, limits["free"])
4. Usage Tracking and Billing
class UsageTracker {
async record(userId: string, usage: TokenUsage) {
await this.db.insert("usage", {
userId,
date: new Date(),
inputTokens: usage.input,
outputTokens: usage.output,
toolCalls: usage.toolCalls,
cost: this.calculateCost(usage),
});
// Check limits
const dailyUsage = await this.getDailyUsage(userId);
const limits = await this.getUserLimits(userId);
if (dailyUsage.messages >= limits.messagesPerDay) {
throw new UsageLimitExceeded("Daily message limit reached");
}
// Stripe integration for overages
if (dailyUsage.cost > limits.budgetAmount) {
await this.chargeOverage(userId, dailyUsage.cost - limits.budgetAmount);
}
}
}
Database Schema
-- Users and organizations
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
org_id UUID REFERENCES organizations(id),
subscription_tier TEXT DEFAULT 'free',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Conversations
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
title TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Messages
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID REFERENCES conversations(id),
role TEXT NOT NULL,
content TEXT NOT NULL,
tool_calls JSONB,
tokens_used INTEGER,
cost_eur DECIMAL(10, 4),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Usage tracking
CREATE TABLE usage (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
date DATE NOT NULL,
message_count INTEGER DEFAULT 0,
input_tokens INTEGER DEFAULT 0,
output_tokens INTEGER DEFAULT 0,
tool_calls INTEGER DEFAULT 0,
cost_eur DECIMAL(10, 4) DEFAULT 0,
UNIQUE(user_id, date)
);
-- Custom tools per user
CREATE TABLE user_tools (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
name TEXT NOT NULL,
config JSONB NOT NULL,
enabled BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Subscription Integration (Stripe)
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const PLANS = {
free: { priceId: null, limits: { messages: 20, model: "gpt-4o-mini" } },
pro: { priceId: "price_pro123", limits: { messages: 500, model: "gpt-4o" } },
enterprise: { priceId: "price_ent456", limits: { messages: -1, model: "gpt-4o" } },
};
export async function handleSubscription(user, newTier) {
const plan = PLANS[newTier];
if (plan.priceId) {
const session = await stripe.checkout.sessions.create({
customer: user.stripeCustomerId,
payment_method_types: ["card"],
line_items: [{ price: plan.priceId, quantity: 1 }],
mode: "subscription",
success_url: `${process.env.APP_URL}/settings?upgraded=true`,
cancel_url: `${process.env.APP_URL}/settings`,
});
return { checkoutUrl: session.url };
}
await db.update("users", user.id, { subscription_tier: newTier });
return { upgraded: true };
}
Security for Multi-Tenant
class TenantSecurity:
async def check_access(self, user_id, resource):
"""Ensure user can only access their own data."""
resource_owner = await self.get_owner(resource)
if resource_owner != user_id:
if not await self.same_org(user_id, resource_owner):
raise PermissionError("Access denied")
async def get_tools(self, user_id):
"""Get user-specific tools with isolation."""
user = await self.db.get_user(user_id)
# User can only access their org's tools + marketplace tools
tools = []
# Org-specific tools (private)
tools.extend(await self.get_org_tools(user.org_id))
# User's custom tools
tools.extend(await self.get_user_tools(user_id))
# Marketplace tools (shared, but usage tracked per user)
tools.extend(await self.get_marketplace_tools(user.tier))
return tools
Launch Checklist
MVP Features
- User authentication (email, Google)
- Chat interface with streaming
- 3-5 core tools/integrations
- Usage tracking and limits
- Stripe subscription integration
- Basic admin dashboard
- Error handling and fallbacks
- Mobile-responsive design
Launch Week
- Product Hunt launch
- Share in communities (Reddit, Discord, Twitter)
- Demo video on landing page
- Early user onboarding flow
- Feedback collection system
- Analytics tracking (PostHog, Mixpanel)
- Error monitoring (Sentry)
Post-Launch
- Weekly feature releases
- User feedback β feature prioritization
- MRR tracking dashboard
- Churn analysis and prevention
- Expansion to new use cases
Cost Structure
Per user costs (Pro tier, β¬29/month):
- LLM API: β¬2-5/month per active user
- Infrastructure: β¬1-2/month per user
- Vector DB: β¬0.50/month per user
- Total: β¬3.50-7.50/month per user
Gross margin: 75-88%
At 100 Pro users:
- Revenue: β¬2,900/month
- Costs: β¬500-750/month
- Profit: β¬2,150-2,400/month
Conclusion
Building a SaaS with AI agents is one of the highest-margin, fastest-growing business models. With modern tools (Next.js, Mastra, MCP, Stripe), you can launch in weeks, not months.
The key: solve one specific problem exceptionally well with AI, price it as a subscription, and scale through word-of-mouth and content marketing.
Learn More
- Building AI Agents with TypeScript
- AI Tool Monetization Strategies
- AI Agent Deployment Best Practices
- AI Automation ROI Calculator
Launch your AI SaaS with skills from SkillExchange.