How to Set Up Per-Seat Pricing in Stripe: Complete Implementation Guide 2026

How to Set Up Per-Seat Pricing in Stripe: Complete Implementation Guide 2026
Sjorsfest
Sjorsfest

Startup engineer with 8+ years of experience building and shipping products. Now an independent builder creating tools for small companies and indie makers, including Donkey Support: a support chat widget for teams that live in Slack, Discord, and Telegram.

Per-seat pricing is one of the most common SaaS billing models, and Stripe makes it surprisingly flexible to implement. Whether you're building a team productivity tool, a developer platform, or a collaboration app, this guide walks you through everything: what per-seat pricing is, when to use it, how to configure it in the Stripe dashboard, and how to wire it up via the API. By the end, you'll have a working per-seat subscription setup and a clear picture of the edge cases to watch out for.

What You'll Learn

  • What per-seat pricing is and when it's the right model for your SaaS
  • How per-seat compares to flat-rate and usage-based billing
  • Step-by-step dashboard setup for per-seat products in Stripe
  • API code examples in Node.js and Python for creating and updating per-seat subscriptions
  • How pro-rating works when seats change mid-cycle
  • Advanced scenarios: tiered discounts, add-ons, and enterprise licensing
  • Best practices and common pitfalls to avoid
  • Real-world pricing examples with actual numbers

What is Per-Seat Pricing and When to Use It

Per-seat pricing (also called per-user pricing) charges customers based on the number of users or seats in their account. If a team has 10 people using your app and your price is $15 per seat per month, they pay $150/month. Simple.

This model works really well when your product's value scales with team size. More users means more value delivered, so it makes sense to charge accordingly. It also gives you predictable, scalable revenue as your customers grow.

Ideal use cases for per-seat billing include team productivity apps (think project management or wikis), collaboration platforms, developer tools used by engineering teams, CRM and sales software, and any SaaS where individual logins are a core part of the experience.

Compared to flat-rate pricing, per-seat billing scales better with customer growth. Compared to usage-based pricing, it's more predictable for both you and your customers. The trade-off is that customers sometimes try to share accounts to avoid paying for more seats, so you'll want to think about how you enforce seat limits.

Per-Seat Pricing vs. Other Models: Comparison

ModelHow It WorksProsConsBest For
Flat-RateOne fixed price regardless of usersSimple to sell, easy to predictDoesn't scale with usage; small teams subsidize large onesSimple tools, solo users, commoditized products
Per-SeatPrice multiplied by number of users/seatsScales with customer growth, aligns cost with value deliveredCustomers may share accounts; churn risk if teams shrinkTeam tools, collaboration apps, B2B SaaS with multiple users
Usage-BasedCharged by API calls, events, or consumptionCustomers pay for what they use; low barrier to startUnpredictable revenue; hard to forecast for customersInfrastructure, APIs, data platforms, developer tools
HybridCombines base fee + per-seat or usage overageFlexible, can capture both predictable and variable revenueMore complex to communicate and implementEnterprise SaaS, platforms with both core and expanded usage

Step-by-Step: Configuring Per-Seat Pricing in Stripe Dashboard

  1. 1Log in to your Stripe Dashboard and navigate to Products (found under the Billing section in the left sidebar).
  2. 2Click 'Add product' and give your product a name (for example, 'Team Plan'). Add a description if you want it to show up in customer-facing invoices.
  3. 3Under 'Pricing', select 'Recurring' as the billing type and choose your billing interval (monthly or annual).
  4. 4Set the unit price (for example, $15.00 per unit). This is the price per seat.
  5. 5In the 'Usage type' field, select 'Licensed'. This tells Stripe that quantity represents the number of seats you're billing for.
  6. 6Optionally, configure a free trial period under 'Trial period days'. For example, enter '14' for a 14-day free trial.
  7. 7To add volume discounts, click 'Add tier' under the pricing section and configure tiered pricing (for example, $15/seat for 1-10 seats, $12/seat for 11-50 seats).
  8. 8Click 'Save product'. Your per-seat price is now ready to attach to subscriptions.
  9. 9To apply a coupon or discount, go to Billing > Coupons, create a coupon (fixed or percentage off), and apply it when creating or updating a subscription.

