Usage-based billing
Overview
Section titled “Overview”BoxBilling supports full usage-based billing. The pipeline works in three stages:
Events → Billable Metrics → Charges → Fees on Invoices- Events are ingested via the API with a metric code, customer ID, and properties
- Billable Metrics define how events are aggregated (count, sum, max, etc.)
- Charges attach metrics to plans with a pricing model (standard, graduated, volume, etc.)
- Fees are calculated at invoice time based on aggregated usage
Ingesting events
Section titled “Ingesting events”Single event
Section titled “Single event”curl -X POST /v1/events \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "transaction_id": "txn_unique_123", "external_customer_id": "cust_001", "code": "api_calls", "timestamp": "2025-01-15T10:30:00Z", "properties": { "region": "us-east", "method": "POST", "bytes": 1024 } }'You can also pass an Idempotency-Key header for request-level deduplication in addition to transaction_id.
Batch ingestion
Section titled “Batch ingestion”curl -X POST /v1/events/batch \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "events": [ { "transaction_id": "txn_1", "external_customer_id": "cust_001", "code": "api_calls", "timestamp": "2025-01-15T10:30:00Z", "properties": {"region": "us-east"} }, { "transaction_id": "txn_2", "external_customer_id": "cust_001", "code": "api_calls", "timestamp": "2025-01-15T10:31:00Z", "properties": {"region": "eu-west"} } ] }'- Up to 100 events per batch
- Events are idempotent — duplicate
transaction_idvalues return the existing event - Rate limited per organization (default: 1000/minute, configurable)
- The response includes
ingestedandduplicatescounts so you can verify delivery
Estimate fees
Section titled “Estimate fees”Preview the fees that would result from a hypothetical event without actually ingesting it:
curl -X POST /v1/events/estimate_fees \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "subscription_id": "sub-uuid", "code": "api_calls", "properties": {"region": "us-east"} }'Returns charge_model, metric_code, units, amount_cents, and unit_amount_cents.
Reprocess an event
Section titled “Reprocess an event”Re-triggers usage threshold and alert checks for all active subscriptions associated with an event:
curl -X POST /v1/events/{event_id}/reprocess \ -H "Authorization: Bearer $API_KEY"Event volume
Section titled “Event volume”Get hourly event counts for a time range:
curl "/v1/events/volume?from_timestamp=2025-01-01T00:00:00Z&to_timestamp=2025-01-02T00:00:00Z" \ -H "Authorization: Bearer $API_KEY"Returns an array of {timestamp, count} data points.
ClickHouse acceleration
Section titled “ClickHouse acceleration”For high-volume event ingestion, enable ClickHouse by setting the CLICKHOUSE_URL environment variable. Events are dual-written to both the primary database and ClickHouse, with aggregation queries routed to ClickHouse for performance.
Events API endpoints
Section titled “Events API endpoints”| Method | Path | Description |
|---|---|---|
POST | /v1/events/ | Ingest a single event |
POST | /v1/events/batch | Ingest up to 100 events |
GET | /v1/events/ | List events (filterable by external_customer_id, code, from_timestamp, to_timestamp) |
GET | /v1/events/{event_id} | Get event by ID |
POST | /v1/events/{event_id}/reprocess | Reprocess an event |
POST | /v1/events/estimate_fees | Estimate fees for a hypothetical event |
GET | /v1/events/volume | Get hourly event volume |
Billable metrics
Section titled “Billable metrics”Billable metrics define how raw events are aggregated into usage values.
Create a metric
Section titled “Create a metric”curl -X POST /v1/billable_metrics \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "api_calls", "name": "API Calls", "aggregation_type": "count" }'Aggregation types
Section titled “Aggregation types”| Type | Description | Requires field_name |
|---|---|---|
count | Number of events | No |
sum | Sum of a numeric property | Yes |
max | Maximum value of a property | Yes |
unique_count | Count of distinct property values | Yes |
weighted_sum | Time-weighted sum (proportional to duration) | Yes |
latest | Most recent event’s value | Yes |
custom | Custom expression evaluation | Requires expression |
Example: sum aggregation
Section titled “Example: sum aggregation”curl -X POST /v1/billable_metrics \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "data_transfer", "name": "Data Transfer (GB)", "aggregation_type": "sum", "field_name": "bytes", "rounding_function": "ceil", "rounding_precision": 0 }'Recurring metrics
Section titled “Recurring metrics”Set recurring: true to persist aggregated values across billing periods instead of resetting to zero. Useful for metrics like “total storage used” where the value carries forward.
Rounding
Section titled “Rounding”| Function | Behavior |
|---|---|
round | Half-up rounding |
ceil | Round up |
floor | Round down |
Precision: 0–15 decimal places.
Filters
Section titled “Filters”Filters segment events by property values, enabling different pricing per segment:
curl -X POST /v1/billable_metrics/api_calls/filters \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "region", "values": ["us-east", "us-west", "eu-west"] }'List existing filters with GET /v1/billable_metrics/{code}/filters and remove with DELETE /v1/billable_metrics/{code}/filters/{filter_id}.
Billable metrics API endpoints
Section titled “Billable metrics API endpoints”| Method | Path | Description |
|---|---|---|
POST | /v1/billable_metrics/ | Create a metric |
GET | /v1/billable_metrics/ | List metrics |
GET | /v1/billable_metrics/{metric_id} | Get metric by ID |
PUT | /v1/billable_metrics/{metric_id} | Update a metric |
DELETE | /v1/billable_metrics/{metric_id} | Delete a metric |
GET | /v1/billable_metrics/stats | Get metrics statistics (total + breakdown by aggregation type) |
GET | /v1/billable_metrics/plan_counts | Get plan counts per metric |
GET | /v1/billable_metrics/{metric_id}/plans | List plans using a metric |
POST | /v1/billable_metrics/{code}/filters | Create a metric filter |
GET | /v1/billable_metrics/{code}/filters | List metric filters |
DELETE | /v1/billable_metrics/{code}/filters/{filter_id} | Delete a metric filter |
Charge models
Section titled “Charge models”Charges connect billable metrics to plans with a pricing model. When creating a plan, include charges in the request:
curl -X POST /v1/plans \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "pro", "name": "Pro Plan", "interval": "monthly", "amount_cents": 9900, "charges": [ { "billable_metric_id": "metric-uuid", "charge_model": "standard", "properties": { "unit_price": "0.01" } } ] }'Available models
Section titled “Available models”| Model | Description |
|---|---|
standard | Fixed per-unit price |
graduated | Tiered pricing — different rates per unit range |
volume | Total units determine per-unit price for all units |
package | Fixed price per block of units |
percentage | Percentage of a total amount plus optional fixed fee |
graduated_percentage | Tiered percentage rates based on amount ranges |
custom | Custom expression evaluation |
dynamic | Per-event property-based pricing |
Standard
Section titled “Standard”Simple per-unit pricing.
{ "charge_model": "standard", "properties": { "unit_price": "0.01" }}Formula: amount = units × unit_price
Graduated
Section titled “Graduated”Tiered pricing where different unit ranges have different prices.
{ "charge_model": "graduated", "properties": { "tiers": [ {"from": 0, "to": 100, "unit_price": "0.10", "flat_fee": "0"}, {"from": 101, "to": 1000, "unit_price": "0.05", "flat_fee": "0"}, {"from": 1001, "to": null, "unit_price": "0.01", "flat_fee": "0"} ] }}Volume
Section titled “Volume”The total units determine the per-unit price for all units.
{ "charge_model": "volume", "properties": { "tiers": [ {"from": 0, "to": 100, "unit_price": "0.10", "flat_fee": "0"}, {"from": 101, "to": null, "unit_price": "0.05", "flat_fee": "0"} ] }}Package
Section titled “Package”Fixed price per block of units.
{ "charge_model": "package", "properties": { "package_size": 10, "package_price": "50.00" }}Percentage
Section titled “Percentage”Percentage of a total amount.
{ "charge_model": "percentage", "properties": { "rate": "2.5", "fixed_amount": "0.30" }}Graduated Percentage
Section titled “Graduated Percentage”Tiered percentage rates based on amount ranges.
Custom
Section titled “Custom”Uses a custom expression for aggregation:
{ "charge_model": "custom", "properties": { "expression": "cpu_seconds + memory_gb * 2" }}Dynamic
Section titled “Dynamic”Per-event property-based pricing — each event is priced individually based on its properties.
Charge filters
Section titled “Charge filters”Apply different pricing based on event properties:
{ "charges": [ { "billable_metric_id": "metric-uuid", "charge_model": "standard", "properties": {"unit_price": "0.01"}, "filters": [ { "billable_metric_filter_id": "filter-uuid", "values": ["us-east"], "properties": {"unit_price": "0.02"}, "invoice_display_name": "US East API Calls" } ] } ]}Events matching the filter values use the filter’s properties (here, $0.02/unit for us-east). All other events use the base charge properties ($0.01/unit). Use invoice_display_name to customize how the filter appears on invoices.
Usage thresholds
Section titled “Usage thresholds”Trigger actions when cumulative usage crosses a monetary threshold within a billing period.
Create a threshold
Section titled “Create a threshold”# On a plan (applies to all subscriptions)curl -X POST /v1/plans/{plan_code}/usage_thresholds \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 10000, "recurring": true, "threshold_display_name": "Usage cap ($100)" }'
# On a specific subscriptioncurl -X POST /v1/subscriptions/{id}/usage_thresholds \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 5000, "recurring": false }'When a threshold is crossed:
- A
usage_threshold.crossedwebhook is sent - Progressive billing invoices can be generated for early collection
Check current usage
Section titled “Check current usage”curl /v1/subscriptions/{id}/current_usage \ -H "Authorization: Bearer $API_KEY"Returns current_usage_amount_cents, billing_period_start, and billing_period_end.
Usage thresholds API endpoints
Section titled “Usage thresholds API endpoints”| Method | Path | Description |
|---|---|---|
POST | /v1/plans/{plan_code}/usage_thresholds | Create plan-level threshold |
GET | /v1/plans/{plan_code}/usage_thresholds | List plan-level thresholds |
POST | /v1/subscriptions/{id}/usage_thresholds | Create subscription-level threshold |
GET | /v1/subscriptions/{id}/usage_thresholds | List subscription-level thresholds |
DELETE | /v1/usage_thresholds/{threshold_id} | Delete a threshold |
Usage alerts
Section titled “Usage alerts”Usage alerts monitor metric-level usage on a subscription and fire when a threshold value is crossed.
Create an alert
Section titled “Create an alert”curl -X POST /v1/usage_alerts \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "subscription_id": "sub-uuid", "billable_metric_id": "metric-uuid", "threshold_value": "1000", "recurring": true, "name": "API calls limit" }'recurring: true— the alert resets and can fire again each billing periodrecurring: false— the alert fires once and stays triggered
Check alert status
Section titled “Check alert status”curl /v1/usage_alerts/{alert_id}/status \ -H "Authorization: Bearer $API_KEY"Returns current_usage, threshold_value, usage_percentage, and the current billing_period_start/billing_period_end.
Test an alert
Section titled “Test an alert”Manually check whether an alert would trigger based on current usage:
curl -X POST /v1/usage_alerts/{alert_id}/test \ -H "Authorization: Bearer $API_KEY"Trigger history
Section titled “Trigger history”curl /v1/usage_alerts/{alert_id}/triggers \ -H "Authorization: Bearer $API_KEY"Returns past trigger records including current_usage, threshold_value, metric_code, and triggered_at.
Usage alerts API endpoints
Section titled “Usage alerts API endpoints”| Method | Path | Description |
|---|---|---|
POST | /v1/usage_alerts/ | Create an alert |
GET | /v1/usage_alerts/ | List alerts |
GET | /v1/usage_alerts/{alert_id} | Get alert by ID |
PATCH | /v1/usage_alerts/{alert_id} | Update alert (threshold_value, name, recurring) |
DELETE | /v1/usage_alerts/{alert_id} | Delete alert |
GET | /v1/usage_alerts/{alert_id}/status | Get current usage vs. threshold |
POST | /v1/usage_alerts/{alert_id}/test | Test alert against current usage |
GET | /v1/usage_alerts/{alert_id}/triggers | List trigger history |
Usage trends
Section titled “Usage trends”Track daily usage over time for a subscription:
curl "/v1/subscriptions/{id}/usage_trend?start_date=2025-01-01&end_date=2025-01-31" \ -H "Authorization: Bearer $API_KEY"Returns an array of data points with date, value, and events_count for each day.
Daily usage aggregation
Section titled “Daily usage aggregation”A background task runs daily at 00:30 UTC to pre-aggregate usage data into the daily_usages table. This speeds up period-based usage queries for invoice generation and threshold checking.