Seat-based billing charges customers based on the number of users on their account. Dodo Payments implements it using the add-on system: a base subscription product plus a per-seat add-on whose quantity represents the seat count.
Implementation Tutorial
Step-by-step guide with code examples.
Add-ons Documentation
Learn about the add-on system that powers seat-based billing.
Subscription Management
Manage seat-based subscriptions and plan changes.
Webhooks
Track seat changes with subscription webhooks.
What is Seat-Based Billing?
La facturation à l’usage facture les clients en fonction du nombre d’utilisateurs qui accèdent à votre produit. Au lieu d’un tarif fixe, le prix évolue avec la taille de l’équipe.Common Use Cases
Benefits of Seat-Based Pricing
Pour votre entreprise :- Les revenus augmentent avec la croissance des clients
- Les clients peuvent prévoir leur budget de manière prévisible
- Une voie de mise à niveau claire, de l’offre individuelle à l’offre d’équipe, puis à l’offre entreprise
- Une valeur vie client plus élevée à mesure que les équipes s’agrandissent
- Ils paient uniquement pour les utilisateurs dont ils disposent
- Des coûts faciles à comprendre et à prévoir
- Ils peuvent ajouter ou supprimer des utilisateurs selon leurs besoins
- Une tarification équitable qui correspond à la taille de l’équipe
How It Works
Dodo Payments implements seat-based billing using the Add-ons system. A seat-based subscription has two parts:
The customer’s monthly total is:
Pricing Strategies
Choose the seat-based pricing strategy that fits your business:Strategy 1: Base + Per-Seat Add-on
Include a set number of seats in the base plan, charge for additional seats.Strategy 2: Pure Per-Seat Pricing
Charge a flat rate per seat with no base fee.Strategy 3: Tiered Seat Pricing
Different base plans with different per-seat rates.Strategy 4: Seat Bundles
Sell seats in packs rather than individually.Setting Up Seat-Based Billing
Step 1: Plan Your Pricing
Before implementation, define your pricing structure:1
Define Base Plan
Déterminez ce qui est inclus dans l’abonnement de base :
- Prix de base (peut être de $0 pour une tarification entièrement par siège)
- Nombre de sièges inclus
- Fonctionnalités disponibles à ce niveau
2
Set Seat Pricing
Determine the per-seat add-on cost:
- Price per additional seat
- Any volume discounts (via multiple add-ons)
- Maximum seats allowed (if applicable)
3
Consider Billing Frequency
Align seat pricing with your billing cycle:
- Monthly subscriptions → monthly seat charges
- Annual subscriptions → annual seat charges (often discounted)
Step 2: Create the Seat Add-on
In your Dodo Payments dashboard:- Navigate to Products → Add-Ons
- Click Create Add-On
- Configure the add-on:
Step 3: Create the Base Subscription
Create your subscription product:- Navigate to Products → Create Product
- Select Subscription
- Configure pricing and details
- In the Add-Ons section, attach your seat add-on
Step 4: Attach Add-on to Product
Link the seat add-on to your subscription:- Edit your subscription product
- Scroll to Add-Ons section
- Click Add Add-Ons
- Select your seat add-on
- Save changes
Your subscription product now supports seat-based pricing. Customers can purchase any quantity of additional seats during checkout.
Managing Seats
Adding Seats to New Subscriptions
When creating a checkout session, specify the seat quantity:Changing Seat Count on Existing Subscriptions
Use the Change Plan API to adjust seats. Theaddons array sets the new total seat count (not the delta).
Removing Seats
To reduce seat count, specify the lower quantity:Removing All Additional Seats
Pass an emptyaddons array to remove all add-ons:
Proration for Seat Changes
When a seat change is applied mid-cycle, Dodo Payments calculates the immediate charge in three steps:How Each Mode Credits
Avec
difference_immediately, le client paie uniquement la différence entre le prix de l’ancien plan et celui du nouveau plan. C’est l’origine de ce nom, et c’est pourquoi le montant reste identique, quel que soit le moment du cycle où la modification est effectuée.
If the credit is larger than the new cycle charge, the difference is held as subscription-scoped credit and applied automatically to future renewals.
Worked Example: Adding 5 Seats
One scenario run through all four modes, so the numbers are directly comparable.
Dans les trois modes immédiats, le client reçoit un mois complet au tarif de $130 en échange du montant payé aujourd’hui.
Why Timing Matters for prorated_immediately
The same change costs more the later in the cycle it is made, because less of the current cycle is left to credit back.
The customer receives a full new month in every row. Only the split between “already paid for” and “paying now” changes.
Pour qu’une modification du nombre de sièges coûte le même montant quel que soit le moment où elle intervient, utilisez
difference_immediately.
Worked Example: The “Surprising Charge”
This is the case that most often surprises merchants. Adding a small seat add-on late in the cycle can produce a charge much larger than the add-on’s price.
L’ajout d’un siège à $10/mois coûte $55.00 avec
prorated_immediately. Le client est facturé pour un mois complet au nouveau tarif de $60 et reçoit un crédit de $5 correspondant au montant restant sur l’ancien mois ; sa date de renouvellement est réinitialisée.
Pour que les petits ajouts en cours de cycle coûtent uniquement le prix du siège, sans frais supplémentaires, utilisez difference_immediately.
Worked Example: Removing Seats (Downgrade)
When the new plan costs less than the credit, the excess is held as subscription credit and applied automatically to future renewals of this subscription. It is not added to the Customer Wallet and is not a credit entitlement.Le crédit couvre l’intégralité de l’abonnement, le plan de base et toutes les extensions compris, et pas uniquement les sièges supprimés.
Reading the Preview Response
previewChangePlan returns the exact line items that will be billed. Each line item has a proration_factor:
Proration is calculated to the second based on the exact time of the change, not rounded to the nearest day. The worked examples above use round day-boundary numbers for clarity.
Preview Before Changing
Always preview proration before making changes:Tracking Seats with Webhooks
Monitor seat changes by listening to subscription webhooks:Relevant Events
Webhook Handler Example
Enforcing Seat Limits
Your application must enforce seat limits. Dodo Payments tracks billing, but you control access.- Hard Limit
- Soft Limit with Warning
- Auto-Upgrade
Strictly prevent adding users beyond the seat count.
Advanced Patterns
Different Seat Types
Offer different seat types with different pricing:Annual Seat Discounts
Offer discounted annual seat pricing:Minimum Seat Requirements
Require a minimum number of seats for certain plans:Best Practices
Pricing Best Practices
- Clear Communication: Show per-seat pricing prominently on your pricing page
- Included Seats: Consider including a few seats in the base price to reduce friction
- Volume Discounts: Offer lower per-seat rates for larger teams to win enterprise deals
- Annual Incentives: Discount annual plans to improve cash flow and retention
Technical Best Practices
- Cache Seat Counts: Cache subscription seat counts locally to avoid API calls on every request
- Sync Regularly: Periodically sync your local seat count with Dodo Payments via API
- Handle Failures: If a seat change fails, show clear error messages and retry options
- Audit Trail: Log all seat changes for billing disputes and compliance
User Experience Best Practices
- Retour en temps réel : affichez immédiatement l’impact financier lors de l’ajustement du nombre de sièges
- Étapes de confirmation : demandez une confirmation avant toute modification de facturation
- Transparence sur le prorata : expliquez clairement les frais au prorata avant de les appliquer
- Mises à niveau inférieures faciles : ne rendez pas difficile la réduction du nombre de sièges (cela renforce la confiance)
Troubleshooting
Seat count mismatch between app and billing
Seat count mismatch between app and billing
Symptom: Your app shows a different seat count than the subscription.Causes:
- Webhook not received or processed
- Race condition during seat change
- Cached data not updated
- Implement webhook handlers for
subscription.plan_changed - Add a “Sync with billing” button that fetches current subscription
- Set cache TTL to ensure regular refresh
Unexpected mid-cycle charge amount
Unexpected mid-cycle charge amount
Symptom: Customer confused by mid-cycle charge amount.Cause: Using
prorated_immediately late in the billing cycle (see The Surprising Charge example above).Solutions :- Utilisez toujours
previewChangePlanavant d’effectuer des modifications - Affichez une ventilation claire : “L’ajout de X sièges coûtera $Y aujourd’hui”
- Passez à
difference_immediatelysi vous souhaitez que le montant facturé corresponde toujours à la différence de prix
Add-on not appearing in checkout
Add-on not appearing in checkout
Symptom: Seat add-on not available during checkout.Causes:
- Add-on not attached to product
- Add-on archived or deleted
- Currency mismatch between product and add-on
- Verify add-on is attached in product settings
- Check add-on status in Add-Ons dashboard
- Ensure currencies match exactly
Cannot reduce seats below current usage
Cannot reduce seats below current usage
Symptom: Customer wants to reduce seats but has users assigned.Solutions:
- Show which users must be removed before reducing seats
- Implement a workflow: Remove users → Reduce seats
- Consider a grace period before enforcing seat reduction
Related Documentation
Seat-Based Pricing Tutorial
Complete implementation guide with code.
Add-ons
Understand the add-on system in depth.
Plan Changes & Proration
Handle subscription modifications.
Subscription Webhooks
Track subscription events.