Code Examples: Setting Up Per-Seat Subscriptions via API

Once your product and price are configured in Stripe, you can create per-seat subscriptions programmatically. The key is the quantity parameter, which tells Stripe how many seats the customer is subscribing to.

Here's how to create a per-seat subscription in Node.js (using the stripe npm package):

const stripe = require('stripe')('sk_live_your_secret_key');

// Create a per-seat subscription
const subscription = await stripe.subscriptions.create({
  customer: 'cus_customer_id',
  items: [
    {
      price: 'price_your_price_id', // the price ID from your Stripe dashboard
      quantity: 5, // number of seats
    },
  ],
  trial_period_days: 14, // optional: 14-day free trial
});

console.log(subscription.id);

And here's the same thing in Python:

import stripe

stripe.api_key = 'sk_live_your_secret_key'

subscription = stripe.Subscription.create(
    customer='cus_customer_id',
    items=[
        {
            'price': 'price_your_price_id',  # price ID from Stripe dashboard
            'quantity': 5,  # number of seats
        },
    ],
    trial_period_days=14,  # optional
)

print(subscription['id'])

To update the seat count mid-subscription (for example, when a customer adds a new team member), use the subscription item update endpoint:

// Update seat count (Node.js)
const updatedSubscription = await stripe.subscriptions.update(
  'sub_subscription_id',
  {
    items: [
      {
        id: 'si_subscription_item_id',
        quantity: 8, // new seat count
      },
    ],
    proration_behavior: 'create_prorations', // handles mid-cycle charges
  }
);

The proration_behavior parameter is important here. We'll cover that in detail in the next section.

For webhook handling, listen for customer.subscription.updated events to sync seat changes back to your app:

// Webhook handler (Node.js / Express)
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;

  try {
    event = stripe.webhooks.constructEvent(req.body, sig, 'whsec_your_webhook_secret');
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  if (event.type === 'customer.subscription.updated') {
    const subscription = event.data.object;
    const quantity = subscription.items.data[0].quantity;
    // Update seat count in your database
    console.log(`Seats updated to: ${quantity}`);
  }

  res.json({ received: true });
});

Handling Seat Changes and Pro-Rating

Pro-rating is how Stripe handles billing fairly when a customer changes their seat count in the middle of a billing cycle.

For example: if a customer is on a $15/seat/month plan with 5 seats and adds 3 more seats halfway through the month, they shouldn't pay the full price for those 3 new seats since they're only using them for half the month. Stripe automatically calculates the prorated amount and adds it to the next invoice.

You control this behavior with the proration_behavior parameter when updating a subscription:

- create_prorations (default): Stripe creates a prorated credit or charge on the next invoice.
- none: No proration is applied. The new quantity takes effect at the next billing period.
- always_invoice: Stripe immediately creates a new invoice for the prorated amount.

For most SaaS products, create_prorations is the right default. Customers get charged fairly, and you collect revenue for the actual usage.

When a customer removes seats, Stripe issues a prorated credit that gets applied to their next invoice. If you want to issue a refund instead, you'll need to handle that manually via the Stripe Dashboard or the Refunds API.

A few best practices for handling seat changes:

- Notify customers via email when their seat count (and bill) changes.
- Show a preview of the prorated charge before the customer confirms the change.
- Use Stripe's retrieveUpcomingInvoice endpoint to calculate and display the prorated cost before applying it.

// Preview prorated cost before applying change (Node.js)
const upcomingInvoice = await stripe.invoices.retrieveUpcoming({
  customer: 'cus_customer_id',
  subscription: 'sub_subscription_id',
  subscription_items: [
    {
      id: 'si_subscription_item_id',
      quantity: 8,
    },
  ],
});

console.log('Proration amount due:', upcomingInvoice.amount_due);

Advanced Per-Seat Scenarios

Once you've got basic per-seat billing working, you can tackle more complex setups.

