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.