Guides

Usage-Based Billing

Meter what customers use, price it on their plan, and bill it automatically.

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:

TypeQuantity for the periodNeeds fieldName
COUNTNumber of eventsNo
SUMSum of a property, e.g. tokens usedYes
MAXHighest value seen, e.g. peak seatsYes
UNIQUE_COUNTDistinct values of a property, e.g. active usersYes
LATESTLast value reported, e.g. storage usedYes
WEIGHTED_SUMValue weighted by how long it appliedYes

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 }
    ]
  }'
ModelHow it prices the quantity
STANDARDOne price per unit: properties: { "amount": "0.10", "currency": "USD" }
GRADUATEDEach range priced on its own (first 10,000 free, the rest at 0.002)
VOLUMEThe whole quantity at the price of the range it lands in
PACKAGEPer block of units: properties: { "amount": "5", "packageSize": 1000, "currency": "USD" }
PERCENTAGEA 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" }
  }'
  • transactionId makes events safe to retry: an event with a transaction ID already seen is ignored, so send the same ID again after a timeout.
  • subscriptionId takes the subscription's ID or your own external subscription ID.
  • timestamp defaults to now; events are counted in the billing period they fall in.
  • Send up to 100 at a time with POST /api/events/batch and { "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.

Copyright © 2026