---
name: "SaaS Billing & Subscriptions"
description: "Implement SaaS billing: Stripe Billing (Products, Prices, Subscriptions), subscription lifecycle, dunning (failed payments), tax handling (Stripe Tax, Paddle MoR), metered/usage billing, enterprise invoicing, revenue recognition, and MRR/churn metrics."
version: "1.0.0"
author: "skynet"
category: "dev"
agents: ["claude-code", "codex", "gemini"]
tags: ["saas", "billing", "stripe", "subscriptions", "payments", "mrr"]
---

# SaaS Billing & Subscriptions

---
name: "SaaS Billing & Subscriptions"
description: "Implement SaaS billing: Stripe Billing (Products, Prices, Subscriptions), subscription lifecycle, dunning (failed payments), tax handling (Stripe Tax, Paddle MoR), metered/usage billing, enterprise in"
version: "1.0.0"
author: "skynet"
category: "dev"
tags: ["saas", "billing", "stripe", "subscriptions", "payments", "mrr"]
---

# SaaS Billing & Subscription Management: Technical Reference

Implementing billing is one of the most critical and complex components of a SaaS architecture. It requires high consistency, security, and a deep understanding of the subscription lifecycle.

## 1. Billing Models

| Model | Description | Technical Implementation |
| :--- | :--- | :--- |
| **Flat Subscription** | Fixed price per interval (e.g., $50/mo). | Single `Price` attached to a `Subscription`. |
| **Per-Seat** | Price multiplied by quantity of users. | `SubscriptionItem` with a `quantity` field; update via webhooks when users are added/removed. |
| **Usage-Based** | Pay for consumption (e.g., per API call). | `Price` with `usage_type=metered`. Requires reporting usage records to the provider. |
| **Credits/Prepaid** | Users buy tokens/credits upfront. | Internal ledger in your DB; decremented as used. Often integrated with "top-up" one-time purchases. |
| **Hybrid** | Base platform fee + usage overages. | Multiple `Prices` on one `Subscription`: one fixed, one metered. |
| **Add-ons** | Optional features (e.g., "Priority Support"). | Supplemental `SubscriptionItems` or one-time `InvoiceItems`. |

---

## 2. Stripe Billing Architecture

Stripe is the industry standard for developer-first billing. Its object hierarchy is:
`Customer` -> `Product` -> `Price` -> `Subscription`.

### Subscription Lifecycle States
- **`trialing`**: Active but not yet billed.
- **`active`**: Payment successful, service granted.
- **`past_due`**: Renewal failed; entering dunning.
- **`unpaid`**: Dunning failed; service usually revoked here.
- **`canceled`**: Explicitly terminated.
- **`incomplete`**: First payment failed (for SCA/3D Secure flows).

### Stripe Implementation (Node.js)
```typescript
// Create a Checkout Session for a new subscription
const session = await stripe.checkout.sessions.create({
  customer: 'cus_123',
  payment_method_types: ['card'],
  line_items: [{ price: 'price_H5ggfxyz', quantity: 1 }],
  mode: 'subscription',
  success_url: 'https://app.com/success?session_id={CHECKOUT_SESSION_ID}',
  cancel_url: 'https://app.com/canceled',
  subscription_data: { trial_period_days: 14 },
});
```

---

## 3. Alternative Platforms

### Merchant of Record (MoR)
MoRs take legal responsibility for the transaction, handling global sales tax, VAT, and compliance.
- **Paddle**: Excellent for global SaaS; handles all VAT/GST. Unified billing/overlay.
- **LemonSqueezy**: High-growth MoR; very indie-friendly, simpler API than Stripe.

### Enterprise & Management Layers
- **Chargebee / Recurly**: Orchestration layers that sit on top of gateways (Stripe/Adyen). Provide advanced revenue recognition and complex logic.
- **Maxio**: Focused on B2B SaaS metrics and financial operations.

---

## 4. Subscription Lifecycle Management

### Proration Strategies
When a user switches plans mid-cycle:
1. **Always Invoice**: Immediately charge/credit the difference.
2. **Defer to Next Cycle**: Calculate the difference but apply it to the next invoice.
3. **No Proration**: Simple "switch at end of period."

