Status: Draft
Created: September 2025
Last Updated: September 2025
Summary
Implement seat-based pricing with a single billing manager per company, assignable seats to customers, and a fixed pricing model where each seat costs $X.Goals
- One billing manager can purchase and manage seat quantities for an org.
- Billing managers can assign/unassign seats to customers (end-users) in that org.
- Price is the same for every seat.
- Clear, testable API and data model; minimal billing complexity for app engineers.
- Safe handling of upgrades/downgrades with predictable proration or renewal.
Non-Goals
- Complex multi-organization ownership, resellers/marketplace flows.
- Per-user usage-based charging; this is seat-quantity pricing.
- Handling taxes, refunds, dunning, and receivables beyond provider defaults.
Key Concepts & Assumptions
- Company: Top-level account that owns a subscription.
- Billing Manager: Single user per org with permission to purchase/modify seats.
- Seat: Right to use the product, assignable to a customer record in the org.
- Billing Period: Monthly (assumed); proration rules vary by option.
Seat Assignment Process
Requirements (by priority)
- Creating and configuring a new product with seat based pricing.
- The customer goes to the merchant site and purchases the product.
- Assign a seat to a customer.
- The customer claims his benefit (like a file download).
- The billing customer removes a seat assignment.
- The billing manager upgrades to the annual plan.
- The billing manager decreases the seats.
- The billing manager increases the number of seats.
Open Questions
How should meters work?Should each customer have its own with their limits or should be a global one?
Future State
What to answer:- Flow of purchasing
- Flow of granting
- Flow of revoking
- API
- The tasks that should be created
Option 1 - Adding CustomerSeat
The idea is to add a new entity that isCustomerSeat
. This entity is responsible to link the billing customer and the seat holders. So its main usage is to assign, claim, and revoke seats based on a Seat Based Pricing.
The model is the following:
seat_based
and a new price that is ProductPriceSeatUnit with the following attributes:
Flows
Purchasing
Assigning seat
Claiming & Granting
API
Creating Product
Assign seat
It should look something like:Tasks
- Create new CustomerSeat and PriceSeatUnit. Extend existing models.
- Create new module
seats
with basic operations (assign seat, revoke, etc) - Add the invitation system functionality
- Implement the claim seat functionality
- Avoid granting benefits on checking out seat based products
- Update the checkout to handle the seat based subscriptions
- Add quantity parameter
- Calculate the pricing
- Implement the benefit granting and revocation functionality
- Update Customer Portal for the Billing Manager
- Showing the seats with status
- Showing the functionality of sending invites
- Update Customer Portal for the Customers:
- List the benefits
- Update the Dashboard to allow creating seat based products
- Update the Checkout to allow purchasing seat based
- Update the API endpoints to allow:
- Creating products with seat based
- Assigning seats
- Revoking seats
- Create metrics and alarms
- Update the documentation
Option 2 - Using Customer and Subscriptions model only
The main difference is that the CustomerSeat is stored inside the Subscription model, where:- Billing customer: is the current
customer_id
from Subscription - There is a JSONB column storing CustomerSeats.
- No additional model
- No FK constraints with customers
- Cannot index individual seats
- Complex queries
Option 3 - Using Customer only
We can store the seats on the Customer object itself, by creating a new customer for every seat and having a parent customer who is the owner of the subscription billing.- No need for new entities
- API is confusing with the concept of parent customer.