Credits
Units your pricing is built on.
Every entitlement limit is denominated in a credit. Every meter tracks consumption in a credit's units. Every margin calculation runs through a credit's overhead_cost and price.
Discrete vs abstract
Discrete credits map to something real: an AI input token, a GPU second, a megabyte of storage. They carry overhead_cost (what it costs you, per unit) and price (what you charge, per unit). This is what makes per-customer margin tracking accurate.
Abstract credits are conceptual units — "AI Credits", "messages", "reports". No cost attached directly. They map to discrete credits through the exchange table. Use them when you want a customer-facing unit that doesn't expose per-token or per-MB pricing, or when you want a single credit pool to drain across multiple discrete entitlements.
Both types use the same schema. The distinction is whether you define overhead_cost, price, and stof_units.
Schema
credits:
<credit-id>:
description: string # Optional. Human-readable description.
label: string # Human-facing label. Default: 'Credit'.
unit: string # Singular unit label. Default: 'credit'.
overhead_cost: float # Cost per unit (in runes). Default: 0.
pricing_model: string # 'flat' | 'tiered' | 'volume' | 'stairstep'. Default: 'flat'.
price: # Required if pricing_model is 'flat'. Null otherwise.
amount: float # Price per unit (in runes).
tiers: # Required if pricing_model is tiered/volume/stairstep.
- up_to: float # Upper bound (exclusive). Omit on the last tier for infinity.
price:
amount: float
stof_units: string # Unit type for this credit. Default: 'float'.
resets: bool # Whether this credit's meter can reset. Default: false.
Fields
description
Optional. Appears in event payloads and customer state objects. Useful for debugging and support tooling.
label
Human-facing label. Shown in the Cloud dashboard and available in the customer object for UI display.
unit
Singular label for one unit of this credit. Used in display contexts.
overhead_cost
What this credit costs you per unit, expressed in runes (1 rune = 1 USD by default). Must be ≥ 0. Used by customerMarginSnapshot() to compute cost-to-serve. The more accurately this reflects your actual provider cost, the more accurate your margin data.
pricing_model
Controls how overage is billed on soft-limit entitlements. Must be one of:
| Model | Behavior |
|---|---|
flat | A single price per unit applied uniformly. Requires price.amount. Default. |
tiered | Graduated pricing — each consumption band has its own per-unit rate, applied only to units within that band. Requires tiers. |
volume | Total consumption determines a single per-unit rate, applied retroactively to all units. Requires tiers. |
stairstep | Total consumption determines which band you're in; you pay that band's flat fee regardless of where within the band you land. Requires tiers. |
price
Required when pricing_model is 'flat'. Must be null for all other pricing models.
price:
amount: 0.000004 # per unit, in runes
tiers
Required when pricing_model is 'tiered', 'volume', or 'stairstep'. A list of price tier objects. The last tier must omit up_to to represent infinity. Tiers are validated and sorted at policy load time.
tiers:
- up_to: 100000
price: { amount: 0.000006 }
- up_to: 1000000
price: { amount: 0.000005 }
- # last tier: no up_to = infinity
price: { amount: 0.000004 }
stof_units
The unit type for this credit. When set, Limitr automatically converts values passed to allow() or increment() into the credit's canonical units before metering.
stof_units: MB # allow('user', 'storage', '2GB') → meters 2000
stof_units: min # allow('user', 'gpu_min', '42seconds') → meters 0.7
stof_units: int # token counts — no unit conversion, integer
stof_units: float # (default) no conversion performed
Valid units include SI storage (B, KB, MB, GB, TB, KiB, MiB, GiB, TiB), time (ms, s, min, hr, day), and others defined in the Stof runtime.
Entitlement limit values are not auto-converted. Set stof_units to the unit you want the limit expressed in, and pass values in compatible units when calling allow().
resets
Whether meters for this credit can reset on a schedule. When true, the reset schedule is defined on the entitlement limit (limit.resets, limit.reset_inc) — not on the credit itself. This flags the credit as reset-capable; the entitlement limit controls when.
Examples
Discrete: AI token credit with flat pricing
credits:
sonnet_input:
description: Claude Sonnet 4 input tokens
overhead_cost: 0.000003 # $3.00 per 1M tokens (your cost)
pricing_model: flat
price:
amount: 0.000004 # $4.00 per 1M tokens (customer price) → $1 margin per 1M
stof_units: int
resets: true
Discrete: storage with tiered pricing
credits:
gb_storage:
description: Object storage
overhead_cost: 0.00002
pricing_model: tiered
tiers:
- up_to: 10
price: { amount: 0.023 }
- up_to: 50
price: { amount: 0.022 }
-
price: { amount: 0.021 }
stof_units: GB
Abstract: customer-facing credit pool
credits:
ai_credit:
description: AI Credits
label: AI Credit
unit: credit
# No overhead_cost, no price, no stof_units
# Maps to discrete credits via the exchange table
SDK
policy.credit()
Returns the credit record for a given credit ID.
const credit = await policy.credit('sonnet_input');
// { description, label, overhead_cost, pricing_model, price, stof_units, resets }
policy.creditFor()
Returns the credit record for the credit backing a specific entitlement. id can be a plan ID or a customer ID.
const credit = await policy.creditFor('user_123', 'chat_input');
policy.creditExchange()
Converts a value from one credit to another using the exchange table. Returns null if no exchange path exists.
// How many sonnet input tokens does 10 ai_credits buy?
const tokens = await policy.creditExchange('ai_credit', 'sonnet_input', 10);
policy.remainingCredit()
Returns the total remaining balance of a specific credit across all of a customer's grants, after exchange conversion. Does not include entitlement meter state.
const remaining = await policy.remainingCredit('user_123', 'ai_credit');