Usage-Based Billing
Usage billing has three parts: a billable metric says what to count, a charge puts a price on that metric in a plan, and events report what each subscription used. At the end of each billing period, usage is aggregated per subscription and invoiced with the plan's fixed price.
1. Define a billable metric
curl -X POST https://api.pimabill.com/api/billable-metrics \
-H "Authorization: Bearer sk_live_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"name": "API Calls",
"code": "api_calls",
"aggregationType": "COUNT"
}'
code is what your events refer to. aggregationType decides how events become a quantity:
| Type | Quantity for the period | Needs fieldName |
|---|---|---|
COUNT | Number of events | No |
SUM | Sum of a property, e.g. tokens used | Yes |
MAX | Highest value seen, e.g. peak seats | Yes |
UNIQUE_COUNT | Distinct values of a property, e.g. active users | Yes |
LATEST | Last value reported, e.g. storage used | Yes |
WEIGHTED_SUM | Value weighted by how long it applied | Yes |
Set recurring: true for quantities that carry over between periods (such as seats). Add filters to price the same metric differently by property value, for example by region.
2. Price it on a plan
A charge attaches a metric to a plan with a pricing model:
curl -X POST https://api.pimabill.com/api/charges \
-H "Authorization: Bearer sk_live_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"planId": "plan_pro",
"billableMetricId": "bm_api_calls",
"chargeModel": "GRADUATED",
"invoiceDisplayName": "API calls",
"graduatedRanges": [
{ "fromValue": 0, "toValue": 10000, "perUnitAmount": 0 },
{ "fromValue": 10001, "perUnitAmount": 0.002 }
]
}'
| Model | How it prices the quantity |
|---|---|
STANDARD | One price per unit: properties: { "amount": "0.10", "currency": "USD" } |
GRADUATED | Each range priced on its own (first 10,000 free, the rest at 0.002) |
VOLUME | The whole quantity at the price of the range it lands in |
PACKAGE | Per block of units: properties: { "amount": "5", "packageSize": 1000, "currency": "USD" } |
PERCENTAGE | A share of a value in the events, with optional fixed amounts and free units |
billingTiming is IN_ARREARS (bill what was used, at the end of the period; the default) or IN_ADVANCE. A range's flatAmount adds a fixed fee for entering it, and minAmountCents sets a floor for the charge.
3. Send usage events
curl -X POST https://api.pimabill.com/api/events \
-H "Authorization: Bearer sk_live_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"transactionId": "req_8f2c91",
"subscriptionId": "sub_abc123",
"code": "api_calls",
"timestamp": "2026-10-25T12:00:00Z",
"properties": { "region": "kampala" }
}'
transactionIdmakes events safe to retry: an event with a transaction ID already seen is ignored, so send the same ID again after a timeout.subscriptionIdtakes the subscription's ID or your own external subscription ID.timestampdefaults to now; events are counted in the billing period they fall in.- Send up to 100 at a time with
POST /api/events/batchand{ "events": [ ... ] }.
GET /api/events/subscription/{subscriptionId} lists what a subscription has reported, which helps when a customer asks about a bill.
Per-customer prices
To give one customer different usage prices without a new plan, use plan overrides (/api/plan-overrides): they replace a plan's prices for a single customer.