Quick Start
This walkthrough takes you from zero to a working subscription in one sitting. We'll define features, build a plan, subscribe a user, gate access, track usage, and explore the lifecycle — each step with complete, copy-paste code.
If you haven't installed the package yet, do that first: Installation.
The Tashil facade
Most examples use the Tashil facade. The fully-qualified equivalent app('tashil') works
everywhere too — use whichever your team prefers. Both resolve the same services.
Step 0 — Make your model Subscribable
A subscriber is any model that can hold a subscription. Add the contract and trait:
use Foysal50x\Tashil\Contracts\Subscribable;
use Foysal50x\Tashil\Traits\HasSubscriptions;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements Subscribable
{
use HasSubscriptions;
}Step 1 — Define your features
Features are defined once in a catalog, independent of any plan. Each has a type that decides how it behaves. We'll create one of each common kind:
use Foysal50x\Tashil\Facades\Tashil;
use Foysal50x\Tashil\Enums\ResetPeriod;
// A hard quota — enforced atomically.
$apiCalls = Tashil::feature('api-calls')->name('API Calls')->limit()->create();
// A simple on/off capability.
$darkMode = Tashil::feature('dark-mode')->name('Dark Mode')->boolean()->create();
// Tracked usage without a hard ceiling (e.g. storage in GB).
$storage = Tashil::feature('storage-gb')->name('Storage (GB)')->consumable()->create();
// Charged per unit consumed against a balance your app controls.
$aiTokens = Tashil::feature('ai-tokens')->name('AI Tokens')->metered()->create();
// Reset the API quota every month.
$apiCalls->update(['reset_period' => ResetPeriod::Monthly]);The five feature types are explained in detail on the Feature System page.
Step 2 — Build a plan
A package (plan) bundles pricing, billing cadence, an optional trial, and a set of features. The fluent builder reads top to bottom:
$pro = Tashil::package('pro')
->name('Pro Plan')
->price(29.99)
->monthly()
->trialDays(14)
->feature($apiCalls, value: '10000') // 10,000 calls / month
->feature($darkMode, value: 'true') // enabled
->feature($storage, value: '50') // 50 GB
->feature($aiTokens, value: '0.001') // metered: $0.001 per token
->create();The pivot value means different things per feature type: a numeric cap for limit, a string for
boolean/enum, and — for metered — the unit price.
Step 3 — Subscribe a user
$user = User::find(1);
// With a 14-day trial (uses the plan's trial_days):
$subscription = Tashil::subscription()->subscribe($user, $pro, withTrial: true);What status you get back depends on the plan and how you subscribed:
Why “Pending”?
By default, a paid plan does not grant access until money actually arrives. Subscribing issues an
initial invoice; access begins when your app marks it paid. This closes the "free first period"
gap. The full model lives in Billing Lifecycle.
Step 4 — Activate a paid subscription
Tashil never charges a card — your gateway integration does. When the charge succeeds, mark the invoice paid and Tashil takes it from there:
use Foysal50x\Tashil\Models\Invoice;
$invoice = Invoice::where('subscription_id', $subscription->id)->latest('id')->first();
// After your gateway confirms the charge:
$invoice->markAsPaid(); // → Tashil activates the subscription automatically
$subscription->refresh(); // status: Active, period anchored to the payment momentStep 5 — Gate access and track usage
Now the day-to-day part. Check whether a user has a feature, then consume it:
// Boolean feature — is it on?
if ($user->hasFeature('dark-mode')) {
// show the dark-mode toggle
}
// Limit feature — consume one unit. Returns false if it would exceed the cap.
if ($user->useFeature('api-calls')) {
// within quota — do the work
} else {
// over the limit — show an upgrade prompt
}
// Metered feature — charges units × unit_price via your balance.
// Returns false if the charge is declined (e.g. insufficient balance).
$user->useFeature('ai-tokens', 1500);
// Absolute reporting for storage-style values:
$user->reportStorage('storage-gb', 38.5); // the bucket is now 38.5 GBThe limit increment is a single atomic database operation — two concurrent requests can never both slip past the cap. See Feature System for the details.
Step 6 — Read the current state
$user->subscribed(); // true if Active, OnTrial, or in grace
$user->onPlan('pro'); // on this specific plan?
$user->onTrial(); // strictly on trial?
$user->featureValue('api-calls'); // '10000' (the snapshot value)
$user->featureUsage('api-calls'); // 1.0 (used so far)
$user->featureRemaining('api-calls');// 9999.0 (null means unlimited)Step 7 — Lifecycle operations
// Grace cancel — keeps access until the period ends.
$user->cancelSubscription();
// Pause and resume — banks the remaining paid time.
$user->pauseSubscription();
$user->unpauseSubscription();
// Move plans. changePlan keeps the same row and prorates an upgrade:
$user->changePlan($enterprisePlan);
// Schedule a downgrade for the end of the current period:
$user->scheduleDowngrade($basicPlan);Subscriptions covers each of these in depth, including the difference
between changePlan() and switchPlan().
Step 8 — Gate routes and views
Three middleware and four Blade directives ship ready to use:
Route::middleware('subscribed')->group(fn () => /* any valid subscription */);
Route::middleware('plan:pro')->group(fn () => /* the Pro plan only */);
Route::middleware('feature:api-calls')->group(fn () => /* needs this feature */);@feature('api-calls')
<p>You have {{ $user->featureRemaining('api-calls') }} calls left this month.</p>
@else
<p>Upgrade to unlock the API.</p>
@endfeatureStep 9 — See the analytics
$stats = Tashil::analytics()->dashboardSummary();
// MRR, active subscriptions, churn, trial conversion — all in one batched query.Where to go next
You now have the whole flow working. Dive deeper into any concept:
- Subscriptions — the full lifecycle and every method.
- Feature System — feature types, snapshots, and counters.
- Billing Lifecycle — activation, renewal, dunning, and proration.
- Metered Billing — wiring per-unit charges to your wallet.