PHPackages                             miladtech/laravel-subscriptions - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. miladtech/laravel-subscriptions

ActiveLibrary[Database &amp; ORM](/categories/database)

miladtech/laravel-subscriptions
===============================

Milad Tech Subscriptions is a flexible plans and subscription management system for Laravel, with the required tools to run your SAAS like services efficiently. It's simple architecture, accompanied by powerful underlying to afford solid platform for your business.

v9.0.3(1mo ago)019MITPHPPHP ^8.2

Since May 14Pushed 11mo ago1 watchersCompare

[ Source](https://github.com/mrmostafaei/laravel-subscriptions)[ Packagist](https://packagist.org/packages/miladtech/laravel-subscriptions)[ Docs](https://milad-tech.com)[ RSS](/packages/miladtech-laravel-subscriptions/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (10)Dependencies (19)Versions (15)Used By (0)

MiladTech Subscriptions
=======================

[](#miladtech-subscriptions)

**MiladTech Subscriptions** is a flexible plans and subscription management system for Laravel, with the required tools to run your SAAS like services efficiently. It's simple architecture, accompanied by powerful underlying to afford solid platform for your business.

Supports **Laravel 11, 12 and 13** on **PHP 8.2+**, fully self-contained, with lifecycle events, grace periods, suspension, safe concurrent usage tracking, and a complete test suite.

Considerations
--------------

[](#considerations)

- Payments are out of scope for this package. Listen to the lifecycle events (e.g. `SubscriptionCanceled`) to integrate your payment provider.
- You may extend the core models when you need to override logic behind helper methods like `renew()`, `cancel()`, etc.

Installation
------------

[](#installation)

```
composer require miladtech/laravel-subscriptions
```

Migrations load automatically. Optionally publish resources:

```
php artisan vendor:publish --tag=miladtech-subscriptions-config
php artisan vendor:publish --tag=miladtech-subscriptions-migrations
php artisan migrate
```

Upgrading from v7? Read [UPGRADE.md](UPGRADE.md).

Usage
-----

[](#usage)

### Add subscriptions to your model

[](#add-subscriptions-to-your-model)

Use the `HasPlanSubscriptions` trait on any subscriber model (usually `User`):

```
namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use MiladTech\Subscriptions\Traits\HasPlanSubscriptions;

class User extends Authenticatable
{
    use HasPlanSubscriptions;
}
```

### Create a plan with features

[](#create-a-plan-with-features)

```
use MiladTech\Subscriptions\Models\Plan;

$plan = Plan::create([
    'name' => 'Pro',
    'description' => 'Pro plan',
    'price' => 9.99,
    'signup_fee' => 1.99,
    'currency' => 'USD',
    'invoice_period' => 1,
    'invoice_interval' => 'month', // hour|day|week|month|year
    'trial_period' => 15,
    'trial_interval' => 'day',
    'grace_period' => 3,
    'grace_interval' => 'day',
    'active_subscribers_limit' => 1000, // null = unlimited
]);

$plan->features()->saveMany([
    new PlanFeature(['name' => 'SMS', 'slug' => 'sms', 'value' => '100', 'resettable_period' => 1, 'resettable_interval' => 'month']),
    new PlanFeature(['name' => 'API Access', 'slug' => 'api-access', 'value' => 'true']),
    new PlanFeature(['name' => 'Legacy Import', 'slug' => 'legacy-import', 'value' => 'false']),
]);
```

Feature `value` semantics: `"true"` = enabled/unlimited · `"false"`, `"0"`, empty = disabled · numeric = countable limit · anything else = descriptive value (enabled).

### Subscribe

[](#subscribe)

```
$user->newPlanSubscription('main', $plan);            // starts now
$user->newPlanSubscription('main', $plan, $date);     // starts at a given date
```

Plans without a trial get `trial_ends_at = null`; with a trial, the paid period starts when the trial ends. Inactive plans and plans at their `active_subscribers_limit` throw (`InactivePlanException`, `PlanSubscribersLimitReachedException`). For admin/internal flows that attach private (inactive) plans manually, skip those checks:

```
$user->newPlanSubscription('main', $privatePlan, null, skipPlanChecks: true);
```

### Check status

[](#check-status)

```
$subscription = $user->planSubscription('main');

$subscription->active();         // on trial, in period, or in grace — and not suspended
$subscription->onTrial();
$subscription->ended();
$subscription->onGracePeriod();  // ended but within the plan's grace window
$subscription->graceEndsAt();    // moment access is truly lost
$subscription->canceled();
$subscription->suspended();
$subscription->remainingDays();

$user->hasActivePlanSubscription();
$user->subscribedTo($planId);
$user->subscribedPlans();
```

### Feature usage — safe by design

[](#feature-usage--safe-by-design)

All writes run in a transaction with a row lock, so concurrent requests can never exceed a limit.

```
$subscription->canUseFeature('sms');          // one use
$subscription->canUseFeature('sms', 5);       // five uses at once

$subscription->recordFeatureUsage('sms');     // +1
$subscription->recordFeatureUsage('sms', 3);  // +3
$subscription->setFeatureUsage('sms', 10);    // absolute
$subscription->reduceFeatureUsage('sms', 2);

$subscription->getFeatureUsage('sms');        // used in the current window
$subscription->getFeatureRemainings('sms');   // PHP_INT_MAX for unlimited
$subscription->getFeatureValue('sms');        // raw value
```

`recordFeatureUsage` throws `FeatureNotFoundException` (unknown feature), `FeatureUsageExceededException` (limit reached) or `SubscriptionException` (inactive subscription) — catch them or gate with `canUseFeature()`. All package exceptions extend `MiladTech\Subscriptions\Exceptions\SubscriptionException`.

Resettable features (`resettable_period`/`resettable_interval`) reset automatically when their window elapses, aligned to the subscription start — even when several windows pass without activity.

### Renew

[](#renew)

```
$subscription->renew();    // one invoice period
$subscription->renew(3);   // three periods at once
```

Early renewal **extends** the current period from `ends_at` — subscribers never lose paid time — and keeps usage. Renewal after expiry starts a fresh period from now and clears usage. Renewing also reverts any scheduled cancellation.

### Cancel / uncancel

[](#cancel--uncancel)

```
$subscription->cancel();       // access remains until ends_at
$subscription->cancel(true);   // terminate immediately (ends trial too)
$subscription->uncancel();     // revert a scheduled cancellation
```

### Suspend / resume

[](#suspend--resume)

```
$subscription->suspend();        // e.g. failed payment — subscription becomes inactive
$subscription->resume();         // paused time is credited back to ends_at
$subscription->resume(false);    // resume without crediting paused time
```

### Change plan

[](#change-plan)

```
$subscription->changePlan($newPlan);
```

Usage is migrated to the new plan's features **by slug**: shared features keep their usage (limits may shrink or grow naturally), removed features lose their usage. Different billing frequency starts a new period today. Pass `changePlan($newPlan, syncUsage: false)` to wipe usage instead.

`changePlan` accepts inactive plans on purpose — changing an existing subscriber's plan is an internal/admin operation, and inactive plans are commonly private/custom plans attached manually. `is_active` only gates new public subscriptions.

### Events

[](#events)

Every lifecycle change dispatches an event you can listen to:

`SubscriptionCreated`, `SubscriptionRenewed`, `SubscriptionCanceled`, `SubscriptionUncanceled`, `SubscriptionSuspended`, `SubscriptionResumed`, `SubscriptionPlanChanged`, `SubscriptionExpired`, `SubscriptionTrialEnded`, `FeatureUsageRecorded`, `FeatureUsageReduced` — all under `MiladTech\Subscriptions\Events`.

`SubscriptionExpired` and `SubscriptionTrialEnded` are fired (exactly once per subscription, grace-period aware) by the checker command. Schedule it in `routes/console.php`:

```
use Illuminate\Support\Facades\Schedule;

Schedule::command('subscriptions:check')->everyFifteenMinutes();
```

### Scopes

[](#scopes)

```
PlanSubscription::ofSubscriber($user)->get();
PlanSubscription::findActive()->get();
PlanSubscription::findSuspended()->get();
PlanSubscription::findEndingTrial(3)->get();   // trials ending within 3 days
PlanSubscription::findEndedTrial()->get();
PlanSubscription::findEndingPeriod(3)->get();
PlanSubscription::findEndedPeriod()->get();
```

### Models &amp; config

[](#models--config)

Override table names or swap in your own models via the published config file (`config/miladtech.subscriptions.php`). Slugs are Persian-friendly (via `pishran/laravel-persian-slug`), and `name`/`description` are translatable (via `spatie/laravel-translatable`):

```
$plan = Plan::create(['name' => ['en' => 'Pro', 'fa' => 'حرفه‌ای'], ...]);
```

Subscription slugs are unique **per subscriber** (every user can own a subscription slugged `main`), and feature slugs are unique **per plan** (so plans can share feature slugs — that's what makes plan changes migrate usage).

Testing
-------

[](#testing)

```
composer test
```

CI runs the suite against every supported PHP/Laravel combination.

License
-------

[](#license)

This software is released under [The MIT License (MIT)](LICENSE).

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance69

Regular maintenance activity

Popularity8

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~89 days

Recently: every ~77 days

Total

14

Last Release

41d ago

Major Versions

v6.0.8 → v7.0.02024-02-23

v7.0.0 → v8.0.02025-09-05

v8.0.0 → v9.0.02026-07-09

PHP version history (3 changes)v6.0.1PHP ^8.0.0

v6.0.2PHP ^8.1.0

v8.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/8f3a9358169a6b591d9d9b3897e5a12f7e6b07797d065e7ecb2794c0c46aa7e3?d=identicon)[miladtech](/maintainers/miladtech)

---

Top Contributors

[![mrmostafaei](https://avatars.githubusercontent.com/u/35763837?v=4)](https://github.com/mrmostafaei "mrmostafaei (11 commits)")

---

Tags

laraveldatabasefeaturerecurringsubscriptionplanvalue

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/miladtech-laravel-subscriptions/health.svg)

```
[![Health](https://phpackages.com/badges/miladtech-laravel-subscriptions/health.svg)](https://phpackages.com/packages/miladtech-laravel-subscriptions)
```

###  Alternatives

[laravelcm/laravel-subscriptions

Laravel Subscriptions is a flexible plans and subscription management system for Laravel, with the required tools to run your SAAS like services efficiently. It's simple architecture, accompanied by powerful underlying to afford solid platform for your business.

24375.3k5](/packages/laravelcm-laravel-subscriptions)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
