Plans
Plans define what each pricing tier offers. They are managed through the admin panel and stored in the plans table.
Plan Model
The Plan model contains all fields needed to describe a pricing tier:
Plan {
name // Display name (e.g. "Pro")
slug // URL-safe identifier (e.g. "pro")
type // One of the 5 plan types
description // Short description for pricing pages
price // Monthly price in cents
yearly_price // Yearly price in cents
currency // ISO currency code (e.g. "usd")
billing_interval // "monthly", "yearly", or "one_time"
features // JSON array of feature strings
limits // JSON object of numeric limits
gateway_prices // JSON mapping gateway to price IDs
credits_amount // Number of credits (for credit plans)
meter_key // Usage metric key (for metered plans)
trial_days // Free trial duration (0 = no trial)
included_seats // Base seats included (for per-seat plans)
extra_seat_price // Price per additional seat in cents
is_active // Whether the plan is available
sort_order // Display order on pricing pages
}
Plan Types
Five constants define the available plan types:
Plan::TYPE_RECURRING // Fixed monthly or yearly subscription
Plan::TYPE_ONE_TIME // Single payment, lifetime access
Plan::TYPE_PER_SEAT // Price based on team member count
Plan::TYPE_METERED // Pay-as-you-go based on usage
Plan::TYPE_CREDITS // Prepaid credit packs
Gateway Price Mapping
The gateway_prices JSON field maps each gateway to its corresponding price IDs. This lets one plan work across multiple gateways:
{
"stripe": {
"monthly": "price_1abc123",
"yearly": "price_1xyz789"
},
"paddle": {
"monthly": "pri_01h1234",
"yearly": "pri_01h5678"
},
"lemonsqueezy": {
"monthly": "variant_12345",
"yearly": "variant_67890"
}
}
When a user subscribes, the system looks up the correct price ID for the active gateway and selected interval.
Admin Management
Plans are managed through the admin panel via AdminPlanController:
GET /api/admin/plans — List all plans
POST /api/admin/plans — Create a new plan
PUT /api/admin/plans/{plan} — Update a plan
DELETE /api/admin/plans/{plan} — Delete a plan
The admin interface provides a full CRUD for creating, editing, reordering, and toggling plans.
Default Seeder
The PlanSeeder creates a default free plan on fresh installations:
Plan::create([
'name' => 'Free',
'slug' => 'free',
'type' => Plan::TYPE_RECURRING,
'price' => 0,
'is_active' => true,
]);
This ensures every new organization can be assigned a plan immediately, even before paid plans are configured.