1. Go to this page and download the library: Download revoltify/subscriptionify library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
revoltify / subscriptionify example snippets
use Revoltify\Subscriptionify\Concerns\InteractsWithSubscriptions;
use Revoltify\Subscriptionify\Contracts\Subscribable;
class Team extends Model implements Subscribable
{
use InteractsWithSubscriptions;
}
use Revoltify\Subscriptionify\Models\Plan;
use Revoltify\Subscriptionify\Models\Feature;
use Revoltify\Subscriptionify\Enums\FeatureType;
use Revoltify\Subscriptionify\Enums\Interval;
// Create a plan
$plan = Plan::create([
'name' => 'Pro',
'slug' => 'pro',
'billing_period' => 1,
'billing_interval' => Interval::Month,
'trial_days' => 14,
]);
// Create features and attach to plan
$apiCalls = Feature::create(['name' => 'API Calls', 'slug' => 'api-calls', 'type' => FeatureType::Consumable]);
$plan->features()->attach($apiCalls, [
'value' => 10_000,
'unit_price' => '0.00100000',
]);
// Subscribe
$team->subscribe($plan);
// Use features
$team->consume('api-calls', 100);
$team->remainingUsage('api-calls'); // 9900
$team->remainingOverage('api-calls'); // extra units affordable from balance
$team->subscribe($plan);
// With custom end date
$team->subscribe($plan, endsAt: now()->addMonths(6));
$team->subscribed(); // has active/trialing subscription
$team->onPlan($plan); // on a specific plan
$team->onTrial(); // currently in trial
$team->onFreePlan(); // on a free plan
$team->canChangePlan($otherPlan); // not already on that plan
$subscription = $team->subscription();
$subscription->active(); // active or trialing
$subscription->onTrial(); // in trial period
$subscription->recurring(); // active, not trialing
$subscription->canceled(); // has been cancelled
$subscription->onGracePeriod(); // cancelled but still within grace period
$subscription->ended(); // cancelled and past grace period
$subscription->pastDue(); // marked as past due
$subscription->expired(); // status is Expired, or Active with past ends_at
$subscription->valid(); // active || trialing || on grace period
$subscription->hasPlan('pro'); // on a specific plan by slug
$subscription->daysRemaining(); // days until ends_at
$subscription->trialDaysRemaining(); // days remaining in trial
$subscription = $team->subscription();
// Change plans
$subscription->changePlan($newPlan);
$subscription->changePlan($newPlan, endsAt: now()->addYear());
$subscription->changePlan($newPlan, resetUsages: true); // resets consumable usages
// Renew
$subscription->renew();
$subscription->renew(endsAt: now()->addYear());
// Cancel
$subscription->cancel(); // at end of billing period (grace period applies)
$subscription->cancelNow(); // immediately
// Resume (only during grace period)
$subscription->resume();
// Lifecycle
$subscription->expire();
$subscription->markPastDue();
// Check access (does the subscribable have this feature?)
$team->hasFeature('api-calls');
// Check if specific units can be consumed
$team->canConsume('api-calls', 100);
// Consume units (throws FeatureException if quota exceeded)
$team->consume('api-calls', 100);
// Try to consume (returns false instead of throwing)
$team->tryConsume('api-calls', 100);
// Check remaining plan quota
$team->remainingUsage('api-calls');
// Check remaining overage capacity (balance / unit_price)
// Requires HasFunds + unit_price configured, returns '0' otherwise
$team->remainingOverage('api-calls');
// Check if feature has unlimited quota
$team->isUnlimitedUsage('api-calls'); // true if unlimited
// Release units (Limit type only — frees up slots)
$team->release('projects', 1);
// Grant with quota
$team->grantFeature('api-calls', value: 50_000);
// Grant with custom unit price for overage
$team->grantFeature('api-calls', value: 50_000, unitPrice: '0.00050000');
// Grant with auto-reset
$team->grantFeature('reports', value: 100, resetPeriod: 1, resetInterval: Interval::Month);
// Grant unlimited (value: 0)
$team->grantFeature('api-calls', value: 0);
// Revoke direct grant (plan quota still applies)
$team->revokeFeature('api-calls');
use Revoltify\Subscriptionify\Contracts\HasFunds;
class Team extends Model implements Subscribable, HasFunds
{
use InteractsWithSubscriptions;
/** @return numeric-string */
public function getBalance(): string
{
return $this->balance;
}
public function hasSufficientFunds(string $amount): bool
{
return bccomp($this->balance, $amount, 8) >= 0;
}
public function deductFunds(string $amount, string $description): void
{
/** @var numeric-string $newBalance */
$newBalance = bcsub($this->balance, $amount, 8);
$this->update(['balance' => $newBalance]);
}
}
// Plan quota: 10,000 | Unit price: $0.001 | Balance: $50.00
$team->remainingUsage('api-calls'); // '10000' — plan quota remaining
$team->remainingOverage('api-calls'); // '50000' — extra units affordable (50 / 0.001)
Route::middleware('subscribed')->group(function () {
// Only accessible with an active subscription
});
Route::middleware('plan:pro')->group(function () {
// Only accessible on the Pro plan
});
Route::middleware('feature:api-calls')->group(function () {
// Only accessible if the subscribable has the api-calls feature
});
// All teams with active/trialing subscriptions
Team::whereSubscribed()->get();
// All teams on a specific plan
Team::whereOnPlan($proPlan)->get();
// All teams currently in trial
Team::whereOnTrial()->get();
// All teams with expired subscriptions
Team::whereExpired()->get();
use Illuminate\Support\Facades\Schedule;
Schedule::command('subscriptionify:expire-overdue')->hourly();
// Example: Listen for feature consumption
use Revoltify\Subscriptionify\Events\FeatureConsumed;
class TrackApiUsage
{
public function handle(FeatureConsumed $event): void
{
// $event->subscribable
// $event->feature
// $event->units
// $event->remaining
// $event->cost
// $event->usedOverage
}
}
use Revoltify\Subscriptionify\Exceptions\SubscriptionException;
use Revoltify\Subscriptionify\Exceptions\FeatureException;
use Revoltify\Subscriptionify\Exceptions\InsufficientFundsException;
try {
$team->consume('api-calls', 100);
} catch (FeatureException $e) {
// Quota exceeded
} catch (InsufficientFundsException $e) {
// Insufficient balance for overage
}
// config/subscriptionify.php
return [
// Override with your own models (must extend base or implement contracts)
'models' => [
'plan' => Plan::class,
'feature' => Feature::class,
'subscription' => Subscription::class,
],
// Rename tables if they conflict (e.g. with Cashier)
'tables' => [
'plans' => 'plans',
'features' => 'features',
'feature_plan' => 'feature_plan',
'subscriptions' => 'subscriptions',
'feature_usages' => 'feature_usages',
'feature_subscribable' => 'feature_subscribable',
],
// Rename middleware aliases if they conflict
'middleware' => [
'subscribed' => 'subscribed',
'plan' => 'plan',
'feature' => 'feature',
],
];
use Revoltify\Subscriptionify\Models\Plan as BasePlan;
class Plan extends BasePlan
{
// Add your own columns, relationships, or methods
}
use Revoltify\Subscriptionify\Subscriptionify;
public function boot(): void
{
Subscriptionify::resolveSubscribableUsing(fn () => Team::current());
}
use Revoltify\Subscriptionify\Enums\SubscriptionStatus;
use Revoltify\Subscriptionify\Models\Contracts\HasSubscription;
class Team extends Model implements Subscribable
{
use InteractsWithSubscriptions;
protected function resolveSubscription(): ?HasSubscription
{
return $this->subscriptions()
->whereIn('status', [
SubscriptionStatus::Active,
SubscriptionStatus::Trialing,
SubscriptionStatus::PastDue, // also