Overview
Usage-based billing covers scenarios like API calls, AI tokens, compute hours, storage GB, and messages. Aviate metering lets you create billing meters, record raw usage events, and connect them to usage-based plans for automatic invoice generation.
The Kill Bill core usage APIs support recording rolled-up usage data, but aggregation must be performed outside Kill Bill. Aviate metering wraps these APIs with additional queuing, aggregation, and validation so that raw (non-aggregated) usage events can be submitted directly. Usage events submitted to Aviate are ultimately recorded in Kill Bill’s usage store for invoicing.
Prerequisites
Before using the metering APIs, ensure the following:
-
The Aviate plugin is installed (see the How to Install the Aviate Plugin guide).
-
Kill Bill is started with the metering feature flag enabled:
com.killbill.billing.plugin.aviate.enableMeteringApis=trueRefer to the Kill Bill Configuration Guide for setting configuration properties.
-
You have a valid ID token for authentication (see Authentication).
-
For invoicing: a catalog with a usage-based plan exists (see Catalog Guide — Creating Usage Plans).
Key Concepts
Billing Meters
A BillingMeter defines what you are measuring — API calls, tokens, minutes, etc. Each meter has:
-
name— human-readable label (e.g. "API Calls") -
code— unique identifier referenced when recording events -
eventKey— the event type key -
aggregationType— how events are rolled up (e.g.SUM) -
eventFilters— optional string array (reserved for future use)
Usage Events
A UsageEvent represents a single usage data point. Each event contains:
-
billingMeterCode— the code of the associated billing meter -
subscriptionId— the Kill Bill subscription ID -
trackingId— used for idempotency; resubmitting events with the same tracking ID is safe -
timestamp— ISO 8601 timestamp of the event -
value— numeric quantity (e.g. 150 API calls, 10.5 minutes)
|
Warning
|
Events within the same submission must have ascending timestamp values. Out-of-order events are rejected. All usage points for a specific subscription must be submitted sequentially (not concurrently).
|
Aggregation
The aggregationType on a billing meter defines how events are rolled up for billing within each billing period:
-
SUM — totals all event values in the billing period (e.g. 150 + 200 = 350 API calls)
Relationship to Kill Bill Usage
Aviate metering replaces the Kill Bill usage APIs for recording data. You should use either the Kill Bill usage APIs (for pre-aggregated data) or the Aviate metering APIs (for raw events) — not both. Usage events submitted through Aviate are aggregated and then recorded in Kill Bill’s usage store, where they drive invoice generation.
For complete API details, see the Aviate Metering API reference.
Step-by-Step: Create a Meter and Record Usage
Step 1: Create a Billing Meter
Use POST /v1/metering/billingMeters to create one or more billing meters. The request body is an array, so you can create multiple meters in one call.
curl -v -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
-d '[
{
"name": "API Calls",
"code": "api_calls",
"eventKey": "api_call",
"aggregationType": "SUM"
}
]' \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/metering/billingMeters
A successful response returns HTTP 200.
Step 2: Verify the Meter Exists
Retrieve a single meter by its code with GET /v1/metering/{meterCode}/billingMeter:
curl -H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/metering/api_calls/billingMeter
Expected response (JSON):
{
"name": "API Calls",
"code": "api_calls",
"eventKey": "api_call",
"aggregationType": "SUM"
}
Step 3: List All Billing Meters
Use GET /v1/metering/billingMeters/all to list every meter configured for the tenant:
curl -H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/metering/billingMeters/all
The response is a JSON array of all billing meters.
Step 4: Record Usage Events
Submit usage events with POST /v1/metering/billing/{accountId}. The request body is an array of events:
curl -v -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
-d '[
{
"billingMeterCode": "api_calls",
"subscriptionId": "f3b2a1d4-c5e6-7890-abcd-123456789abc",
"trackingId": "batch-2026-02-14-001",
"timestamp": "2026-02-14T10:00:00Z",
"value": 150
},
{
"billingMeterCode": "api_calls",
"subscriptionId": "f3b2a1d4-c5e6-7890-abcd-123456789abc",
"trackingId": "batch-2026-02-14-002",
"timestamp": "2026-02-14T11:00:00Z",
"value": 200
}
]' \
http://127.0.0.1:8080/plugins/aviate-plugin/v1/metering/billing/e5d3d5b5-4415-4166-b57f-33ca00a59e88
|
Important
|
Events within the same submission must have ascending timestamp values. The trackingId provides idempotency — resubmitting events with the same tracking ID is safe.
|
Step 5: Connect to Invoicing
Usage events are aggregated per billing period based on the meter’s aggregationType. When the subscription’s billing cycle runs, the aggregated value appears as a USAGE invoice item.
To make this work end-to-end:
-
Create a billing meter (Step 1 above).
-
Create a catalog with a usage-based plan that references the meter’s code (see Catalog Guide — Creating Usage Plans).
-
Create a subscription for the account using that plan.
-
Record usage events against the subscription.
-
When the billing period closes, Kill Bill generates an invoice with a USAGE line item reflecting the aggregated total.
Delete a Billing Meter
Use DELETE /v1/metering/{meterCode}/billingMeter to remove a meter. If usage events already exist for the meter, you must pass force=true:
curl -v -X DELETE \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: my-tenant" \
-H "X-Killbill-ApiSecret: my-secret" \
"http://127.0.0.1:8080/plugins/aviate-plugin/v1/metering/api_calls/billingMeter?force=true&accountId=e5d3d5b5-4415-4166-b57f-33ca00a59e88"
|
Important
|
Without force=true, attempting to delete a meter that has associated usage events will return an error.
|
What to Verify
After completing the steps above, confirm that:
-
The meter appears in the response from
GET /v1/metering/billingMeters/all. -
Usage events are accepted (HTTP 200 on the POST).
-
After the billing cycle runs, the invoice shows a USAGE line item with the aggregated amount.
-
The Kill Bill usage API (
/1.0/kb/usages/) reflects the recorded events.
Common Pitfalls
-
Submitting events out of chronological order — events are rejected if timestamps are not ascending.
-
Using a
billingMeterCodethat does not exist — the API returns an error. -
Missing
subscriptionIdin usage events — events cannot be linked to billing. -
Forgetting to create a usage-based plan in the catalog — events are recorded but no invoice is generated.
-
Deleting a meter without
force=truewhen events exist — the API returns an error.
Related
-
Authentication — obtaining an ID token
-
Catalog Guide — creating usage-based plans
-
AI Usage Tutorial — full end-to-end workflow with wallet and metering
-
Wallet — prepaid credits consumed by usage