LarsaSub is launching soon. Purchases and account registration open shortly.

Documentation for larsasub v0.12.0. On an older version? Your release notes ship with the package (CHANGELOG.md).

LarsaSub - Quick Start Guide

A Laravel package for managing SaaS subscriptions with Mollie payment integration and multi-tenant support.


Introduction

LarsaSub provides a complete subscription management system for Laravel applications:


Requirements


Quick Install

1. Install Package

LarsaSub is not on Packagist. Point composer at our repository and authenticate with your license token first — see Installation for the three commands and for CI setup. Without that step this fails with "package not found".

composer require peters-development/larsasub

2. Run Installation

php artisan larsasub:install

This publishes config, runs migrations, and seeds payment methods.

3. Configure User Model

Add the BillableModel interface and IsBillableModel trait to your User model:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use PetersDevelopment\LarsaSub\Contracts\BillableModel;
use PetersDevelopment\LarsaSub\Traits\IsBillableModel;

class User extends Authenticatable implements BillableModel
{
    use IsBillableModel;

    public function getBillableNameAttribute(): string
    {
        return $this->name;
    }

    public function getBillableEmailAttribute(): string
    {
        return $this->email;
    }

    public function getBillableIdentifierAttribute(): string
    {
        return (string) $this->id;
    }
}

Billable intermediary: LarsaSub automatically creates a Billable record (in larsasub_billables) that links your User/Team model to all billing entities. This happens lazily on first use — no manual setup required.

Subscription convenience methods: To use $user->activeSubscription(), $user->hasFeature(), etc., also add the HasSubscriptions trait. The matching Contracts\HasSubscriptions interface is optional — nothing in the package type-hints on it — but the trait satisfies it in full, so declare it if your own code wants to accept "anything with subscriptions":

use PetersDevelopment\LarsaSub\Contracts\HasSubscriptions as HasSubscriptionsContract;
use PetersDevelopment\LarsaSub\Traits\HasSubscriptions;

class User extends Authenticatable implements BillableModel, HasSubscriptionsContract
{
    use IsBillableModel, HasSubscriptions;
}

4. Configure Environment

Add to your .env file:

# Payment Provider
LARSASUB_PROVIDER=mollie

# Currency
LARSASUB_CURRENCY_DEFAULT=EUR

# Mollie API key
MOLLIE_KEY=test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Notifications (optional)
LARSASUB_NOTIFICATIONS_SALES=sales@yourcompany.com
LARSASUB_NOTIFICATION_CHANNELS=mail

# Company Notification Toggles (optional)
LARSASUB_NOTIFY_COMPANY_SUBSCRIPTION_ACTIVATED=true

5. Add Mollie Trait (Optional)

For Mollie-specific features (customer management, mandates), add the IsMollieBillableModel trait to your User model:

use PetersDevelopment\LarsaSub\PaymentProviders\Mollie\Traits\IsMollieBillableModel;

class User extends Authenticatable implements BillableModel
{
    use IsBillableModel, IsMollieBillableModel;
}

This provides $user->mollieCustomers(), $user->mollieMandates(), and $user->getMollieCustomer().


Billing Modes

Direct Billing (Default)

The User model itself holds subscriptions and is charged directly.

// config/larsasub.php
'billable' => [
    'model' => \App\Models\User::class,
    'relation' => null,  // User IS the billable
],

Indirect Billing (Team/Company)

A related model (Team, Company) holds the subscription. Multiple users can share one subscription.

// config/larsasub.php
'billable' => [
    'model' => \App\Models\Team::class,
    'relation' => 'team',  // $user->team() returns the billable
],

The Team model must implement BillableModel and use IsBillableModel:

class Team extends Model implements BillableModel
{
    use IsBillableModel;

    public function getBillableNameAttribute(): string
    {
        return $this->name;
    }

    public function getBillableEmailAttribute(): string
    {
        return $this->contact_email;
    }

    public function getBillableIdentifierAttribute(): string
    {
        return (string) $this->id;
    }

    // Optional: define who receives notifications
    public function getNotifiableUsers(): Collection
    {
        return $this->users;
    }
}

How Billing Works Internally

LarsaSub uses a Billable intermediary model between your application model and all billing entities:

Your Model (User, Team, Company)
    │
    └── Billable (larsasub_billables)    ← created automatically on first billing operation
            ├── BillableSubscription     ← references billable_id
            ├── RecurringCharge          ← references billable_id
            ├── SinglePayment            ← references billable_id
            ├── BillableCredit           ← references billable_id
            └── MollieCustomer           ← references billable_id

The IsBillableModel trait provides relation helpers that route through the Billable transparently. The HasSubscriptions trait adds subscription and feature convenience methods on top.


Mollie Connect (Multi-Tenant)

Mollie Connect enables multi-tenant platforms where each tenant has their own Mollie account. Payments go directly to the tenant's account, with optional platform application fees.

Enable Connect Mode

Connect collects payments on behalf of others, which requires a Platform license. Declare it alongside the switch — without the declaration the package refuses to boot. Nothing is verified over the network and nothing is sent anywhere; see larsasub.eu/pricing.

