Tashil: Subscription Plans, Feature Limits & Usage Tracking For Laravel
Published on October 9, 2026 by Dinesh Uprety
💳 Tashil: Subscription Plans, Feature Limits & Usage Tracking for Laravel
Every SaaS eventually needs the same boring-but-critical machinery: plans, trials, "you've used 4 of 5 uploads", upgrade nudges, failed-payment retries. Tashil is a Laravel package that gives you all of it — without locking you into Stripe Billing or any specific payment gateway.
Think of it as the subscription brain of your app: it owns plans, who is subscribed, what each plan allows, and how much each customer has used. It issues invoices and tracks their state — but it never moves money. Your gateway (Stripe, Paddle, eSewa, whatever you use) stays yours; Tashil just records what happened.
What you'll build: a podcast-hosting SaaS with Hobby and Studio plans, monthly upload limits, a custom-domain toggle, trials, and upgrade nudges — in about 30 minutes.
Prerequisites: a Laravel app, a database, and (optionally) Redis for caching hot counters.
📦 1. Install
composer require foysal50x/tashilphp artisan vendor:publish --tag=tashil-configphp artisan vendor:publish --tag=tashil-migrationsphp artisan migrate
👥 2. Make Your Model Subscribable
Any Eloquent model can hold a subscription — User, Team, Organization, a tenant model. Implement the contract and use the trait:
use Foysal50x\Tashil\Contracts\Subscribable;use Foysal50x\Tashil\Traits\HasSubscriptions; class Team extends Model implements Subscribable{ use HasSubscriptions;}
Building for teams instead of users? Tell Tashil how to find "the current subscriber" so Blade directives and middleware resolve the right one:
Tashil::resolveSubscribableUsing(fn () => auth()->user()?->currentTeam);
🧩 3. Define Features — Five Flavors
Features are the things plans grant. Tashil has five types:
- Boolean — on/off toggles (custom domain, priority support)
- Limit — counted quotas that reset (uploads per month)
- Consumable — absolute amounts you report (GB of storage used)
- Enum — pick-one-of options (support tier: community / priority / dedicated)
- Metered — pay-per-unit (AI tokens at $0.001 each)
use Foysal50x\Tashil\Facades\Tashil;use Foysal50x\Tashil\Enums\ResetPeriod; $uploads = Tashil::feature('episode-uploads') ->name('Episode Uploads') ->limit() ->create();$uploads->update(['reset_period' => ResetPeriod::Monthly]); $customDomain = Tashil::feature('custom-domain') ->name('Custom Domain') ->boolean() ->create();
📋 4. Build a Package
Packages are plans. A fluent builder, with features attached at chosen values:
$hobby = Tashil::package('hobby') ->name('Hobby') ->price(12) ->monthly() ->feature($uploads, value: '4') ->feature($customDomain, value: 'false') ->create();
One comforting detail: if you change a plan later, teams already on it keep the limits they signed up with. Only new subscribers get the new values. No accidental downgrades, no angry emails.
🚀 5. Subscribe — Trials Included
$subscription = Tashil::subscription() ->subscribe($team, $hobby, withTrial: true);
Trials are first-class citizens: isOnTrial() is strict, and converting a trial anchors the first paid period and issues the first invoice. Priced plans subscribe as pending with no access until the first invoice is paid; free plans go straight to active.
🚦 6. Gate Access and Track Usage
This is the money line of the whole package:
if (! $team->useFeature('episode-uploads')) { return back()->withErrors([ 'audio' => "You've used all {$team->featureValue('episode-uploads')} uploads this month.", ]);}
useFeature() increments the counter and returns false when the limit is reached. The check and the increment happen in one database query — a conditional UPDATE — so two uploads hitting at the same moment can't both sneak past the limit. Race-safe by construction, not by luck.
Blade and routes get helpers too:
@feature('custom-domain') <x-domain-settings />@else <p>Custom domains are available on the Studio plan.</p>@endfeature
Route::middleware('feature:custom-domain')->group(...);Route::middleware('plan:studio')->group(...);Route::middleware('subscribed')->group(...);
And when a team crosses 80% of a limit, Tashil fires a UsageLimitWarning event once per period — the perfect hook for a "you're almost out of uploads, want to upgrade?" email.

Metered and storage-style features work just as smoothly:
$team->useFeature('ai-tokens', 1500); // metered: units × unit price$team->reportStorage('storage-gb', 38.5); // absolute: 38.5 GB used
🔄 7. Lifecycle: Cancel, Pause, Switch, Downgrade
$team->cancelSubscription(); // grace cancel — access until period end$team->pauseSubscription(); // banks remaining time$team->unpauseSubscription();$team->switchPlan($studioPlan); // immediate switch$team->scheduleDowngrade($hobby);// takes effect at period end$team->changePlan($studioPlan); // in-place change, prorated
Failed payments get a proper dunning flow — Active → PastDue → Suspended → Expired — processed by the tashil:process-dunning command, with automatic recovery when payment lands.
🧾 8. Billing Without the Gateway Lock-In
Tashil's philosophy in one line: it owns the invoice, never the money.
It issues renewal invoices, routes paid invoices by kind (initial → activate, renewal → advance period, lapsed → reactivate), and prorates in-place plan changes. Your gateway integration charges the card and tells Tashil the invoice was paid. Every state change lands in an immutable, append-only event log with idempotency keys — an audit trail you can actually trust.
📊 9. Analytics Included
MRR, churn, trial conversion, and per-package breakdowns come out of the box — the numbers a SaaS founder checks every morning, without wiring up a separate analytics pipeline.
🎯 Final Thoughts
Tashil is the rare package that treats SaaS pricing as a product feature, not a billing afterthought. Plans as code, race-safe usage counters, trials, dunning, invoices, analytics — and your payment gateway stays your choice.
If you're building a SaaS in Laravel, this one deserves a weekend spike. What would your first metered feature be? Drop a comment below. 👇
Sources:
Senior Software Engineer • Writer @ Laranepal • PHP, Laravel, Livewire, TailwindCSS & VueJS • CEO @ Laranepal & Founder @ laracodesnap