Monetization: Adding Payments and Making Money
Learning Objectives
- Understand SaaS revenue models
- Implement subscription payments with Stripe
- Distinguish free/paid users and limit features
- Learn legal considerations for payments
7.1 SaaS Revenue Models
Common Models
| Model | Description | Examples |
|---|---|---|
| Subscription | Monthly/yearly recurring payment | Netflix, Notion |
| Usage-based | Pay for what you use | AWS, OpenAI API |
| Freemium | Free basics + paid features | Spotify, LinkedIn |
| One-time purchase | Pay once | Apps, courses |
LinkHub Revenue Model
We'll apply a Freemium + Subscription model:
| Plan | Price | Features |
|---|---|---|
| Free | $0/month | 5 links, basic theme |
| Pro | $5/month | Unlimited links, premium themes, click analytics, custom domain |
Note
The pricing in this book is an example. Adjust prices to fit your service.
Key Metrics (Good to Know)
- MRR (Monthly Recurring Revenue) - Monthly recurring revenue
- Churn Rate - Subscription cancellation rate
- LTV (Customer Lifetime Value) - Customer lifetime value
7.2 Getting Started with Stripe
Stripe is a developer-friendly payment service. Well-documented and supports international payments including Korean payments.
Account Setup
- Sign up at stripe.com
- Enter business information
- Start in test mode (no real payments)
Create Product and Price
- Dashboard → Products → Add product
- Name: "LinkHub Pro"
- Pricing: Recurring, $5/month
- Copy Product ID and Price ID
Check API Keys
Find these in Developers → API keys:
| Key | Purpose | Expose? |
|---|---|---|
| Publishable key (pk_...) | Frontend | O |
| Secret key (sk_...) | Backend | Never |
7.3 Implementing Payment Page
Using Stripe Checkout means you don't need to build the payment page yourself.
Payment Flow
1. User clicks "Subscribe to Pro"
2. Server creates Stripe Checkout session
3. Redirect to Stripe payment page
4. User enters card information
5. Payment complete → Return to our site
6. Webhook confirms payment → Update DBCreating API Route
Create a Next.js API route.
/api/checkout:
- Create Stripe Checkout session
- Use logged-in user's email
- Redirect to /dashboard on success
- Redirect to /pricing on cancel// /api/checkout.ts
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
payment_method_types: ['card'],
line_items: [{
price: process.env.STRIPE_PRICE_ID,
quantity: 1,
}],
success_url: `${origin}/dashboard?success=true`,
cancel_url: `${origin}/pricing`,
customer_email: user.email,
});
return Response.json({ url: session.url });
}Webhook Setup
Stripe notifies our server when payment is complete.
Create an API to handle Stripe Webhook.
/api/webhook:
- Handle checkout.session.completed event
- Change user's subscription_status to 'pro'
- Include signature verification7.4 Implementing Feature Limits
Usage Tracking
Track link count per user.
Count active links from the links table for each user.
Free users limited to 5.Applying Limits
async function canAddLink(userId: string) {
const user = await getUser(userId);
// Pro users are unlimited
if (user.subscription_status === 'pro') {
return { allowed: true };
}
// Free users get 5 links
const count = await getActiveLinkCount(userId);
if (count >= 5) {
return {
allowed: false,
reason: 'You have reached your free plan link limit.',
remaining: 0
};
}
return { allowed: true, remaining: 5 - count };
}UI Display
- Show remaining link slots on the dashboard
- Upgrade prompt modal when limit reached
- Link to pricing comparison page
7.5 Subscription Management
Customer Portal
Stripe-provided subscription management page:
- Change payment method
- Change subscription plan
- Cancel subscription
- View payment history
// Create Customer Portal session
const session = await stripe.billingPortal.sessions.create({
customer: stripeCustomerId,
return_url: `${origin}/dashboard`,
});Handling Subscription Cancellation
Handle subscription cancellation Webhook.
customer.subscription.deleted event:
- Change subscription_status to 'free'
- Maintain features until cancellation point7.6 Cost Optimization
Learn how to manage costs for sustainable operations.
API Cost Monitoring
Claude API costs can exceed expectations.
| Model | Input (1M tokens) | Output (1M tokens) | Use Case |
|---|---|---|---|
| Claude Opus | $15 | $75 | Complex tasks |
| Claude Sonnet | $3 | $15 | General tasks (recommended) |
| Claude Haiku | $0.25 | $1.25 | Simple tasks |
Cost-Saving Tips
- Remove unnecessary context - Send only needed information
- Request in small units - Large requests waste tokens
- Use cheaper models during development - Test with Haiku, finalize with Sonnet
Infrastructure Cost Management
| Service | Free Tier | Paid Starts | Tips |
|---|---|---|---|
| Vercel | 100GB bandwidth/month | $20/month | Personal projects fine on free |
| Railway | $5 credit/month | Usage-based | Sleep settings reduce costs |
| Supabase | 500MB DB, 2GB bandwidth | $25/month | Use external CDN for images |
7.7 Legal Considerations
Required Documents
- Terms of Service
- Privacy Policy
- Refund Policy
For Korean Business Owners
- Online mail-order business registration required
- E-commerce law compliance
- Tax invoice issuance (B2B)
- VAT reporting
Test → Live Transition
- Test thoroughly in Stripe test mode
- Enter real business information
- Connect bank account
- Switch to live API keys
- First payment!
7.8 Other Payment Options
Besides Stripe, there are various payment services. Consider alternatives especially when targeting the Korean market or wanting to delegate tax/refund handling.
Options Comparison
| Service | Features | Fees | Recommended For |
|---|---|---|---|
| Stripe | Global standard, developer-friendly | 2.9% + 30¢ | Global services |
| Paddle | MoR, handles tax/refunds | ~5% + 50¢ | Global SaaS, no tax worries |
| Lemon Squeezy | Easy setup, MoR | 5% + 50¢ | Solo developers, quick start |
| Toss Payments | Optimized for Korea, various payment methods | 3.3% | Korean user base |
| PortOne (Iamport) | PG integration, multiple PG connections | Varies by PG | Comparing multiple PGs |
| PayPal | Global recognition, buyer protection | 3.49% + 49¢ | International individual customers |
Paddle (Merchant of Record)
Paddle is a Merchant of Record (MoR) service. Paddle becomes the seller and handles tax filing, refunds, and dispute resolution for you.
Implement subscription payments with Paddle.
Use @paddle/paddle-js.
Checkout Overlay method.// Paddle client example
import { initializePaddle } from '@paddle/paddle-js';
const paddle = await initializePaddle({
environment: 'sandbox', // or 'production'
token: process.env.NEXT_PUBLIC_PADDLE_TOKEN!,
});
// Start checkout
paddle.Checkout.open({
items: [{ priceId: 'pri_xxxxx', quantity: 1 }],
customer: { email: user.email },
});Paddle Advantages
- Handles VAT, GST, and global taxes automatically
- Handles refunds and dispute resolution
- Auto-generates tax invoices
- Sell globally without complex tax issues
Lemon Squeezy
Lemon Squeezy is also MoR like Paddle, but provides simpler setup. Especially popular with solo developers.
Implement payments with Lemon Squeezy.
Use @lemonsqueezy/lemonsqueezy.js.
Checkout link method.// Lemon Squeezy example
import { createCheckout } from '@lemonsqueezy/lemonsqueezy.js';
// Create checkout link
const checkout = await createCheckout(storeId, variantId, {
checkoutData: {
email: user.email,
custom: { user_id: userId },
},
});
// Redirect to payment page
window.location.href = checkout.data.attributes.url;Lemon Squeezy vs Paddle
- Lemon Squeezy: Easier to start, cheaper for small-scale sales
- Paddle: More features, enterprise support
Toss Payments (Korea)
If your target audience is Korean users, Toss Payments is a great choice. It supports cards, bank transfers, and easy-pay services (Toss Pay, Kakao Pay, etc.).
Implement payments with Toss Payments.
Use @tosspayments/payment-sdk.
Support card payments and easy-pay.// Toss Payments example
import { loadTossPayments } from '@tosspayments/payment-sdk';
const tossPayments = await loadTossPayments(clientKey);
// Request payment
await tossPayments.requestPayment('카드', {
amount: 10000,
orderId: 'order_xxxxx',
orderName: 'LinkHub Pro Subscription',
customerEmail: user.email,
successUrl: `${origin}/api/payments/success`,
failUrl: `${origin}/api/payments/fail`,
});Korean Payment Characteristics
- PG (Payment Gateway) approval required (business registration mandatory)
- Recurring payments require separate review
- Supports card payments + bank transfers + virtual accounts + easy-pay services
PortOne (Iamport)
A unified service that lets you integrate multiple PG providers at once. You can use Toss Payments, KG Inicis, NicePay, and more through a single SDK.
Implement payments with PortOne.
Use @portone/browser-sdk.// PortOne example
import * as PortOne from '@portone/browser-sdk/v2';
const response = await PortOne.requestPayment({
storeId: 'store-xxxxx',
paymentId: `payment-${Date.now()}`,
orderName: 'LinkHub Pro',
totalAmount: 10000,
currency: 'KRW',
payMethod: 'CARD',
});Which One Should You Choose?
| Situation | Recommendation |
|---|---|
| Global service, developer manages directly | Stripe |
| Global service, delegate tax/refunds | Paddle |
| Solo developer, quick start | Lemon Squeezy |
| Korean user base | Toss Payments |
| Comparing multiple PGs | PortOne |
| International individual customers, simple payments | PayPal |
Vibe Coding Tip
Start with Stripe (global) or Toss Payments (Korea). As you scale and tax handling becomes complex, consider switching to Paddle or Lemon Squeezy.
Chapter Summary
- Understood SaaS revenue models
- Set up Stripe account
- Implemented subscription payments
- Separated free/paid features
- Added subscription management features
- Learned how to manage API and infrastructure costs
- Checked legal requirements
- Learned about various payment options
Congratulations!
You've now completed a SaaS service that can actually generate revenue.
What you learned building LinkHub:
- Vibe Coding - Writing code by chatting with AI
- Database - Storing profiles and links with Supabase
- Authentication - Login/social login
- Real-time Features - Live preview, click analytics
- Security - User data protection, RLS
- Deployment - Launching to the world with Vercel
- Monetization - Making money with Stripe payments
Apply this process to your own ideas!