A plan is the central pricing configuration in Subscribd. You define plans as named entries under the plans key in config/subscribd.php, then sync them to the database with an Artisan command. Plans drive what a subscriber pays, how they are billed, and which features their subscription unlocks.
Plan definition structure
Every plan is identified by a string key (e.g., 'starter') and supports the following fields:
| Field | Type | Description |
|---|
name | string | Display name shown in UI components |
description | string | Optional human-readable description |
rule | string | Pricing rule: flat, per_unit, tiered, or metered |
price | int | Price in minor currency units (e.g., cents for USD) |
currency | string | ISO 4217 currency code (e.g., 'USD') |
interval | string | Billing interval: 'month' or 'year' |
interval_count | int | Number of intervals per cycle (e.g., 1 for monthly) |
trial_days | int | Days of free trial before billing starts |
features | array | Map of feature keys to their values (see below) |
rule_config | array | Extra config required by tiered and metered rules |
Complete example
The following config defines two flat-rate plans with feature limits:
'plans' => [
'starter' => [
'name' => 'Starter',
'description' => 'Full product access for individuals.',
'rule' => 'flat',
'price' => 1900, // $19.00/month
'currency' => 'USD',
'interval' => 'month',
'interval_count' => 1,
'trial_days' => 14,
'features' => [
'projects' => 5,
'api_access' => true,
'support' => 'email',
],
],
'pro' => [
'name' => 'Pro',
'description' => 'Everything in Starter, plus priority support.',
'rule' => 'flat',
'price' => 4900, // $49.00/month
'currency' => 'USD',
'interval' => 'month',
'interval_count' => 1,
'trial_days' => 14,
'features' => [
'projects' => null, // unlimited
'api_access' => true,
'support' => 'priority',
],
],
],
Syncing plans to the database
After editing your plan config, run the sync command to upsert records in the subscribd_plans table:
php artisan subscribd:plan sync
Other plan management commands:
php artisan subscribd:plan list
php artisan subscribd:plan deactivate starter
Plans are resolved by their config key. Renaming a key creates a new plan record and orphans the old one — existing subscriptions retain a reference to the old plan. Add a new migration or manually migrate subscriptions if you need to rename a key.
The four pricing rules
flat
per_unit
tiered
metered
A fixed price billed each cycle regardless of usage or seat count. Use this for standard SaaS memberships.'rule' => 'flat',
'price' => 1900, // $19.00/month
Price scales with a quantity you provide. Use this for per-seat or per-license billing.'rule' => 'per_unit',
'price' => 800, // $8.00 per seat/month
The quantity is set when subscribing or updated via UpdateQuantity. Graduated pricing: different rates apply to each tier of volume. Requires a rule_config.tiers array.'rule' => 'tiered',
'price' => 0,
'rule_config' => [
'tiers' => [
['up_to' => 1000, 'unit_amount' => 5, 'flat_amount' => 0],
['up_to' => 10000, 'unit_amount' => 3, 'flat_amount' => 2000],
['up_to' => null, 'unit_amount' => 1, 'flat_amount' => 5000],
],
],
up_to => null marks the final unlimited tier. flat_amount is a per-tier fixed fee added when that tier is reached. Charge for actual consumption reported during the billing period. Requires a rule_config.unit_price.'rule' => 'metered',
'price' => 0, // base price is 0; usage drives the bill
'rule_config' => [
'unit_price' => 2, // $0.02 per unit
],
Usage is recorded with the RecordUsage action and summed at period end.
The features map
The features array on a plan is stored as JSON and drives the entitlement system. Three value types are supported:
| Value | Meaning |
|---|
true | Feature is enabled; binary access check passes |
false | Feature is explicitly disabled |
null | Feature is available with no numeric limit (unlimited) |
| integer | Feature is available up to this numeric limit |
| string | Feature has a named value (e.g., 'priority' support tier) |
'features' => [
'projects' => 5, // limited to 5
'api_access' => true, // boolean access
'exports' => null, // unlimited
'support' => 'email', // named value
],
See Entitlements for how to check these values at runtime.