Skip to main content

Multiple Subscriptions

A single billable model can hold multiple independent subscriptions simultaneously via named slots. Each slot is a separate subscription record with its own plan, status, invoices, and gateway subscription ID.

When to use multiple slots

  • Teams — one subscription for the individual, another for a shared team plan
  • Multi-tenant apps — each tenant represented as a separate subscription on the owning user
  • Resellers — separate subscription per managed account
  • Add-on services — a base plan slot and a separate add-on slot billed independently

Creating subscriptions on named slots

Pass a name option to CreateSubscription:
use Pixelworxio\Subscribd\Actions\CreateSubscription;
use Pixelworxio\Subscribd\Models\Plan;

$starterPlan = Plan::where('key', 'starter')->firstOrFail();
$teamPlan    = Plan::where('key', 'team-pro')->firstOrFail();

// Individual slot
app(CreateSubscription::class)->execute($user, $starterPlan, ['name' => 'individual']);

// Team slot
app(CreateSubscription::class)->execute($user, $teamPlan, ['name' => 'team']);

Accessing a specific slot

$user->subscription();              // default slot (name = 'default')
$user->subscription('individual');  // named slot
$user->subscription('team');        // named slot — null if it doesn't exist

Checking subscription state per slot

All ManagesBilling state helpers accept an optional slot name:
$user->subscribed();                    // default slot
$user->subscribed('team');              // team slot
$user->onTrial('individual');           // individual slot
$user->onGracePeriod('team');           // team slot

Acting on a specific slot

Every action class operates on a Subscription model, so you retrieve the slot first:
use Pixelworxio\Subscribd\Actions\SwapPlan;
use Pixelworxio\Subscribd\Actions\CancelSubscription;

$teamSub  = $user->subscription('team');
$newPlan  = Plan::where('key', 'team-enterprise')->firstOrFail();

// Swap the team plan
app(SwapPlan::class)->execute($teamSub, $newPlan);

// Cancel the individual subscription, keep team active
$individualSub = $user->subscription('individual');
app(CancelSubscription::class)->execute($individualSub);

Entitlements across multiple slots

The Entitlements facade aggregates entitlements across all active subscriptions by default. Use for() with a slot name to scope to a specific subscription:
use Pixelworxio\Subscribd\Facades\Entitlements;

// Aggregated — merges features from all active subscriptions
Entitlements::for($user)->allows('exports');
Entitlements::for($user)->limit('api_calls');       // highest limit wins

// Scoped to a single slot
Entitlements::for($user)->on('team')->allows('team_management');
Entitlements::for($user)->on('individual')->limit('projects');
See Entitlements — Multiple Subscriptions for the full aggregation reference.

Invoice history per slot

// All invoices across all slots
$user->invoices()->get();

// Invoices for a specific slot
$user->subscription('team')->invoices()->get();

Livewire components with named slots

Pass a subscription-name prop to any subscriber component:
{{-- Individual subscription management --}}
<livewire:subscribd::subscriber.subscription-manager :subscription-name="'individual'" />

{{-- Team subscription management --}}
<livewire:subscribd::subscriber.subscription-manager :subscription-name="'team'" />

{{-- Plan picker for the team slot --}}
<livewire:subscribd::subscriber.plan-picker :subscription-name="'team'" />

Design considerations

Keep slot names stable. Changing a slot name in code while records in the database use the old name will cause subscription('new_name') to return null. If you need to rename a slot, write a migration to update the name column on the affected subscribd_subscriptions rows. Consider using an Eloquent model (e.g. Team) as the billable rather than a named slot on User when teams are first-class entities in your domain. This keeps billing directly attached to the team and simplifies multi-tenancy.

Next steps