Defining Features
Learn how to define and use features in BillAI to control access to your app's functionality.
What are Features?
Features are the building blocks of your pricing plans. Each feature represents a capability or resource that users can access based on their subscription plan.
When you create a plan in BillAI, you define which features are included and optionally set limits for usage-based features.
Feature Types
Boolean Features
Simple on/off access control. Either a user has access to the feature, or they don't.
Usage-based Features
Features with a numeric limit. Track usage and automatically deny access when limits are exceeded.
Defining Features in Plans
When creating a plan in the dashboard, you can add features using the Features Editor. Here's how to define each type:
Boolean Features
Add a feature with a boolean value of true.
{
"premium_export": true,
"ai_summaries": true,
"advanced_settings": true
}Usage-based Features
Add a feature with a numeric value representing the limit.
{
"api_calls": 1000, // 1000 API calls per month
"storage_mb": 500, // 500 MB storage
"ai_tokens": 10000 // 10,000 AI tokens
}Combined Example
Most plans will have a mix of both types:
{
// Boolean features
"premium_export": true,
"ai_summaries": true,
"priority_support": true,
// Usage-based features
"api_calls": 10000,
"storage_mb": 2048,
"ai_tokens": 50000
}Checking Features in Code
Boolean Features
const result = await access.check(userId, 'premium_export');
if (!result.granted) {
// Feature not available - show upgrade prompt
return {
error: 'upgrade_required',
upgradeUrl: result.upgradeUrl
};
}
// Proceed with the feature
return performExport();Usage-based Features
// Check and increment usage in one call
const result = await access.check(userId, 'api_calls', {
increment: 1, // Count this API call
});
if (!result.granted) {
// Limit exceeded
return {
error: 'limit_exceeded',
message: `API limit reached (${result.usage}/${result.limit})`,
upgradeUrl: result.upgradeUrl,
};
}
// Proceed with the API call
return processRequest();Check Without Incrementing
To check remaining usage without counting, omit the increment option:
// Just check, don't increment
const result = await access.check(userId, 'api_calls');
const remaining = (result.limit || 0) - (result.usage || 0);
console.log(`Remaining API calls: ${remaining}`);Feature Naming Best Practices
Use snake_case
Feature names should be lowercase with underscores: premium_export, api_calls
Be descriptive
Choose names that clearly describe the feature: ai_text_generation instead of just ai
Include unit for usage features
Add the unit to make limits clear: storage_mb, bandwidth_gb
Feature names are case-sensitive
api_calls and API_Calls are different features. Stick to one convention.
Plan Design Tips
Start with a Free plan
Create a Free plan with limited features. This lets users try your app before committing. Set usage limits low enough to demonstrate value but encourage upgrades.
Gate premium capabilities, not core functionality
Let users accomplish basic tasks for free. Reserve premium features for power users who will see the value in paying.
Use meaningful limits
Set usage limits that match real usage patterns. Too low frustrates users, too high and there's no incentive to upgrade.
Provide clear upgrade paths
When access is denied, show users exactly what they get by upgrading. Use the upgradeUrl from the check result.
Example Plan Structure
Here's a typical three-tier pricing structure:
Free
$0/month
{
"basic_export": true,
"api_calls": 100,
"storage_mb": 50
}Pro
Popular$19/month
{
"basic_export": true,
"premium_export": true,
"ai_summaries": true,
"api_calls": 5000,
"storage_mb": 1024
}Enterprise
$99/month
{
"basic_export": true,
"premium_export": true,
"ai_summaries": true,
"priority_support": true,
"api_calls": 100000,
"storage_mb": 10240
}