Introduction


Subscription-based business models generate predictable recurring revenue and are the dominant monetization strategy for SaaS products. As a developer, your technical skills give you a significant advantage in building, measuring, and optimizing a subscription business. This guide covers the essential components from pricing strategy to billing implementation and metric tracking.


Pricing Tier Design


Effective pricing tiers balance value capture with customer acquisition:



# Pricing strategy framework

tiers:

  free:

    monthly_price: 0

    features:

      - Up to 100 API calls/day

      - 7-day data retention

      - Community support

    limitations:

      - No custom domains

      - Rate limit: 10 req/min

    goal: "Acquisition and onboarding"

  pro:

    monthly_price: 29

    features:

      - Up to 10,000 API calls/day

      - 90-day data retention

      - Email support (24h response)

      - Custom domains

    limitations: []

    goal: "Primary revenue driver"

  team:

    monthly_price: 99

    features:

      - Up to 100,000 API calls/day

      - 1-year data retention

      - Priority support (4h response)

      - Team accounts (up to 5 seats)

      - API analytics dashboard

    limitations: []

    goal: "Team adoption and expansion"

  enterprise:

    monthly_price: null  # Custom pricing

    features:

      - Unlimited API calls

      - Unlimited retention

      - Dedicated support engineer

      - SSO/SAML

      - Custom SLA

      - On-premise option

    limitations: []

    goal: "High-value accounts"


