Skip to main content

Per-Seat Billing

Per-seat billing charges a fixed price per user, team member, or “seat.” The total bill scales proportionally with the number of active seats. This is common in B2B SaaS where customers invite team members and each member incurs cost.

Plan configuration

Use the per_unit pricing rule:
// config/subscribd.php
'plans' => [
    'team' => [
        'name'           => 'Team',
        'rule'           => 'per_unit',
        'amount'         => 800,         // $8.00 per seat/month in cents
        'currency'       => 'USD',
        'interval'       => 'month',
        'interval_count' => 1,
        'features'       => [
            'seats'   => null,           // unlimited seats; quantity drives the price
            'support' => 'standard',
        ],
    ],
],

Creating a subscription with an initial quantity

Pass the initial seat count in plan_items:
use Pixelworxio\Subscribd\Actions\CreateSubscription;
use Pixelworxio\Subscribd\Models\Plan;

$plan = Plan::query()->where('key', 'team')->firstOrFail();

app(CreateSubscription::class)->execute($team, $plan, [
    'plan_items' => ['seats' => $team->members()->count()],
]);

Updating quantity when membership changes

Use the UpdateQuantity action whenever a seat is added or removed:
use Pixelworxio\Subscribd\Actions\UpdateQuantity;

// After a new member joins
app(UpdateQuantity::class)->execute($subscription->items->firstWhere('key', 'seats'), $newCount);

Automating quantity sync with a resolver

Register a quantity resolver in AppServiceProvider::boot() to let Subscribd keep the quantity in sync automatically:
use Pixelworxio\Subscribd\Pricing\QuantityResolverRegistry;

app(QuantityResolverRegistry::class)->register(
    'team',
    fn ($team, $plan) => $team->members()->where('active', true)->count(),
);
With a resolver registered, Subscribd calls it before every billing cycle to ensure the quantity is current.

PlanItems and caps

For plans with a hard cap on seats, configure the PlanItem directly:
'plan_items' => [
    [
        'key'           => 'seats',
        'cap_behaviour' => 'hard',    // reject over-limit additions
        'ceiling'       => 50,        // max 50 seats
        'included'      => 5,         // first 5 included in base price
        'overage_price' => 1500,      // $15.00 per seat above 5
    ],
],
Attempting to add a seat beyond the ceiling throws Pixelworxio\Subscribd\Exceptions\SubscriptionItemCapExceededException.

Checking seat entitlements

use Pixelworxio\Subscribd\Facades\Entitlements;

$seatLimit = Entitlements::for($team)->limit('seats');
// Returns null (unlimited) or int

$seatsUsed = $team->members()->count();

if ($seatLimit !== null && $seatsUsed >= $seatLimit) {
    abort(403, 'Seat limit reached. Upgrade to add more members.');
}

Next steps