Map your pricing to a policy
Start from your pricing page, or the one you want. Every line on it maps to a piece of a policy.
The pricing page
| Starter (free) | Team ($49/mo) | Enterprise | |
|---|---|---|---|
| Projects | 3 | Unlimited | Unlimited |
| AI assistant | 50k tokens a month | 2M tokens a month, then $20 per million | Contract |
| Seats | 1 | 5 included, $12 per extra seat | Contract |
| API | 100k requests a month | Contract | |
| CSV export | Yes | Yes | Yes |
| PDF export | Yes | Yes | |
| SSO | Yes | ||
| Token packs | 1M tokens for $15 |
Step by step
- List what you count. Each countable thing is a credit: projects, AI tokens, seats,
requests. Put the price on the credit when you charge for it past an allowance, and the cost when it costs you
something. When a model's input and output are priced differently, give each its own credit
(
sonnet_input,sonnet_output); see AI costs per model. - One plan per column. The plan customers get by default gets
default: true. - One entitlement per row. Use the same entitlement name in every plan, so your code doesn't care which plan a
customer is on.
- A Yes (a feature) is an entitlement with no limit.
- A number is a limit. Pick the mode:
hardwhen the plan stops there,softwhen usage past it is billed,observewhen it's only tracked. - Unlimited is a feature (no limit), or an
observelimit when you still want to count it. - A blank is no entitlement in that plan: the call is denied.
- Monthly allowances reset.
resets: true, reset_sch: 'monthly:1'for calendar months, orreset_inc: 30daysfor 30 days from first use. - The plan fee is a
subscriptionentitlement metered in a credit priced at the fee. See Plan fees. - Packs are topups.
- Enterprise is usually a plan with generous limits that you adjust per customer with overrides and gives, rather than a plan per customer.
- Protection you don't sell (a rate limit, an abuse ceiling) can share the row's entitlement when the two limits are the same, or get an entitlement of its own when they differ. See Rate limits.
The policy
policy: {
credits: {
project: { label: 'Project' }
// You charge $20 per million tokens, and they cost you $8 per million.
ai_token: { label: 'AI token', price: { amount: 0.00002 }, overhead_cost: 0.000008 }
seat: { label: 'Seat', price: { amount: 12 } }
request: { label: 'API request' }
team_month: { label: 'Team plan, monthly', price: { amount: 49 } }
}
plans: {
starter: {
label: 'Starter'
default: true
entitlements: {
projects: { limit: { credit: 'project', value: 3 } }
ai_assistant: {
limit: {
credit: 'ai_token', value: 50_000
resets: true, reset_sch: 'monthly:1'
}
}
seats: { scope: 'org', limit: { credit: 'seat', value: 1 } }
export_csv: {}
}
}
team: {
label: 'Team'
entitlements: {
subscription: {
limit: {
credit: 'team_month', mode: 'soft', value: 0
resets: true, reset_sch: 'monthly:1'
}
}
// unlimited, still counted
projects: { limit: { credit: 'project', mode: 'observe', value: 0 } }
ai_assistant: {
limit: {
credit: 'ai_token', mode: 'soft', value: 2_000_000
resets: true, reset_sch: 'monthly:1'
}
}
seats: { scope: 'org', limit: { credit: 'seat', mode: 'soft', value: 5 } }
api: {
limit: {
credit: 'request', value: 100_000
resets: true, reset_sch: 'monthly:1'
}
}
export_csv: {}
export_pdf: {}
}
topups: {
tokens_1m: { credit: 'ai_token', value: 1_000_000, price: { amount: 15 } }
}
}
enterprise: {
label: 'Enterprise'
hidden: true
entitlements: {
projects: { limit: { credit: 'project', mode: 'observe', value: 0 } }
ai_assistant: {
limit: {
credit: 'ai_token', mode: 'soft', value: 20_000_000
resets: true, reset_sch: 'monthly:1'
}
}
seats: {
scope: 'org'
limit: { credit: 'seat', mode: 'soft', value: 50 }
}
api: {
limit: {
credit: 'request', mode: 'soft', value: 5_000_000
resets: true, reset_sch: 'monthly:1'
}
}
export_csv: {}
export_pdf: {}
sso: {}
}
}
}
}
Your code is the same for every plan:
await limitr.ensureCustomer(orgId, 'team', 'org');
// On their org's plan
await limitr.ensureCustomer(userId, '', 'user', name, [orgId]);
if (!(await limitr.allow(userId, 'projects', 1))) return upgrade('projects');
if (!(await limitr.allow(userId, 'export_pdf'))) return upgrade('export_pdf');
Pricing models
| Model | In a policy |
|---|---|
| Usage-based (pay for what you use) | A soft limit with value: 0: every unit is billed at the credit's price. |
| AI usage per model | A credit per model and direction, each billed at its own price. See AI costs per model. |
| Allowance plus overage | A soft limit at the allowance, resetting monthly. Bill meter-overage. |
| Hard caps per tier | Hard limits; the upgrade is the way past them. |
| Seats | A seats entitlement with scope: 'org', increment on invite and decrement on removal. See Seats. |
| Prepaid credits | Limits at 0, priced credits, and a shared credit granted by topups. See Prepaid credits. |
| Flat fee | A subscription entitlement priced at the fee. |
| Volume discounts | A credit with tiered, volume, or stairstep pricing. |
| Hybrid | Any mix of the above in one plan: a fee, seats, and metered AI usage. |
| Spend limits | Spend caps, per customer or shared across an org. |
| Free trial of a feature | A give with an expiry. |
Before you ship it
- Validate it:
Limitr.newthrows on mistakes, andvalid()checks it in CI. - Test it: write the behavior you expect as tests.
- Check its margin:
marginSnapshot(plan, usage)prices hypothetical usage for a plan (Cost and margin).