Pricing psychology tips:

  • **Decoy effect**: offer three tiers where the middle one is your target
  • **Annual discount**: 20-30% discount for annual billing improves cash flow and reduces churn
  • **Usage-based caps**: set fair usage limits that encourage upgrades

  • Stripe Billing Integration


    
    // Stripe subscription management
    
    import Stripe from 'stripe';
    
    
    
    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
    
      apiVersion: '2025-09-01',
    
    });
    
    
    
    // Create a checkout session for subscription
    
    async function createCheckoutSession(
    
      customerId: string,
    
      priceId: string,
    
      successUrl: string,
    
      cancelUrl: string
    
    ) {
    
      const session = await stripe.checkout.sessions.create({
    
        customer: customerId,
    
        mode: 'subscription',
    
        line_items: [{
    
          price: priceId,
    
          quantity: 1,
    
        }],
    
        subscription_data: {
    
          metadata: {
    
            source: 'direct_checkout',
    
            plan_tier: priceId === PRICE_PRO_MONTHLY ? 'pro' : 'team',
    
          },
    
          trial_period_days: 14,
    
        },
    
        success_url: successUrl,
    
        cancel_url: cancelUrl,
    
      });
    
    
    
      return session.url;
    
    }
    
    
    
    // Handle subscription lifecycle via webhooks
    
    async function handleSubscriptionWebhook(event: Stripe.Event) {
    
      switch (event.type) {
    
        case 'customer.subscription.created':
    
          await onSubscriptionCreated(event.data.object);
    
          break;
    
        case 'customer.subscription.updated':
    
          await onSubscriptionUpdated(event.data.object);
    
          break;
    
        case 'customer.subscription.deleted':
    
          await onSubscriptionCancelled(event.data.object);
    
          break;
    
        case 'invoice.payment_failed':
    
          await onPaymentFailed(event.data.object);
    
          break;
    
        case 'invoice.payment_succeeded':
    
          await onPaymentSucceeded(event.data.object);
    
          break;
    
      }
    
    }
    
    
    
    async function onPaymentFailed(invoice: Stripe.Invoice) {
    
      // Send dunning emails
    
      if (invoice.attempt_count === 1) {
    
        await sendEmail({
    
          to: invoice.customer_email,
    
          subject: "Payment failed - please update your billing info",
    
          template: "payment_failed_first_attempt",
    
        });
    
      }
    
    
    
      // Notify via Slack for manual follow-up
    
      if (invoice.attempt_count >= 3) {
    
        await notifySlack(
    
          `Payment failed 3 times for ${invoice.customer_email}. ` +
    
          `Subscription may be downgraded soon.`
    
        );
    
      }
    
    }
    
    

    Churn Reduction Strategies


    Track churn with event analytics and implement proactive retention:


    
    // Churn prediction and intervention
    
    interface ChurnRiskFactors {
    
      daysSinceLastLogin: number;
    
      apiCallDeclinePercent: number;
    
      supportTicketsOpen: number;
    
      paymentFailures: number;
    
    }
    
    
    
    function calculateChurnRisk(factors: ChurnRiskFactors): 'low' | 'medium' | 'high' {
    
      let score = 0;
    
    
    
      // Login frequency
    
      if (factors.daysSinceLastLogin > 14) score += 2;
    
      if (factors.daysSinceLastLogin > 30) score += 3;
    
    
    
      // Usage decline
    
      if (factors.apiCallDeclinePercent > 50) score += 2;
    
    
    
      // Support issues
    
      if (factors.supportTicketsOpen > 2) score += 2;
    
    
    
      // Billing problems
    
      if (factors.paymentFailures > 0) score += 3;
    
    
    
      if (score >= 5) return 'high';
    
      if (score >= 3) return 'medium';
    
      return 'low';
    
    }
    
    
    
    async function applyChurnIntervention(userId: string, risk: ChurnRiskFactors) {
    
      // Schedule automated outreach
    
      if (risk.daysSinceLastLogin > 7) {
    
        await sendEmail({
    
          userId,
    
          template: "we_miss_you",
    
          delay: risk.daysSinceLastLogin > 14 ? 0 : 24 * 60 * 60 * 1000,
    
        });
    
      }
    
    
    
      // Offer downgrade path before cancel
    
      if (risk.paymentFailures > 0) {
    
        await offerDowngradeTier(userId);
    
      }
    
    }
    
    

    Customer Lifecycle


    Map the customer journey from acquisition to expansion:


    
    Acquisition → Activation → Retention → Revenue → Referral
    
        |            |           |          |          |
    
      Landing     First       Monthly    Upgrade    Share with
    
      page        value       check-in   prompts    friends
    
    

    Automate each stage:


    
    async function handleCustomerLifecycle(userId: string, daysSinceSignup: number) {
    
      switch (true) {
    
        case daysSinceSignup === 0:
    
          // Send welcome email with getting started guide
    
          await sendWelcomeSequence(userId);
    
          break;
    
        case daysSinceSignup === 3:
    
          // Check if they've used key features
    
          const usage = await getUserUsage(userId);
    
          if (usage.apiCalls === 0) {
    
            await sendOnboardingReminder(userId);
    
          }
    
          break;
    
        case daysSinceSignup === 14:
    
          // Trial ending soon
    
          await sendTrialEndingEmail(userId);
    
          break;
    
        case daysSinceSignup === 30:
    
          // One-month review: ask for feedback
    
          await sendNpsSurvey(userId);
    
          break;
    
        case daysSinceSignup % 90 === 0:
    
          // Quarterly check-in
    
          if (isPowerUser(userId)) {
    
            await suggestUpgrade(userId);
    
          }
    
          break;
    
      }
    
    }
    
    

    Key SaaS Metrics


    | Metric | Formula | Target | Why It Matters |

    |---|---|---|---|

    | MRR | Monthly recurring revenue | Growing 10-20% month-over-month | Core health metric |

    | ARR | MRR x 12 | >$100K for seed stage | Annual run rate |

    | LTV | ARPU / Churn Rate | >3x CAC | Customer lifetime value |

    | CAC | Sales + Marketing / New Customers | <$500 for self-serve | Cost to acquire |

    | NDR | Net Dollar Retention | >100% | Expansion minus contraction |

    | Churn Rate | Cancelled / Total Customers | <5% monthly | Revenue retention |


    Track these with a simple dashboard:


    
    -- Monthly recurring revenue calculation
    
    SELECT
    
      DATE_TRUNC('month', subscription_start) AS month,
    
      COUNT(*) AS customers,
    
      SUM(monthly_price) AS mrr,
    
      SUM(monthly_price) * 12 AS arr
    
    FROM subscriptions
    
    WHERE status = 'active'
    
    GROUP BY 1
    
    ORDER BY 1 DESC;
    
    
    
    -- Churn rate
    
    SELECT
    
      DATE_TRUNC('month', cancelled_at) AS month,
    
      COUNT(*)::float /
    
        (SELECT COUNT(*) FROM subscriptions
    
         WHERE status = 'active'
    
           AND subscription_start < DATE_TRUNC('month', s.cancelled_at))
    
      AS churn_rate
    
    FROM subscriptions s
    
    WHERE status = 'cancelled'
    
    GROUP BY 1
    
    ORDER BY 1 DESC;
    
    

    Start with a simple pricing model (one paid tier), launch with Stripe's pre-built checkout, and focus on the first $1K MRR before optimizing pricing or building complex billing logic.