Skip to content
iD
InfoDive Labs
Back to blog
StartupsSaaSMonetization

SaaS Pricing and Monetization: Technical Implementation Guide

A technical guide to SaaS pricing models, billing system architecture, Stripe integration, usage metering, feature gating, and dunning management.

January 5, 20268 min read

SaaS Pricing and Monetization: Technical Implementation Guide

Pricing is the most underleveraged growth lever in SaaS. While teams invest thousands of hours into product development and marketing, the billing system that captures revenue often gets bolted on as an afterthought - a few Stripe API calls wrapped in spaghetti code that nobody wants to touch. The result is pricing that is hard to change, experiments that are impossible to run, and revenue leakage from failed payments that nobody notices.

This guide covers the technical architecture behind SaaS monetization systems, from choosing a pricing model to building the metering, billing, and entitlement infrastructure that supports it. Whether you are launching a new product or rearchitecting an existing billing system, these patterns will help you build a foundation that scales.

Pricing Models: Choosing the Right Structure

Every pricing model involves trade-offs between simplicity, revenue predictability, and alignment with customer value. Understanding these trade-offs is essential before writing any code.

Flat-rate pricing charges every customer the same monthly or annual fee for full access to the product. It is the simplest model to implement and communicate but leaves money on the table - small customers overpay (and churn), while large customers underpay relative to the value they receive.

Tiered pricing groups features and usage limits into packages (Starter, Pro, Enterprise). Each tier has a fixed price and a defined set of capabilities. This is the most common SaaS pricing model because it balances simplicity with the ability to capture more revenue from larger customers. The engineering challenge is building a robust entitlement system that enforces feature access per tier.

Usage-based pricing charges customers based on how much they consume - API calls, compute hours, storage, seats, or transactions. It aligns cost with value (customers only pay for what they use) and reduces barriers to adoption. However, it makes revenue less predictable and requires accurate, real-time metering infrastructure.

Hybrid pricing combines a base platform fee with usage-based charges. For example, $99/month for the platform plus $0.01 per API call above the included 10,000. This model provides revenue predictability while still capturing upside from heavy users. It is increasingly popular and works well for infrastructure and developer tool products.

Billing System Architecture

A well-designed billing system separates concerns into distinct layers:

Loading diagram...

Metering layer captures raw usage events in real time. This must be highly available, append-only, and idempotent. Use an event streaming architecture (Kafka, Amazon Kinesis, or even a well-designed database queue) to handle spikes in usage data.

Rating and pricing engine applies your pricing rules to raw usage data. It resolves questions like: "This customer is on the Pro plan with a 15 percent annual discount and a custom rate card for API calls - what do they owe?" Keep pricing logic centralized and version-controlled. When pricing changes, existing customers may stay on their current plan, so your system must support multiple active price versions simultaneously.

Invoicing engine generates invoices at the end of each billing period by aggregating rated usage, applying credits and discounts, and calculating taxes. Invoice generation should be idempotent - running it twice for the same period should produce the same result.

Payment gateway processes charges through Stripe, Braintree, or another provider. The integration handles creating and updating payment methods, processing charges, managing refunds, and handling webhook events for payment outcomes.

Stripe Integration Patterns

Stripe is the default payment platform for most SaaS companies, and for good reason - its API is well-designed, documentation is excellent, and it handles the complexity of global payments, tax calculation, and compliance. Here are the integration patterns that matter most.

Use Stripe Billing for subscription management when your pricing is tier-based or seat-based. Stripe handles proration, upgrades, downgrades, and billing cycle management.

// Creating a subscription with Stripe
const subscription = await stripe.subscriptions.create({
  customer: customerId,
  items: [
    { price: 'price_pro_monthly' },  // Base plan
    {
      price: 'price_api_calls',      // Metered usage
      // Usage reported separately via usage records
    },
  ],
  payment_behavior: 'default_incomplete',
  payment_settings: {
    save_default_payment_method: 'on_subscription',
  },
  expand: ['latest_invoice.payment_intent'],
});

Report usage with usage records for metered billing components:

// Report usage for a metered subscription item
await stripe.subscriptionItems.createUsageRecord(
  subscriptionItemId,
  {
    quantity: apiCallCount,
    timestamp: Math.floor(Date.now() / 1000),
    action: 'increment', // or 'set' for gauge metrics
  },
  { idempotencyKey: `usage-${customerId}-${periodId}` }
);

Handle webhooks reliably. Stripe communicates payment outcomes, subscription changes, and invoice events through webhooks. Your webhook handler must be idempotent (processing the same event twice should be safe) and should acknowledge receipt quickly, processing the event asynchronously if needed.