**Stripe Proration Example:**
```typescript
const subscription = await stripe.subscriptions.update('sub_123', {
  items: [{
    id: 'si_abc', // existing item
    price: 'price_new_premium',
  }],
  proration_behavior: 'always_invoice', // Charge immediately
});
```

---

## 5. Dunning & Failed Payments

Dunning is the process of communicating with customers to recover failed payments.
- **Smart Retries**: Stripe's "Smart Retries" use ML to attempt charges at optimal times.
- **Grace Periods**: Allow 3–7 days of access while `past_due`.
- **Card Updater**: Stripe/Braintree automatically update expired card details via network partnerships.
- **Webhook Workflow**:
    - `invoice.payment_failed` -> Send "Action Required" email.
    - `customer.subscription.updated` (status: `unpaid`) -> Revoke app access.

---

## 6. Tax Handling

SaaS is taxable in most jurisdictions (Nexus in US, VAT in EU).
- **Stripe Tax**: Automatically calculates and collects tax based on customer address.
- **TaxJar / Avalara**: Specialized tax engines for complex nexus scenarios.
- **The MoR Advantage**: If using Paddle/LemonSqueezy, you don't need these; they act as the seller and remit all taxes.

---

## 7. Metered Billing (Usage Tracking)

**Pattern: Event-Based Reporting**
Don't calculate the bill yourself. Send "events" to Stripe and let it aggregate.

```typescript
// Report 50 units of "API Calls" used today
await stripe.subscriptionItems.createUsageRecord('si_123', {
  quantity: 50,
  timestamp: Math.floor(Date.now() / 1000),
  action: 'increment', // 'set' replaces the previous value
});
```
- **Aggregation**: Choose `sum` (total units), `last_during_period` (current state), or `max`.

---

## 8. Enterprise Billing Requirements

Enterprise customers rarely use credit cards.
- **Invoice Billing**: Payment terms like **Net 30** or **Net 60**.
- **Purchase Orders (PO)**: Requiring a PO number on the generated PDF.
- **Custom Contracts**: Negotiated pricing that doesn't exist on your public pricing page (use "Ad-hoc" prices in Stripe).
- **Consolidated Billing**: One "Parent" company paying for multiple "Child" departments/entities.

---

## 9. Key SaaS Metrics (The "North Stars")

- **MRR / ARR**: Monthly/Annual Recurring Revenue.
- **Churn Rate**:
    - **Logo Churn**: % of customers leaving.
    - **Revenue Churn**: % of MRR lost.
- **Net Revenue Retention (NRR)**: (Starting MRR + Expansion - Contraction - Churn) / Starting MRR. Target > 100%.
- **LTV (Lifetime Value)**: `ARPU (Average Revenue Per User) / Churn Rate`.
- **CAC (Customer Acquisition Cost)**: Total Sales & Marketing / New Customers.

---

## 10. Revenue Recognition (ASC 606)

Under ASC 606, you cannot recognize a $1,200 annual payment the day you receive it.
- **Deferred Revenue**: The $1,100 remaining after month 1.
- **Recognized Revenue**: $100 per month for 12 months.
- **Implementation**: Ensure your billing system (or a tool like ProfitWell/ChartMogul) handles the "Earned vs. Unearned" logic for accounting compliance.

---

## 11. Architectural Best Practices

1. **Webhook Idempotency**: Stripe may send the same webhook twice. Always check `event.id` against a processed events table in your DB.
2. **Don't Store CC Data**: Use Stripe Elements or Checkout. Your servers should never see raw card numbers (PCI compliance).
3. **Sync State via Webhooks**: Your DB should be a "read-only" mirror of Stripe's state for fast authorization checks (e.g., `user.is_subscribed = true`).
4. **The "Portal" Pattern**: Use the **Stripe Customer Portal** to outsource 90% of your self-service UI (changing plans, updating cards, downloading invoices).

```typescript
// Generate a link to the hosted Customer Portal
const portalSession = await stripe.billingPortal.sessions.create({
  customer: 'cus_123',
  return_url: 'https://app.com/settings',
});
// Redirect user to portalSession.url
```

