What Is Subscriptionify?
Subscriptionify is a Laravel package by Rasel Islam Rafi that handles subscription plan modelling, feature quota enforcement, and usage tracking entirely within your own database. Unlike Laravel Cashier, it is completely payment-gateway-agnostic — it does not wrap any billing API. That makes it a practical choice when you bill through a provider Cashier does not support, charge against a prepaid balance, or need to gate features without charging at all.
It requires PHP 8.2 and supports Laravel 11, 12, and 13.
Installation
composer require revoltify/subscriptionify
php artisan vendor:publish --tag=subscriptionify-config
php artisan vendor:publish --tag=subscriptionify-migrations
php artisan migrate
The migrations create six tables covering plans, features, the plan/feature pivot, subscriptions, usage records, and direct feature grants.
Making Any Model Subscribable
Implement the Subscribable contract and add the InteractsWithSubscriptions trait to any Eloquent model — User, Organisation, Workspace, or whatever fits your domain:
use Revoltify\Subscriptionify\Concerns\InteractsWithSubscriptions;
use Revoltify\Subscriptionify\Contracts\Subscribable;
class Workspace extends Model implements Subscribable
{
use InteractsWithSubscriptions;
}
Four Feature Types for Different Quota Patterns
Subscriptionify distinguishes four feature types, each with its own consumption semantics:
- Toggle — a plain on/off capability gate.
- Consumable — a depletable quota that resets on a schedule (e.g. monthly API calls).
- Limit — a hard cap on a running total that can be freed again (e.g. active seats or projects).
- Metered — pay-per-use tracking with no cap, charging per unit.
Features are created once and attached to plans through a pivot that carries the allocation:
$plan->features()->attach($reports, [
'value' => 500, // 0 means unlimited
'unit_price' => '0.02000000',
'reset_period' => 1,
'reset_interval' => 'month',
]);
Usage Tracking on the Subscribable Model
All consumption methods live directly on the subscribable model:
$workspace->subscribe($plan);
$workspace->hasFeature('reports'); // feature available?
$workspace->canConsume('reports', 10); // 10 units available?
$workspace->consume('reports', 10); // record usage, throws on quota breach
$workspace->tryConsume('reports', 10); // returns false instead of throwing
$workspace->remainingUsage('reports'); // units left this period
For Limit features, release() hands units back — essential for slot-based resources like projects or seats:
$workspace->consume('projects', 1); // create a project
$workspace->release('projects', 1); // delete it, freeing the slot
Direct Grants Independent of the Plan
grantFeature() assigns quota directly to a subscribable on top of whatever the plan already provides. A plan with 500 reports plus a 1,000-unit grant yields 1,500 available units — useful for one-off top-ups or promotional bonuses without creating bespoke plans:
$workspace->grantFeature('reports', value: 1_000);
$workspace->revokeFeature('reports'); // plan allocation still applies
Optional Overage and Metered Billing
Billing is opt-in. Implement the HasFunds contract and the package charges overage against a balance you control. Amounts are passed as strings and compared with bccomp, so all arithmetic is arbitrary-precision rather than floating-point. Without HasFunds, features fall back to hard limits that throw on breach — meaning you can enforce quotas first and add billing later without rewriting consumption code.
Route Middleware and Blade Directives
Three middleware aliases protect routes and return 403 on failure:
Route::middleware('subscribed')->group(...);
Route::middleware('plan:pro')->group(...);
Route::middleware('feature:reports')->group(...);
Matching Blade directives gate view content, including @onTrial and @feature blocks.
Lifecycle, Events, and Scheduled Expiry
Subscriptions support changePlan(), renew(), cancel(), cancelNow(), and resume(). Each transition dispatches an event (SubscriptionCreated, SubscriptionCancelled, FeatureConsumed, etc.). An Artisan command handles expiry:
Schedule::command('subscriptionify:expire-overdue')->hourly();
Key Takeaways
- Gateway-agnostic: works with any payment provider or no provider at all.
- Four distinct feature types cover toggle, consumable, limit, and metered patterns.
- Direct grants let you top up individual subscribers without creating new plans.
- Billing via
HasFundsis opt-in; quota enforcement works without it. - Arbitrary-precision math (
bcmath) prevents floating-point billing errors. - Middleware and Blade directives provide first-class access gating.
Source: Laravel News — Subscriptionify: Feature-Based Subscription Management for Laravel