Critical webhook events to handle:

  • invoice.payment_succeeded - Confirm payment, update entitlements
  • invoice.payment_failed - Trigger dunning workflow
  • customer.subscription.updated - Reflect plan changes in your entitlement system
  • customer.subscription.deleted - Revoke access, trigger offboarding

Metering and Usage Tracking

For usage-based pricing, metering accuracy is directly tied to revenue accuracy. Under-counting means lost revenue; over-counting means customer disputes and churn.

Design principles for metering:

  1. Capture events at the source. Instrument your application to emit usage events as close to the actual resource consumption as possible. Do not rely on log parsing or batch estimates.

  2. Make events idempotent. Include a unique event ID so that duplicate events (from retries, network issues, or reprocessing) do not result in double-counting.

  3. Use an append-only event store. Never update or delete usage events. If corrections are needed, emit compensating events. This preserves the full audit trail.

  4. Aggregate close to billing time. Store raw events and aggregate them into billable units during the rating phase. This allows you to change pricing logic retroactively for future billing cycles without modifying raw data.

  5. Provide real-time usage visibility. Customers should be able to see their current usage at any time. Build a read-optimized view (materialized view, cache, or dedicated dashboard database) that updates frequently.

Trial, Freemium, and Feature Gating

Free tiers and trials are critical acquisition levers, but they require careful engineering to avoid abuse and ensure smooth conversion to paid plans.

Time-limited trials grant full (or limited) access for a fixed period. Track trial start and end dates per customer, send conversion nudges at key moments (day 1, midpoint, 3 days before expiry), and define a clear degraded experience when the trial ends.

Freemium models offer a permanently free tier with limited functionality. The engineering challenge is building a feature gating system that cleanly enables and disables capabilities based on the customer's plan.

Implementing feature gates:

// Entitlement service pattern
interface Entitlements {
  plan: 'free' | 'starter' | 'pro' | 'enterprise';
  features: {
    apiAccess: boolean;
    customDomains: boolean;
    ssoIntegration: boolean;
    advancedAnalytics: boolean;
    auditLogs: boolean;
  };
  limits: {
    seats: number;          // -1 for unlimited
    apiCallsPerMonth: number;
    storageBytes: number;
  };
}
 
// Check entitlement before executing feature logic
async function checkEntitlement(
  orgId: string,
  feature: keyof Entitlements['features']
): Promise<boolean> {
  const entitlements = await entitlementService.getForOrg(orgId);
  return entitlements.features[feature] === true;
}
 
// Usage limit enforcement
async function checkUsageLimit(
  orgId: string,
  metric: keyof Entitlements['limits'],
  currentUsage: number
): Promise<{ allowed: boolean; remaining: number }> {
  const entitlements = await entitlementService.getForOrg(orgId);
  const limit = entitlements.limits[metric];
  if (limit === -1) return { allowed: true, remaining: Infinity };
  return {
    allowed: currentUsage < limit,
    remaining: Math.max(0, limit - currentUsage),
  };
}

Key design decisions:

  • Gate at the API layer, not the UI. Hiding a button is not security. Enforce limits server-side and return clear error messages (HTTP 403 with a body indicating the required plan).
  • Cache entitlements aggressively with short TTLs (30-60 seconds). Entitlement checks happen on every request and must be fast.
  • Provide upgrade prompts at the moment of friction. When a user hits a limit, show them exactly what upgrading unlocks.

Dunning Management: Recovering Failed Payments

Failed payments are the largest source of involuntary churn for SaaS businesses. A well-engineered dunning process recovers the majority of failed payments automatically.

Smart retry strategy:

Stripe's Smart Retries use machine learning to determine the optimal time to retry a failed payment. Enable this as a baseline. If implementing custom retry logic, retry on days 1, 3, 5, and 7 after the initial failure, varying the time of day (some payment processors have higher approval rates during business hours).

Communication sequence:

  1. Day 0 - Payment fails. Send a friendly email explaining the issue with a direct link to update payment information.
  2. Day 3 - Second notification. Emphasize that service continuity is at risk.
  3. Day 7 - Final warning. Clearly state that the account will be downgraded or paused if payment is not resolved.
  4. Day 10 - Downgrade to a restricted mode (read-only access, no new data creation) rather than hard-locking the account. Give customers a reason to come back.
  5. Day 30 - If still unresolved, suspend the account but preserve data for 90 days.

In-app notifications are more effective than email alone. Display a banner in the product when payment has failed, with a one-click path to the billing page.

Reduce involuntary churn proactively:

  • Send pre-dunning notifications when a card is about to expire.
  • Use Stripe's automatic card updater, which refreshes expired card details with the issuing bank.
  • Offer multiple payment methods (credit card, ACH/bank transfer, wire for enterprise).

Need help building this?

Our team specializes in turning these ideas into production systems. Let's talk.