Tiered (volume) pricing lets you offer discounts as seat counts grow. In Stripe, you set up tiered pricing on the price object. For example: $20/seat for seats 1-10, $15/seat for seats 11-50, $10/seat for 51+. Stripe handles the tier calculation automatically based on the quantity at billing time.

Per-seat with add-ons means attaching multiple price items to a single subscription. A customer might have a base per-seat price plus an add-on price for a premium feature. Both items appear on the same invoice.

// Subscription with base per-seat + add-on (Node.js)
const subscription = await stripe.subscriptions.create({
  customer: 'cus_customer_id',
  items: [
    { price: 'price_base_per_seat', quantity: 10 }, // 10 seats at base price
    { price: 'price_addon_feature', quantity: 1 },  // flat add-on
  ],
});

Enterprise seat licensing often involves negotiated pricing. You can handle this in Stripe by creating custom prices for specific customers, or by using coupons to apply agreed-upon discounts.

Team vs. seat counts can get nuanced when organizations have sub-teams. One approach: count total active users at the organization level and bill accordingly. Another: allow each team to have its own subscription. The right approach depends on your product's structure.

Seat-based feature gating means your app unlocks features based on the number of seats purchased. Stripe doesn't enforce this in your app directly; you'll track the seat count from your database (synced via webhooks) and gate features on your side.

Best Practices and Common Pitfalls

Here are the things that trip people up most often with per-seat Stripe implementations.

Best Practices

  • Define what a 'seat' means clearly before you build. Is it an active user? A named user? A concurrent session? Get this right early.
  • Use Stripe's quantity parameter on subscription items, not a custom metadata field, so billing calculations stay accurate.
  • Always preview prorated charges before applying seat changes. Use retrieveUpcoming to show customers what they'll owe.
  • Test your subscription flows in Stripe's test mode using test clock to simulate billing cycles, seat changes, and renewals.
  • Set minimum seat counts if your pricing model requires it (for example, minimum 3 seats). Enforce this in your app's UI, not just in Stripe.
  • For free trials with per-seat billing, set trial_period_days on the subscription and make sure customers understand that billing starts at the per-seat rate after the trial.
  • Send proactive email notifications when a customer's seat count changes or when an invoice is about to be generated.
  • Use Stripe Customer Portal to let customers self-manage seat counts without you building a custom UI.

Common Pitfalls to Avoid

  • Not handling seat removal correctly. If you set quantity to 0, Stripe will error. Always enforce a minimum of 1 seat.
  • Forgetting to sync seat counts via webhooks. If your app's seat count and Stripe's quantity get out of sync, billing breaks.
  • Skipping the proration preview. Customers get frustrated by unexpected charges. Show them the cost before confirming.
  • Setting up metered billing instead of licensed billing for seat counts. Metered billing is designed for usage reporting, not seat management.
  • Not testing cancellations and downgrades. Make sure your webhook handlers cover customer.subscription.deleted and customer.subscription.updated events.
  • Hardcoding price IDs in production. Store price IDs in environment variables or your database so you can update them without a code deploy.

Real-World Per-Seat Pricing Examples

Here are three concrete examples of how per-seat pricing works in practice, with actual numbers.

Example 1: Team Productivity App (5-50 Seats)

  • Price: $12/seat/month
  • Minimum seats: 5 (enforced in app UI)
  • Free trial: 14 days
  • Revenue at 5 seats: $60/month
  • Revenue at 20 seats: $240/month
  • Revenue at 50 seats: $600/month
  • Setup: Single licensed price in Stripe, quantity set at subscription creation, updated via API when users are added or removed

Example 2: Developer Tool with Tiered Per-Seat Pricing

  • Tier 1: $25/seat/month for seats 1-10
  • Tier 2: $20/seat/month for seats 11-30
  • Tier 3: $15/seat/month for seats 31+
  • A team of 15 pays: (10 x $25) + (5 x $20) = $350/month
  • A team of 40 pays: (10 x $25) + (20 x $20) + (10 x $15) = $800/month
  • Setup: Tiered price object in Stripe with 'volume' pricing mode

