Charging for Consumption
Usage-based billing charges customers based on consumption rather than a fixed price. Common use cases:- API calls
- Storage (GB)
- Compute hours
- Active users
- Transactions processed
How It Works
Metered billing is three pieces:- A billable metric — a named meter that reduces raw usage events to
one quantity per period (eight aggregations, from
countto a sandboxedcustomexpression). - A charge — a pricing model (
per_unit,graduated,volume,package,percentage,graduated_percentage, ordynamic) attaching that metric to a plan. - Rating — at period close, Recurso aggregates the elapsed period’s events per metric, prices them, and adds the result to the renewal invoice as its own tax-resolved line item (billed in arrears).
1. Define a Billable Metric
The metric’scode doubles as the event dimension it aggregates, so any
events you already report keep working.
Aggregations
A
unique metric needs the property to count; percentile puts the percentile
in field_name:
weighted_sum metric time-weights a running level built from signed
deltas — ideal for per-second resources like seats or provisioned units. Report
+5 when five seats are added and -2 when two are removed; the metric bills
the average level held over the period (5 seats for 15 days + 10 for 15 days →
7.5). The starting level carries forward, so a resource active before the period
counts from day one.
A custom metric evaluates an expression against every event and sums the
results, so you can price on arithmetic over event fields without a bespoke
aggregation:
The
custom expression is sandboxed: it reads only quantity and numeric
properties.*, has no functions or external access, is bounded in time and
memory, and must return a number. It is validated when the metric is created, so
an invalid expression is rejected up front — never at invoice time.2. Attach Charges to a Plan
PUT /v1/plans/{id}/charges replaces the plan’s full charge set (same
semantics as entitlements). Rates are decimal strings in major currency
units — sub-paise pricing like ₹0.0035/call is first-class — while flat and
package amounts are integers in minor units.
Report Usage
Report usage events throughout the billing period. ThePOST /v1/usage/events endpoint accepts:
string
required
The subscription to report usage for. Must belong to your tenant (
404 otherwise).string
required
The subscription’s customer (
400 if it doesn’t match).string
required
Usage dimension/meter name, e.g.
api_calls — matches a billable metric’s code.integer
required
Amount of usage to record. Must be greater than zero.
object
Optional string attributes (max 20; keys ≤100 chars, values ≤255) —
unique metrics count distinct values of one of them.string
Your idempotency key for this event (≤255 chars) — retries collapse to the
original event instead of double-counting.
Idempotent ingestion
Add atransaction_id (your own unique key, ≤255 chars) and retries can
never double-count: a duplicate (subscription, transaction_id) collapses
to the original event — the API answers 200 with
"status": "duplicate" and the original event_id.
Batch ingestion
POST /v1/usage/events/batch accepts up to 500 events with per-item
results — one bad event never fails the batch:
Charge Models
The same 7,000-call month prices very differently depending on the model — switch the tabs to compare:- per_unit
- graduated
- volume
- package
- percentage
- graduated_percentage
- dynamic
Every unit at one rate.1,500 calls × ₹0.0035 = ₹5.25. Sub-paise rates are computed
exactly (big-rational arithmetic) and rounded half-up once per line.
Tier rules: bounds are strictly ascending; the last tier must leave
up_to null (unbounded); a tier’s optional flat_amount (minor units) is
added once when any unit lands in it. Amounts are validated at PUT time
with the same code path that rates invoices, so a config that saves cannot
fail at billing time.What the Invoice Looks Like
At period close the renewal invoice carries the flat fee (in advance, as today) plus one line per charge with usage (in arrears). Zero-usage charges add no line. Each metered line is taxed through the normal per-line GST/HSN resolution — the charge’shsn_code wins, falling back to the plan’s, then
the tenant SAC.
Rated windows are recorded in a
usage_ratings claim keyed by
(subscription, charge, period_start), so a retried invoice generation can
never bill the same window twice. Immediate cancellation generates a final
usage-only invoice for the partial elapsed window.
Bill in advance (per event)
By default usage bills in arrears at period close. Setpay_in_advance on a
charge to bill each event’s usage the moment it’s reported — captured as a
pending charge that folds onto the next invoice. Only non-cumulative models
qualify (per_unit, percentage, dynamic), since a graduated/volume price
depends on the whole period’s total.
Dimensional pricing (charge filters)
Price distinct values of one event property differently under a single charge. Setfilter_key to the property and give per-value amounts; events matching no
value fall to the charge’s base amounts.
custom/weighted_sum aggregations or the dynamic
model, which compute their quantity a different way.)
Progressive billing (interim invoices)
For high-usage customers you can bill before period close. Set aprogressive_billing_threshold (minor units) on the subscription: once accrued
usage crosses it, an interim invoice bills the delta since the last one, and the
renewal invoice settles the remainder. A per-charge watermark guarantees
every unit is billed exactly once — interim bills + close always sum to the same
total as pure arrears, no double-billing across retries or concurrent runs. A
background sweep triggers interim invoices automatically; you can also force one
with POST /v1/subscriptions/{id}/bill-usage.
Simulate a price before you ship it
POST /v1/pricing/simulate rates a proposed charge set against sample or
real usage without persisting anything — compare pricing options, see the rated
lines and a balanced GL preview, and catch a mistake before it reaches an
invoice.
Preview the Current Period
GET /v1/subscriptions/{id}/usage-amount prices the running period as of
now — what the customer would owe if invoiced this second:
Query Usage Over Time
GET /v1/usage aggregates events into time buckets (day or month) over
an arbitrary window — the endpoint behind usage charts. Scope by
subscription_id, customer_id, or both, and optionally filter to one
dimension. The window defaults to the last 30 days.
Show Customers Their Usage
GET /v1/subscriptions/{id}/usage answers the question every usage-based
product has to put on a dashboard: “you’ve used 4,231 of 10,000 API
calls this month.”
It returns each dimension’s total inside the current billing period plus
its lifetime total — and here is the wiring that makes the “of 10,000”
part work: when the customer holds an entitlement limit whose
feature_key equals the dimension name, the effective limit_value and
remaining headroom are joined into the row automatically.
limit_value: null
and remaining: null; remaining goes negative when the customer is
over their limit — a natural trigger for an upgrade prompt. See the
Entitlements guide for how limits resolve across
multiple subscriptions.
Best Practices
Use Idempotency
Always include idempotency keys to prevent duplicate charges. See the Idempotency guide.
Report Often
Report usage frequently (hourly) rather than in one batch
Show Estimates
Display current usage to customers in real-time
Set Alerts
Notify customers when approaching usage limits