Usage-Based Billing in SaaS: Designing a Scalable Metering System
Most developers assume SaaS billing is just integrating Stripe. In reality, Stripe only handles payments. The real challenge is tracking usage accurately and enforcing limits in your backend.
If your metering system is weak, you either lose revenue or break user experience. This becomes critical as your SaaS scales.
What is Metering?
Metering is the process of tracking how much a tenant uses your system. This can include API calls, storage, feature usage, background jobs, or any billable action.
Every billing system depends on this layer. Without reliable metering, billing logic becomes inaccurate.
Core Flow of Usage-Based Billing
A typical backend flow looks like this: request comes in → validate tenant → check usage → process request → record usage → sync billing.
- Validate tenant from authentication
- Check current usage against plan limits
- Allow or reject request
- Track usage event
- Aggregate usage for billing
Tracking Usage Per Tenant
Usage tracking must be fast and scalable. Redis is commonly used because it supports atomic increments and low latency.
This approach works well for real-time enforcement but should be backed by persistent storage for billing records.
Enforcing Limits Before Execution
Limits should always be checked before executing the main business logic. This prevents unnecessary load and ensures predictable system behavior.
You can also implement soft limits (warnings) and hard limits (blocking requests).
Async Usage Tracking with Queues
Writing usage directly to a database for every request does not scale. Instead, emit events and process them asynchronously using queues or Kafka.
Workers can batch and persist this data efficiently, reducing database load.
Handling Idempotency and Duplicates
In distributed systems, duplicate events are common. Your metering system must handle retries safely.
- Use idempotent event processing
- Store unique request IDs
- Avoid double-counting usage
- Design consumers to be retry-safe
Stripe Integration (Where It Fits)
Stripe should only handle billing and invoicing. Your backend should calculate usage and send aggregated data to Stripe.
Never depend on Stripe to track your usage logic. It does not understand your domain.
Scaling Considerations
- Use Redis for real-time counters
- Use Kafka or queues for async aggregation
- Persist usage data in database for billing history
- Separate billing service from core business logic
- Monitor usage per tenant for anomaly detection
Common Mistakes
- Not tracking usage from day one
- Mixing billing logic with application logic
- Relying only on Stripe for metering
- Ignoring retries and duplicate events
- Not designing for scale early
Conclusion
Usage-based billing is a system design problem, not just a payment feature. If your metering is accurate, scalable, and reliable, your billing system becomes simple and predictable.
If it is not, you will either lose revenue or damage user trust.