Pricing is a model in your code
Whatever the marketing page says, the codebase needs a single source of truth:
type Plan = {
id: string;
name: string;
basePriceCents: number;
interval: 'month' | 'year';
limits: { seats: number; apiCalls: number; storageGb: number };
features: Set<FeatureFlag>;
};Every entitlement check goes through this model. The pricing page renders from it. The billing system syncs from it.
Freemium
Free is a marketing channel, not a pricing tier. Make sure the free experience clearly maps to a paid upgrade and the upgrade flow is one click.
Per-seat
Easy to understand, easy to bill. The friction: customers under-provision and share accounts. Detect shared sessions; nudge instead of locking out.
Usage-based
- Track every metered event with
tenant_id,timestamp,quantity,unit. - Aggregate hourly or daily; never bill from live writes.
- Always show the customer their running usage and projected bill.
Hybrid
Most SaaS products land on per-seat with usage limits and overages. Build the data model to support this even if you launch with a simpler plan.
Changes and grandfathering
When pricing changes, current customers expect the old terms. Tag each subscription with its pricing version. Migrations are explicit, opt-in, and surfaced in the UI.
Closing
Pricing models change every 18 months. Build the system so changes are configuration, not deploys.