Plans & Roles
Your pricing model is your business model. The roles you define determine who can do what — both on your team and inside your customers' teams. This page lets you configure all of it from the admin panel, without writing code or redeploying.
Subscription Plans
Plans define what your customers get and what they pay. Every SaaS pricing page is backed by a set of plan objects that control which features are unlocked, what resource limits apply, and how the payment gateway charges for them.
The AdminPlanController provides full CRUD so you can create, modify, and retire plans as your product evolves.
Why This Matters
Most SaaS products change their pricing 3-5 times in the first two years. Maybe you launch with two plans and realize you need a free tier to drive adoption. Maybe an enterprise customer needs a custom plan with higher limits. With plan management in the admin panel, your product manager can make these changes without waiting for an engineering deploy.
Endpoints
GET /api/admin/plans # List all plans
POST /api/admin/plans # Create a new plan
PUT /api/admin/plans/{id} # Update an existing plan
DELETE /api/admin/plans/{id} # Delete a plan (only if no active subscribers)
When you update a plan, changes apply to new subscriptions immediately. Existing subscribers remain on their current terms until renewal — you will not accidentally change what a paying customer is getting mid-cycle.
Plans with active subscribers cannot be deleted. Deactivate them instead by setting is_active: false. Deactivated plans stop appearing on the pricing page but existing subscribers continue uninterrupted.
Plan Fields Explained
name— Display name shown on the pricing page and in invoices (e.g., "Pro", "Business", "Enterprise").slug— URL-safe identifier used in code and API calls (e.g., "pro", "business"). Cannot be changed after creation because it may be referenced in feature checks throughout your codebase.type— The billing model. Five options, each suited to different business models:- free — No payment required. Use for freemium tiers that let users try the product with limited features. Good for driving signups and building a user base.
- recurring — Fixed monthly or yearly subscription. The most common SaaS model. Predictable revenue, easy for customers to understand.
- lifetime — One-time payment for permanent access. Useful for AppSumo-style launches or early-bird deals. Generates cash upfront but no recurring revenue.
- usage — Charges based on consumption (API calls, storage, messages sent). Good for infrastructure products and APIs where usage varies wildly between customers.
- per_seat — Charges per team member. Good for collaboration tools where value scales with team size. Each seat beyond the included count is billed at the
extra_seat_price.
price_monthly/price_yearly— Display prices for the pricing page. The actual charge amount is determined by thegateway_pricesconfigured in your payment gateway.features— An array of feature keys that this plan unlocks. These are the strings you check in your application code (e.g.,api_access,priority_support,custom_domain). When a user tries to access a feature, the system checks whether their organization's plan includes it.limits— Resource caps that the plan enforces. Unlike features (which are binary on/off), limits are numeric thresholds. Common limits include:members— Maximum team members in the organization.storage_gb— Maximum file storage.api_requests_per_month— API call quota.projects— Maximum number of projects, boards, or whatever your primary resource is.
When a limit is reached, the application blocks further resource creation and prompts the user to upgrade.
gateway_prices— Maps plan intervals to price IDs in your payment gateway. This is what connects your plan to the actual charge. You create the price in Stripe (or your gateway's dashboard), copy the price ID, and paste it here."gateway_prices": { "stripe": { "monthly_price_id": "price_1abc...", "yearly_price_id": "price_2def..." } }If you support multiple gateways, add price IDs for each one. The system uses whichever gateway is active in your billing settings.
trial_days— Number of days of free access before payment is required. Set to0for no trial. 14 days is standard for B2B SaaS. Trials let customers experience the product before committing — they significantly improve conversion rates.included_seats— Number of team members included in the base price (for per-seat plans). For example, if your plan costs $49/month and includes 5 seats, the first 5 members are free.extra_seat_price— Price per additional seat beyond the included count (for per-seat plans). For example, $10/month per extra member.is_active— Whether this plan is visible on the pricing page and available for new subscriptions. Set tofalseto retire a plan without affecting existing subscribers.
Example: Creating a Pro Plan
{
"name": "Pro",
"slug": "pro",
"type": "recurring",
"price_monthly": 29.00,
"price_yearly": 290.00,
"features": [
"unlimited_projects",
"api_access",
"priority_support",
"custom_domain",
"advanced_analytics"
],
"limits": {
"members": 25,
"storage_gb": 50,
"api_requests_per_month": 100000
},
"gateway_prices": {
"stripe": {
"monthly_price_id": "price_1NxHk2...",
"yearly_price_id": "price_1NxHk3..."
}
},
"trial_days": 14,
"included_seats": 5,
"extra_seat_price": 10.00,
"is_active": true
}
This creates a Pro plan at $29/month ($290/year, saving the customer ~17%). It includes 5 team seats with additional seats at $10/month each. New subscribers get a 14-day trial. The plan unlocks 5 features and sets limits on members (25), storage (50 GB), and API requests (100k/month).
Global Roles
Global roles control who on your team can access the admin panel and what they can do there. These are completely separate from organization roles — a super admin is not a member of any customer organization.
Why This Matters
Not everyone on your team needs full admin access. Your co-founder needs everything. Your support agent needs to look up users and view subscriptions, but should not be able to change billing settings or delete accounts. Your accountant might need to see invoices but nothing else.
Built-in Roles
- super_admin — Full access to everything in the admin panel. Can manage users, organizations, plans, settings, and all other admin features. Reserve this for founders and senior engineers.
- support_agent — Read-only access to admin views. Can look up users, view organization details, and see subscription status, but cannot modify anything. Give this to customer support team members.
When to Create Custom Roles
As your team grows, you will need more granular access. Common custom roles:
- billing_manager — Can manage plans, view subscriptions, and issue refunds, but cannot access user management or platform settings. Good for a finance team member or billing operations person.
- content_manager — Can edit email templates and documentation, but nothing else. Good for a marketing team member who writes customer-facing copy.
- developer — Can view audit logs, manage feature flags, and flush cache, but cannot modify billing or user data. Good for on-call engineers who need to troubleshoot production issues.
Endpoints
GET /api/admin/roles # List all global roles
POST /api/admin/roles # Create a new role
PUT /api/admin/roles/{id} # Update a role
DELETE /api/admin/roles/{id} # Delete a role
Assigning Permissions
POST /api/admin/roles/{id}/permissions
{
"permissions": [
"admin.users.view",
"admin.users.edit",
"admin.settings.view",
"admin.plans.view",
"admin.plans.edit"
]
}
Permissions are granular and scoped to admin features. A role can have any combination. The naming convention is admin.{resource}.{action}, making it easy to understand what each permission grants.
Organization Role Templates
Organization roles control what your customers' team members can do within their organization. You define the templates; every organization gets these roles by default.
Why This Matters
Your customers need different levels of access within their teams. The CEO needs full control. The developer needs API key access. The intern needs read-only access. If you only have one "member" role, your customers will ask for more — and you want to have the answer ready.
Default Role Templates
- owner — Full control of the organization: billing, team management, settings, data deletion. Every organization has exactly one owner. Ownership can be transferred to another admin.
- admin — Can do almost everything the owner can: invite members, change roles, manage projects, view billing. Cannot delete the organization or transfer ownership.
- member — Standard access: can use the product, create and edit their own resources, but cannot manage the team or billing. This is the default role for invited users.
When to Add Custom Role Templates
Add custom roles when your customers' teams have specialized access needs:
- viewer — Read-only access to everything. Cannot create, edit, or delete anything. Useful for stakeholders, clients, or auditors who need visibility without the ability to make changes.
- developer — Member access plus the ability to create and manage API keys. Useful for technical team members who need programmatic access but should not manage billing or invite users.
- billing_admin — Can view and manage the organization's subscription, payment method, and invoices, but cannot access project data or manage team members. Useful for finance departments at larger companies.
- guest — Limited access to specific resources (e.g., one project). Useful for external collaborators like freelancers or agency partners who need access to a subset of the organization's data.
Endpoints
GET /api/admin/org-roles # List all role templates
POST /api/admin/org-roles # Create a new template
PUT /api/admin/org-roles/{id} # Update a template
DELETE /api/admin/org-roles/{id} # Delete a template
Assigning Permissions to a Template
POST /api/admin/org-roles/{id}/permissions
{
"permissions": [
"projects.create",
"projects.edit",
"projects.delete",
"members.invite",
"billing.view"
]
}
List Available Organization Permissions
GET /api/admin/org-permissions
Returns the complete list of permissions that can be assigned to organization roles, grouped by feature area. Use this endpoint to populate a permissions picker in the admin UI. Permissions are organized by module (e.g., projects.*, members.*, billing.*, api_keys.*), making it easy to grant access to entire feature areas at once.