Overview
Use Limitr to monetize usage.
Monetizing usage means defining credits with a price, and entitlements that define control behavior (limits) for customers that reference credits (and prices).
What gets charged is a single rule: overage can be billed, anything under the defined limit is not (it's included with the plan).
Limits have one of 3 modes:
hard— never charges, overage not allowed as usage can never go above the limitsoft— allows overage, charges for the usage obove the limit at a price defined by the credit usedobserve— never charges, overage cannot happen, analytics/metering only
An entitlement limit can be thought of as the included plan usage, and it is valid to set it to zero — counting all usage as overage and billing accordingly if desired.
The Credit is the only concept in Limitr that relates to money — any unit of value with a price, cost, or unit that matters to you or your customer (real or "fake") is a credit.
Limitr Cloud Integration
Limitr Cloud is a fully managed and hosted platform for atomic usage ledgers per customer, invoicing, per-customer rates & limits, revenue analytics, payments/billing integrations — a fully built out platform for usage monetization.
These docs define local policy definition examples (open-source & offline), which are not by themselves enough for usage monetization. With Limitr Cloud, your hosted policy is pulled down separately server-side for secure and accurate billing. The client-side local engine is responsible for usage events only — all prices, overhead, etc. is display-only.
Client integration for Cloud, however, is the same as these docs apart from using Limitr.cloud({token: apiToken}) instead of Limitr.new('policy: {}').
Customer meters are independent of invoice/ledger quantities — meter resets are not required to align with billing periods. Some credits like AI tokens are typically reset in the ledger per billing period, where credits like seats are not.
This is obvious in the Cloud UI, however, keep this in mind for the following examples, as any resets defined outline meter resets, not ledger resets (ledgers do not exist in the open-source engine).
Our team is always here to support your needs, and usage control/monetization often has subtle differences product to product. The following examples give a high-level introduction to common patterns, but please reach out and we'll make sure you're setup for long-term success.
Basic seats
3 included with plan, no charges
A starter plan that entitles a customer to a maximum of 3 seats, and does not allow them to go over.
policy:
credits:
seat:
description: A single seat
plans:
starter:
entitlements:
seats:
limit:
credit: seat
value: 3
mode: hard
1 included with plan, $10/seat for every additional
A starter plan that includes 1 seat, and charges $10 per additional seat.
policy:
credits:
seat:
description: A single seat
price: { amount: 10 }
plans:
starter:
entitlements:
seats:
limit:
credit: seat
value: 1
mode: soft
$39.99 for every seat
A starter plan that entitles customers to seats, charging for every one of them.
policy:
credits:
seat:
description: A single seat
price: { amount: 39.99 }
plans:
starter:
entitlements:
seats:
limit:
credit: seat
value: 0 # every increment is overage
mode: soft
Monthly plan subscription
A soft limit that immediately charges overage, incremented once per customer and never reset.
Any one-time purchase can be modeled this way — increment to purchase. Purchases like subscriptions repeat, where others, like an onboarding fee, don't. You can specify this right within the Limitr Cloud UI.
Topup purchases have a dedicated path, they are independent from entitlements and limits.
policy:
credits:
starter_subscription:
price: { amount: 599.99 }
pro_subscription:
price: { amount: 899.99 }
plans:
starter:
entitlements:
subscription:
limit:
credit: starter_subscription
value: 0
mode: soft
pro:
entitlements:
subscription:
limit:
credit: pro_subscription
value: 0
mode: soft
Each plan has a subscription entitlement. In code, you'd increment this with policy.increment(userId, 'subscription'), regardless of plan.
In the SDK, there is a shortcut for adding a plan subscription quantity: ensureCustomerPlanQuantity. By default, this will increment a subscription entitlement if the meter value is less than 1. The subscription entitlement name can be set to the name of your choice by defining a string subscription field on each plan object.
AI Tokens
For all discrete usage (tied to the real world), all entitlements should use credits defined as specificly as possible, so that usage can be attributed correctly to that vendor.
To translate raw vendor usage into abstract outcomes, like run_success or anything like that, the pipeline should have all steps defined as discrete, vendor specific credits. There should then be an abstract run_successes entitlement and credit that gets incremented seperately at the end, optionally including spend, run, or customer metadata for additional attribution. Invoice line items would then include all usage, correctly accounted for, in all pipeline scenarios.
Multiple entitlements are often stacked or combined to create desired behaviors.
Claude Sonnet 5 Input & Output
Defining separate input and output credits for repackaged Claude Sonnet 5 tokens.
policy:
credits:
claude_sonnet_5_input:
description: Input token for Claude Sonnet 5 ($3/MTok overhead)
price: { amount: 0.000006 } # 50% margin per token
overhead_cost: 0.000003
claude_sonnet_5_output:
description: Output token for Claude Sonnet 5 ($15/MTok overhead)
price: { amount: 0.00003 } # 50% margin per token
overhead_cost: 0.000015
plans:
starter:
entitlements:
home_page_ai_chat_input_tokens: # feature/product specific entitlement, not credit specific
limit:
credit: claude_sonnet_5_input
value: 0
mode: soft
resets: true
reset_sch: 'monthly:1' # meter resets on the 1st of every month (UTC, lazy resets)
home_page_ai_chat_output_tokens:
limit:
credit: claude_sonnet_5_output
value: 0
mode: soft
resets: true
reset_sch: 'monthly:1'
Monetization/Billing Only Usage
If you want to bill for usage only, it would then look something like:
const [inputCount, outputCount] = await callLLM(prompt);
// charge for specific vendor-counted input and output tokens (monetization purposes, not control purposes)
await limitrPolicy.allow(userId, 'home_page_ai_chat_input_tokens', inputCount);
await limitrPolicy.allow(userId, 'home_page_ai_chat_output_tokens', outputCount);
Control Usage
If you want to gate usage, allow(...) always returns a boolean value that you can use to do so.
const inputCount = await freeLLMCount(prompt);
if (await limitrPolicy.allow(userId, 'home_page_ai_chat_input_tokens', inputCount)) {
const [_, outputCount] = await callLLM(prompt);
await limitrPolicy.allow(userId, 'home_page_ai_chat_output_tokens', outputCount);
}
For controlling or gating AI usage, I prefer to split the responsibility completely. 2+ entitlements dedicated to just the billing, then one or more completely separate entitlement(s) and credit(s) for control.
Sounds like it would add complexity, but in real life it simplifies things, and plays much nicer with custom tooling & helpers.
This enables extremely accurate billing tied to the vendor, and also the flexibility for me to gate and control tokens on my own terms, with my own preferred counting.
I would charge for the vendor tokens, and not for the control tokens. Pattern is top of function/pipeline/step count and gate (return early) with control only entitlements, then call into LLM/vendor, then at the bottom allow(...) with entitlements responsible for billing the user.
// gate/control usage
const controlCount = await countTokensMyWay(prompt);
if (!await limitrPolicy.allow(userId, 'control_only_tokens', controlCount)) return;
// check does not change meters/state, just checks if allow would be true off of the rough count
// optional part of the control step for spend caps to deny when only the vendor tokens have a price & over the cap
if (!await limitrPolicy.check(userId, 'home_page_ai_chat_input_tokens', controlCount)) return;
const [accurateInputCount, accurateOutputCount] = await callLLM(prompt);
await limitrPolicy.allow(userId, 'home_page_ai_chat_input_tokens', accurateInputCount);
await limitrPolicy.allow(userId, 'home_page_ai_chat_output_tokens', accurateOutputCount);
GPU Seconds
The Limitr runtime has native types for time.
policy:
credits:
gpu_second:
description: One second of GPU time
price: { amount: 0.001 }
overhead_cost: 0.00012
stof_units: s
plans:
starter:
entitlements:
gpu_time:
limit:
credit: gpu_second
value: 2min # 2 minutes included before overage starts
mode: soft
Unit conversions happen automatically:
// meter 34 milliseconds, bill for any overage
await limitrPolicy.allow(userId, 'gpu_time', 34 + 'ms');
// SDK always returns values in units of the credit (seconds)
// Fun fact, remaining(..) takes credit grants into account by default using the exchange table (if applicable)!
// Means if the user has 50 SuperCoolAppCredits for example, we'd convert those to gpu_seconds and tell you how much you have left to use right now
const remainingSeconds = await limitrPolicy.remaining(userId, 'gpu_time');
Outcomes
An outcome is an abstract, app/product specific credit. Depending on the product, it can be something very tried and true, like api_call or tool_call, or, it can be something more specific to the customer, like call_resolved or meeting_booked.
In Limitr, they work the same as any other credit:
policy:
credits:
api_call:
description: One API call
price: { amount: 0.001 }
call_resolved:
description: An AI agent resolved a call
price: { amount: 0.10 }
plans:
starter:
entitlements:
api_calls:
limit:
credit: api_call
value: 0 # charge for all of them!
mode: soft
calls_resolved:
limit:
credit: call_resolved
value: 10 # plan includes 10 call resolutions, bills for everything after
mode: soft
Implementation typically looks something like:
// Gate/control on whether the outcome would be allowed with check(...) - no meters change
if (!await limitrPolicy.check(userId, 'calls_resolved', 1)) return;
const metadata = {
/*
* Optional outcome metadata - spend, margin, details, whatever.
* Useful for agent, pipeline, etc. usage attribution & analytics across your product.
*/
};
{
/*
* Pipeline of usage to reach outcome, populates metadata.
* May or may not have many vendor calls, or discrete allow(...) steps for control/billing.
*/
}
// Meter the outcome, bill for any overage, attach the metadata to the event (recorded in Limitr Cloud)
await limitrPolicy.allow(userId, 'calls_resolved', 1, metadata);
Any kind of usage
Limitr can monetize and control any type of usage. If it can be counted, it can be limited, capped, billed, and otherwise controlled.
The catch-all credit units are int or float, able to count anything. But Stof also has native types for things like: time (s, ms, hr, etc.), memory (bytes, GiB, TB, MB, etc.), mass (kg, g, lb, etc.), length (m, miles, cm, etc.), angles (deg, rad), temperature (F, C, K), and more that can also be used.
If you think you have the craziest type of usage, message or email me (cj@limitr.dev) — I want to here about it, and there might be something in it for you if it's sufficiently wacky :)