# .env
LARSASUB_LICENSE_TIER=platform
LARSASUB_CONNECT_ENABLED=true
LARSASUB_CONNECT_TENANT_RELATION=danceSchool
LARSASUB_CONNECT_TENANT_LABEL="dance school"
LARSASUB_CONNECT_TENANT_NAME_ATTRIBUTE=name
LARSASUB_CONNECT_TENANT_OWNER_ATTRIBUTE=owner_id

# Mollie OAuth credentials (from Mollie Dashboard → Developers → OAuth apps)
MOLLIE_CONNECT_CLIENT_ID=app_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MOLLIE_CONNECT_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MOLLIE_ORGANIZATION_ID=org_xxxxxxxx
// config/larsasub.php
'license' => [
    'tier' => 'platform',  // required for Connect
],

'billable' => [
    'model' => \App\Models\User::class,
    'relation' => 'danceSchool',  // $user->danceSchool() returns the billable tenant
],

'connect' => [
    'enabled' => true,
    'tenant_relation' => 'danceSchool',
    'tenant_label' => 'dance school',         // Used in UI labels and translations
    'tenant_name_attribute' => 'name',        // $tenant->name shown in emails
    'tenant_owner_attribute' => 'owner_id',   // Determines who can manage Mollie connection
],

Application Fees

Charge a platform fee on every tenant payment:

# .env
LARSASUB_CONNECT_FEE_ENABLED=true
LARSASUB_CONNECT_FEE_TYPE=percentage    # 'percentage' or 'fixed'
LARSASUB_CONNECT_FEE_VALUE=10           # 10% or €10.00
LARSASUB_CONNECT_FEE_DESCRIPTION="Platform fee"

Fees can also be overridden per subscription plan via the fee_type and fee_value fields on the Subscription model.

Fees are automatically skipped when the platform itself is the billable (self-transactions).

Tenant OAuth Flow

Tenants connect their Mollie account via OAuth:

  1. Tenant owner clicks "Connect Mollie" in the tenant admin dashboard
  2. LarsaSub redirects to Mollie OAuth authorization page
  3. Tenant authorizes the platform to access their Mollie account
  4. Mollie redirects back with an authorization code
  5. LarsaSub exchanges the code for access/refresh tokens
  6. Tokens are stored encrypted in larsasub_mollie_connected_accounts
  7. Tenant is now ready to receive payments

The tenant admin dashboard is available at the URL configured in standalone.url.tenant-connect-dashboard (default: billing/admin/connect).

Tenant-Aware Models

In Connect mode, Mollie customers and mandates are scoped per tenant:

// Customers and mandates are automatically created under the tenant's Mollie account
$user->getMollieCustomer();  // Creates customer via tenant's access token

// Subscription plans can be global or tenant-specific
$plans = Subscription::forTenant($tenant, includeGlobal: true)->isEnabled()->get();  // Tenant plans + global plans

Dual Billing

For platforms that charge tenants directly AND where tenants charge their own users:

// config/larsasub.php
'billable' => [
    'model' => \App\Models\User::class,           // Tenant's users (uses Connect account)
    'platform_model' => \App\Models\DanceSchool::class,  // Platform bills this model (uses global Mollie key)
],

Both models must implement BillableModel. The MollieClientResolver automatically routes:


Basic Usage

Check User Subscription

// Get active subscription
$subscription = $user->activeSubscription();

// Check if has active subscription
if ($subscription && $subscription->isActive()) {
    // User has active subscription
}

Feature Access

// Check feature access
if ($user->hasFeature('premium_support')) {
    // Allow premium support
}

// Get feature value
$limit = $user->featureValue('api_calls', 100);

Query Subscriptions

use PetersDevelopment\LarsaSub\Models\BillableSubscription;

// Get all active subscriptions
$active = BillableSubscription::isActive()->get();

// Get chargeable subscriptions
$chargeable = BillableSubscription::isChargeable()->get();

Resolve Billable

use PetersDevelopment\LarsaSub\Helpers\BillableResolver;

// Resolve the billable from an authenticated user
$billable = BillableResolver::resolve($user);

// Resolve from the current request
$billable = BillableResolver::fromRequest($request);

// Check if using direct mode (User IS billable)
$isDirect = BillableResolver::isDirect();

Standalone Dashboard URLs

Default URLs for user subscription management (configurable via standalone.url config):

URL Description
/billing/dashboard View/manage subscription
/billing/payments Payment history
/billing/payment-methods Payment methods
/billing/admin/... Management dashboards: plans, subscribers, charges, invoices. Connect mode: for the tenant owner, scoped to the tenant. Simple mode: operator management on the global plans — set larsasub.policies.admin_role to grant access.

Key Commands

# Test installation with sample data (fresh install only — skipped on an
# existing installation, so it cannot duplicate a live catalogue)
php artisan larsasub:install --seed

# Plan charges for subscriptions
php artisan larsasub:plan-charges

# Execute pending charges
php artisan larsasub:execute-charges

# Notify upcoming charges
php artisan larsasub:notify-charges

# Renewal management
php artisan larsasub:renew-billable-subscriptions
php artisan larsasub:announce-renewal-billable-subscriptions

# Credit management
php artisan larsasub:process-expired-credits
php artisan larsasub:notify-expiring-credits

# Test notifications
php artisan larsasub:test-notifications --list

Credit System

LarsaSub includes a credit system for managing customer balances. Credits can be:

See Full Documentation for detailed credit system documentation.


What's Next?

For complete documentation including:

See Full Documentation