Chapters
7. Monetization

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

ModelDescriptionExamples
SubscriptionMonthly/yearly recurring paymentNetflix, Notion
Usage-basedPay for what you useAWS, OpenAI API
FreemiumFree basics + paid featuresSpotify, LinkedIn
One-time purchasePay onceApps, courses

LinkHub Revenue Model

We'll apply a Freemium + Subscription model:

PlanPriceFeatures
Free$0/month5 links, basic theme
Pro$5/monthUnlimited 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

  1. Sign up at stripe.com
  2. Enter business information
  3. Start in test mode (no real payments)

Create Product and Price

  1. Dashboard → Products → Add product
  2. Name: "LinkHub Pro"
  3. Pricing: Recurring, $5/month
  4. Copy Product ID and Price ID

Check API Keys

Find these in Developers → API keys:

KeyPurposeExpose?
Publishable key (pk_...)FrontendO
Secret key (sk_...)BackendNever

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 DB

Creating 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 verification

7.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 point

7.6 Cost Optimization

Learn how to manage costs for sustainable operations.

API Cost Monitoring

Claude API costs can exceed expectations.

ModelInput (1M tokens)Output (1M tokens)Use Case
Claude Opus$15$75Complex tasks
Claude Sonnet$3$15General tasks (recommended)
Claude Haiku$0.25$1.25Simple 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

ServiceFree TierPaid StartsTips
Vercel100GB bandwidth/month$20/monthPersonal projects fine on free
Railway$5 credit/monthUsage-basedSleep settings reduce costs
Supabase500MB DB, 2GB bandwidth$25/monthUse 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

  1. Test thoroughly in Stripe test mode
  2. Enter real business information
  3. Connect bank account
  4. Switch to live API keys
  5. 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

ServiceFeaturesFeesRecommended For
StripeGlobal standard, developer-friendly2.9% + 30¢Global services
PaddleMoR, handles tax/refunds~5% + 50¢Global SaaS, no tax worries
Lemon SqueezyEasy setup, MoR5% + 50¢Solo developers, quick start
Toss PaymentsOptimized for Korea, various payment methods3.3%Korean user base
PortOne (Iamport)PG integration, multiple PG connectionsVaries by PGComparing multiple PGs
PayPalGlobal recognition, buyer protection3.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?

SituationRecommendation
Global service, developer manages directlyStripe
Global service, delegate tax/refundsPaddle
Solo developer, quick startLemon Squeezy
Korean user baseToss Payments
Comparing multiple PGsPortOne
International individual customers, simple paymentsPayPal
💡

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:

  1. Vibe Coding - Writing code by chatting with AI
  2. Database - Storing profiles and links with Supabase
  3. Authentication - Login/social login
  4. Real-time Features - Live preview, click analytics
  5. Security - User data protection, RLS
  6. Deployment - Launching to the world with Vercel
  7. Monetization - Making money with Stripe payments

Apply this process to your own ideas!

Appendix A: Architecture Guide →