Example 3: Enterprise with Custom Seat Negotiation

  • Negotiated rate: $8/seat/month for a 200-seat annual contract
  • Annual contract value: $8 x 200 x 12 = $19,200/year
  • Implementation: Custom price created in Stripe for the customer, billed annually
  • Coupon applied for any agreed-upon discount vs. standard rate
  • Seat changes handled via account manager with manual Stripe updates

Pricing Calculator: Projecting Revenue

Use this simple formula to project monthly recurring revenue (MRR) from your per-seat model:

MRR = (Number of customers) x (Average seats per customer) x (Price per seat)

For example, if you have 50 customers averaging 8 seats at $15/seat:

MRR = 50 x 8 x $15 = $6,000/month

As customers grow their teams, your MRR grows with them without any additional sales effort. This is why per-seat pricing creates natural expansion revenue, making it a strong model for B2B SaaS products with collaborative workflows.

FAQ: Per-Seat Billing Implementation

What is per-seat pricing and how does it work?+

Per-seat pricing charges customers based on the number of users (seats) in their account. For example, if your price is $15/seat/month and a customer has 10 users, they pay $150/month. In Stripe, you implement this by creating a licensed price and passing a quantity parameter when creating or updating a subscription.

How do I set up per-seat pricing in Stripe?+

Create a product in the Stripe Dashboard, add a recurring price with 'Licensed' usage type, set your per-seat unit price, then create subscriptions using that price ID with a quantity value equal to the number of seats. You can also do this entirely via the Stripe API using the stripe.subscriptions.create() method with the quantity parameter.

Can I use per-seat pricing with annual billing?+

Yes. When creating your price in Stripe, set the billing interval to 'year' instead of 'month'. The customer pays quantity x price x 12 upfront. You can offer a discount for annual billing by creating a separate annual price with a lower per-seat rate, or by applying a coupon.

How does pro-rating work when seats change mid-cycle?+

When a customer adds seats mid-cycle, Stripe calculates the prorated cost for the remaining days in the billing period and adds it to the next invoice. When seats are removed, Stripe issues a prorated credit on the next invoice. You control this behavior via the proration_behavior parameter: create_prorations (default), none, or always_invoice.

What's the difference between per-seat and flat-rate pricing?+

Flat-rate pricing charges one fixed amount regardless of how many users are on the account. Per-seat pricing scales with team size. Flat-rate is simpler to communicate but doesn't capture value from larger teams. Per-seat scales your revenue as customers grow, but requires more careful implementation and seat enforcement.

How do I handle free admin seats in per-seat billing?+

The simplest approach is to define 'seats' as non-admin users only, and exclude admin or owner accounts from the billable quantity. Track this in your own database and pass only the billable seat count as quantity to Stripe. Make sure this is clearly communicated to customers in your pricing page.

Can I combine per-seat with usage-based pricing?+

Yes. You can attach multiple price items to a single Stripe subscription: one licensed item for the per-seat charge and one metered item for usage-based charges (like API calls or storage). Both appear on the same invoice. This is a common pattern for developer tools or data platforms.

How do I migrate from flat-rate to per-seat pricing?+

The safest approach is to grandfather existing customers on their current flat-rate plan and apply per-seat pricing only to new subscribers. For customers you want to migrate, create a new per-seat subscription, set the quantity to their current user count, and cancel the old flat-rate subscription at the end of the current billing period using cancel_at_period_end: true. Always communicate the change clearly before it happens.

You're Ready to Implement Per-Seat Billing

Per-seat pricing is one of the most scalable billing models for B2B SaaS products, and Stripe gives you the tools to implement it cleanly. Start with a licensed price in the dashboard, pass quantity when creating subscriptions, handle seat changes with proration_behavior, and sync everything back to your app via webhooks.

The key things to get right: define what a seat means upfront, preview prorated charges before applying changes, test in Stripe's test mode with test clocks, and listen to subscription webhooks to keep your app in sync.

If you're building per-seat pricing into your product but want a support tool that doesn't charge you per seat, check out Donkey Support. It connects to Slack, Discord, or Telegram and has no per-seat pricing. You can be live in 5 minutes.

References and Further Reading