Why Subscription Billing Is Surprisingly Hard
Subscription billing feels like it should be a solved problem — charge a card every month, done. In reality, billing systems are one of the most complex domains in SaaS engineering. A single subscription can touch proration, tax calculation, dunning sequences, refunds, plan changes, trial management, revenue recognition, and real-time usage metering — all at once.
When a customer upgrades from a $49/month plan to a $149/month plan on day 18 of a 30-day billing cycle, you need to: charge them for the remaining 12 days at the $149 rate, credit them for unused days on the $49 plan, apply the net to their next invoice, update your revenue recognition schedules, and send them a prorated receipt — all while ensuring their access is upgraded instantly. Miss any step and you have an angry customer or an accounting nightmare.
Beyond edge cases, the cost of getting billing wrong is enormous. Failed payments alone cause significant revenue leakage — payments fail for reasons the customer never intended: expired cards, insufficient funds, bank-side fraud blocks, network timeouts. This "involuntary churn" is one of the most underappreciated revenue drains in the SaaS industry.
Beyond failed payments, subscription billing complexity includes: tax compliance across 50+ jurisdictions (EU VAT, US sales tax nexus, AU GST, Canadian GST/HST), currency handling, refund processing, dunning email sequences, plan change proration, metered usage aggregation, deferred revenue accounting, and integration with ERP/accounting systems. The good news: modern billing platforms handle most of this — if you choose and configure them correctly.
Billing Platform Comparison: Stripe vs Paddle vs Chargebee vs Recurly vs Zuora
Choosing the right billing platform is a foundational architectural decision that is expensive to reverse. Here is a detailed comparison of the five major players in 2026, covering merchant-of-record status, transaction fees, tax handling, pricing, and ideal use case.
| Platform | Merchant of Record | Transaction Fee | VAT / Tax | Pricing | Best For | Global Reach |
|---|---|---|---|---|---|---|
| Stripe Billing | No — you are MoR | 0.5% on Starter; 0.8% on Scale | Stripe Tax add-on (~0.5% per transaction) | Pay-as-you-go | Dev-first teams, full control | 195+ countries |
| Paddle | Yes — Paddle is MoR | 5% + $0.50 per transaction | Included — Paddle handles all VAT/GST/sales tax | Revenue share model | B2C SaaS, global tax compliance | 200+ countries |
| Chargebee | No — sits on top of Stripe/Braintree | $0 txn fee (plan-based pricing) | Chargebee Tax (Avalara integration) | $599–$2,000+/mo | Mid-market SaaS, complex billing logic | 180+ countries |
| Recurly | No — sits on top of payment gateways | 0.9% of revenue | Avalara AvaTax integration | $249–$2,000+/mo | B2C subscriptions, high volume | 160+ countries |
| Zuora | No | Enterprise custom pricing | Zuora Tax (Avalara) | Enterprise contract only | Enterprise SaaS, complex quoting | Global |
Merchant of Record (MoR) explained: When Paddle or Lemon Squeezy is the MoR, they appear on the customer's bank statement, handle all VAT/sales tax remittance globally, and absorb chargeback liability. You receive the net amount. This dramatically simplifies compliance for indie developers and small SaaS teams but costs more in transaction fees. Stripe, Chargebee, and Recurly make you the MoR — you are responsible for tax compliance in every jurisdiction where you have nexus.
Lemon Squeezy (now owned by Stripe) is another popular MoR option for indie developers, with a simple 5% + $0.50 per transaction fee and built-in affiliate system. For most early-stage SaaS companies with global ambitions and under $1M ARR, Paddle or Lemon Squeezy often provides the best balance of simplicity and compliance. Above $1M ARR with complex billing needs, Stripe Billing with Stripe Tax becomes cost-effective. Enterprise companies with CPQ (configure-price-quote) requirements typically graduate to Zuora.
Stripe Billing Deep Dive
Stripe Billing is the most developer-friendly and extensible subscription billing system available. Understanding its object model is essential before building on top of it.
Object Hierarchy: Products → Prices → Subscriptions
Stripe's billing model is organized as a three-level hierarchy. A Product represents what you are selling (e.g., "Pro Plan", "Enterprise Plan"). A Price defines how you charge for that product — amount, currency, interval, and billing type. A Subscription links a Customer to one or more Prices and manages the recurring billing lifecycle.
Price Types
- Flat rate$49/month — fixed price regardless of usage or seats.
- Per seat (per_unit)$15/user/month — multiply unit amount by quantity. Quantity updated when seats change.
- Metered (usage-based)Price based on reported usage events. Aggregated at end of billing period into invoice.
- TieredVolume or graduated pricing — different rates at different usage thresholds.
- One-timeNon-recurring charge. Can be added to a subscription invoice as an add-on.
Creating a Subscription — Node.js Example
Stripe Meters API (Usage-Based Billing — GA 2025)
Stripe's Meters API (released to general availability in mid-2025) replaces the older Usage Records API with a more robust, idempotent event-driven system. Instead of reporting a cumulative usage count, you emit discrete events that Stripe aggregates according to the meter's aggregation type.
Critical Webhooks to Handle
customer.subscription.createdProvision access, send welcome email, set trial end date in your DB.customer.subscription.updatedHandle plan change: update feature flags, adjust seat count, refresh entitlements.customer.subscription.deletedDeprovision access, trigger offboarding flow, export user data if requested.invoice.payment_succeededMark payment received, send receipt, reset dunning state, extend access.invoice.payment_failedTrigger dunning sequence: email customer, schedule retries, optionally restrict features.invoice.finalizedInvoice is locked and sent to customer. Good time to post to accounting system.customer.subscription.trial_will_endFires 3 days before trial ends. Prompt to add payment method.Always validate webhook signatures using stripe.webhooks.constructEvent() and handle idempotency — Stripe may retry webhooks for up to 72 hours. Store processed event IDs and skip duplicates. Use a queue (SQS, BullMQ) rather than processing webhooks inline to avoid timeout failures.
Dunning Management: Recovering Failed Payments
"Dunning" is the process of communicating with customers and retrying payment collection after an initial payment failure. It is one of the highest ROI activities in subscription billing — recovering even 30-40% of failed payments translates directly to ARR that would otherwise vanish silently.
Payment failures fall into two categories: hard declines (stolen card, account closed — do not retry) and soft declines (insufficient funds, do not honor temporarily, card network timeout — retry is appropriate). Your dunning logic must distinguish between them.
Stripe Smart Retries vs Manual Retry Schedule
ML-powered retry scheduling that analyzes the optimal time to retry based on card network signals, time of day, day of week, and historical recovery patterns. Stripe's data shows Smart Retries recover 38% more failed payments than fixed retry schedules.
- 3–4 retry attempts over 7 days
- Adaptive timing based on card type
- Avoids retry storms (all at midnight)
- Enable: set
smart_retries: truein subscription settings
When you need full control over retry timing (e.g., custom business rules), define your own schedule via the Stripe API or Chargebee/Recurly dunning settings.
- Day 0: Initial failure — soft notification
- Day 3: First retry + email reminder
- Day 7: Second retry + stronger email
- Day 14: Third retry + final warning
- Day 28: Final retry or cancel subscription
Dunning Email Sequence
Pause vs Cancel Flow
Before hard-canceling a subscription, offer the customer a pause option. Stripe supports pausing billing (but not access) for up to 3 months. Many users who would otherwise churn will take the pause — and resume paying without any intervention from your team. Implement this in your cancellation flow as a "Take a break?" option shown before the final cancellation confirmation.
Account Updater: Stripe automatically contacts card networks to get updated card details when a card expires or is replaced. Enable this in your Stripe Dashboard — it silently recovers many cards that would otherwise hard-fail without the customer ever knowing there was an issue. Reduces involuntary churn from card expiry by ~15-20%.
Metered / Usage-Based Billing
Usage-based billing (UBB) — where customers pay based on what they consume rather than a flat subscription rate — is the fastest growing pricing model in SaaS. Companies like Twilio, Cloudflare, AWS, and Stripe itself pioneered it; now it is table stakes for API businesses and increasingly popular for AI and analytics SaaS.
Stripe's Meters API (GA 2025) provides a production-ready infrastructure for usage-based billing. The architecture involves three components: a Meter definition (what you are measuring and how to aggregate it), Meter Events (individual usage occurrences you report), and a metered Price (how much each unit costs, attached to a subscription).
Stripe Meters API Workflow
stripe.billing.meters.create()billing_scheme: "per_unit"stripe.billing.meterEvents.create()invoice.finalized webhookAggregation Types
summaxlast_during_periodReal-World Examples
Implement usage alerts proactively — notify customers at 80% and 100% of any included usage threshold. This reduces bill shock churn (customers who cancel after seeing an unexpected invoice) and creates natural upsell opportunities. Stripe's usage-based billing allows defining soft and hard caps at the Price level.
Proration Logic: Handling Plan Changes Correctly
Proration is the calculation of partial-period charges and credits when a customer changes plans mid-billing-cycle. Getting this wrong creates customer service tickets, accounting errors, and trust issues. Stripe handles proration automatically — but you must understand which behavior to configure for each scenario.
Customer upgrades from $49/mo to $149/mo on day 18 of a 30-day cycle (12 days remaining).
- Credit: 12/30 × $49 = $19.60 unused old plan
- Charge: 12/30 × $149 = $59.60 new plan remainder
- Net charge immediately: $59.60 − $19.60 = $40.00
- Next invoice: full $149/mo on renewal date
Customer downgrades from $149/mo to $49/mo on day 18 of a 30-day cycle (12 days remaining).
- Credit: 12/30 × $149 = $59.60 unused old plan
- Charge: 12/30 × $49 = $19.60 new plan remainder
- Net credit: $59.60 − $19.60 = $40.00 applied to next invoice
- No immediate charge — credit balance carries forward
Stripe proration_behavior Options
'create_prorations'Default. Creates proration invoice items immediately. Customer charged/credited on current or next invoice.'always_invoice'Creates proration items AND immediately finalizes and pays an invoice. Good for upgrades where you want instant charge.'none'No proration. Plan change takes effect at next renewal. Best for downgrade UX — do not charge/credit mid-cycle.Edge case — upgrade on last day of billing cycle: If a customer upgrades on the last day of the cycle, the prorated charge for "remaining days" is nearly zero (1/30 × price difference). This means they get the upgraded plan for almost a full month before being charged the full new price. Decide upfront whether this is acceptable or if you want to use 'always_invoice' to ensure immediate billing and a clean monthly cycle reset.
Revenue Recognition: ASC 606 & IFRS 15 for SaaS
Revenue recognition is an accounting principle that determines when you can record revenue on your income statement. For SaaS companies, this is governed by ASC 606 (US GAAP) and IFRS 15 (international). Getting this right is critical for: accurate financial reporting, investor due diligence, and avoiding accounting restatements.
The core principle: recognize revenue when (or as) performance obligations are satisfied. For subscriptions, you are delivering ongoing access to software — so revenue is recognized ratably (evenly) over the subscription period, not all at once when payment is received.
Stripe Revenue Recognition
Stripe's Revenue Recognition add-on automatically generates GAAP-compliant journal entries for all Stripe transactions. It handles deferred revenue waterfall schedules, plan changes, refunds, and disputes — eliminating the manual spreadsheet reconciliation that kills finance teams at $1M+ ARR.
Accounting System Integration
Global Tax Compliance for SaaS
Tax compliance is the silent killer of SaaS companies that scale internationally without legal guidance. The rules differ by country, by product type (digital goods vs software vs services), by B2B vs B2C, and by revenue threshold. Here is a practical breakdown of the major jurisdictions you will encounter.
No federal sales tax. Each state sets its own rules. "Economic nexus" created by $100K revenue OR 200+ transactions in a state per year. Once nexus is established, you must register, collect, and remit sales tax in that state. SaaS is taxable in ~35 states (definitions vary — "prewritten software" vs "custom software" vs "SaaS" treated differently by state).
VAT rates range from 17% (Luxembourg) to 27% (Hungary). If you sell B2C digital services to EU customers, you must register for VAT OSS (One Stop Shop) once you exceed €10,000 in EU cross-border sales. B2B sales: apply reverse charge (customer self-accounts for VAT with their VAT number). Always collect and validate VAT IDs from B2B customers.
Federal GST at 5%. Provinces with HST (Ontario, BC, etc.) add provincial portion for combined rates of 12-15%. Quebec charges QST separately (9.975%). Register when annual worldwide taxable supplies exceed $30,000 CAD. Non-resident digital service providers supplying B2C customers in Canada must register even without a physical presence.
Flat 10% GST on all digital services sold to Australian consumers. Register for GST if you make more than AUD $75,000 in annual turnover in Australia. Non-resident suppliers can register through the ATO's simplified GST registration system. B2B supplies to GST-registered businesses use reverse charge.
Indian GST at 18% on digital services (OIDAR — Online Information and Database Access or Retrieval services). Foreign suppliers must register under the simplified GST registration for OIDAR services. Collect GSTIN (GST Identification Number) from B2B customers — allows them to claim input tax credit. Display GSTIN on invoices.
Recommendation for early-stage startups: Use Paddle or Lemon Squeezy (Merchant of Record) to avoid all tax registration and remittance complexity until you reach $500K-$1M ARR and have a dedicated finance/legal team. The 5% transaction fee is cheaper than the cost of tax compliance infrastructure and risk of non-compliance penalties.
SaaS Billing Analytics: Metrics That Matter
Your billing system is also your most accurate business intelligence source. The metrics derived from subscription data — not website analytics — are what investors look at and what drive strategic decisions. Here are the key metrics every SaaS team must track, with formulas.
Analytics Tools
Frequently Asked Questions
Need Help Architecting Your Billing System?
Codazz has helped 30+ SaaS companies design and implement subscription billing systems — from Stripe Billing setup to metered usage engines to global tax compliance. Book a free 30-minute billing architecture review.
Book Free Billing Architecture Review