Skip to content
Saad Sultan

Stripe Billing: Subscriptions and Metered Usage

Subscription management, metered usage for contract reviews, webhook handling, and differentiated pricing for standard vs complex reviews in a legal-tech SaaS.

Overview

I built the Stripe-based billing infrastructure for a legal-tech SaaS: subscription management, metered usage for contract reviews, webhook processing for subscription and invoice events, and differentiated pricing so standard and complex reviews could be charged differently. The system supports the product’s usage model while staying within Stripe’s primitives and keeping the backend idempotent and resilient to duplicate events.

Tech Stack

TypeScriptNode.jsStripePostgreSQL

Impact & Scale

  • Customers subscribe with usage-based billing aligned to contract review volume
  • Differentiated pricing for standard vs complex reviews without separate products
  • Webhook-driven subscription and usage sync keeps billing state correct

Key Challenges & Solutions

Metered usage and reporting usage at the right time

Contract reviews can be standard or complex; we needed to report the correct usage to Stripe so invoices reflected actual consumption. We tied usage to completed processing and handled late or retried jobs so we did not double-count or miss usage.

Webhook idempotency and ordering

Stripe can send the same event more than once. We stored processed event IDs and skipped duplicates. For subscription updates we also had to handle out-of-order events (e.g. renewal before update) so the local subscription state stayed consistent.

Differentiated pricing without product sprawl

We wanted one subscription with two usage dimensions (standard vs complex reviews) rather than separate plans. We used Stripe metered billing with multiple usage types so a single invoice could show both and we could apply different unit prices.

Technical Highlights

  • Subscription lifecycle: create, update, cancel, and renewal handling via webhooks
  • Metered usage reporting for standard and complex contract reviews with correct attribution
  • Webhook handler with idempotency and idempotency-key handling to avoid duplicate side effects
  • Differentiated unit prices per usage type so one plan supports tiered pricing
  • Sync of subscription and usage state into our DB for fast UI and reporting

Role and scope

I designed and implemented the billing backend: Stripe customer and subscription creation, metered usage reporting, webhook ingestion, and the local models that mirror subscription and invoice state for the product UI.

Architecture

Customers are created in Stripe when they sign up; subscriptions are created or updated from the product. When a contract review completes, we report usage to Stripe with the appropriate metered dimension (standard or complex). Webhooks for subscription and invoice events update our PostgreSQL tables so the app can show plan status and billing history without calling Stripe on every page load. All webhook handlers are idempotent using Stripe event IDs.

Lessons learned

  • Idempotency is non-negotiable for billing webhooks. Duplicate events would have led to double provisioning or wrong usage. Storing processed event IDs and short-circuiting on replay saved us from subtle bugs.
  • Metered billing fits usage-based products well. One subscription with multiple usage types kept the model simple for customers while still allowing different prices per unit type.
  • Keep a local copy of subscription state. Relying only on Stripe for "what plan is this customer on?" would have made the UI slow and fragile; syncing to our DB gave fast reads and a clear audit trail.

Interested in discussing this project or working together? Get in touch.