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.

Building a Subscription Business as a Developer

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.