> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bouclay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Usage billing

> Charge for what customers use: API calls, messages, tokens, storage

> [!NOTE]
>
> Early access. Write to [hello@bouclay.com](mailto:hello@bouclay.com) to have metered billing turned on for your account.

Usage billing charges for what a customer actually used in a period. Your app sends a **usage event** each time something billable happens. Bouclay adds the events up with a **meter**, prices the total, and bills it when the period ends.

**1. Create a meter**

A meter names an event and how to add it up.

**2. Put a usage price on it**

A price decides what each unit costs. One meter can back many prices.

**3. Subscribe the customer**

The subscription bills the usage at the end of each period.

**4. Send events as they happen**

Bouclay counts them and puts the total on the invoice.

## 1. Create a meter

```bash theme={null}
curl https://bouclay.com/api/v1/meters \
  -H "Authorization: Bearer $BOUCLAY_KEY" \
  -H "Idempotency-Key: meter-sms-v1" \
  -H "Content-Type: application/json" \
  -d '{"name": "SMS sent", "eventName": "sms.sent", "aggregation": "count", "unitLabel": "SMS"}'
```

`aggregation` decides how a period's events become one number:

| Aggregation | Bills | Example |
| - | - | - |
| `count` | The number of events. | SMS sent |
| `sum` | The total of each event's value. | Tokens used, GB transferred |
| `max` | The largest value in the period. | Peak number of servers |
| `last` | The value of the latest event. | Storage at the end of the month |
| `unique_count` | The number of different values of one property (`uniqueKey`). | Monthly active users |

For `sum`, `max` and `last`, the number comes from the event's `value`, or from a property you name with `valueKey`.

`eventName`, `aggregation`, `valueKey` and `uniqueKey` can't change once the meter has events, because that would change what past usage cost. To count differently, create a new meter.

## 2. Put a usage price on it

A usage price is a recurring price with `usageType: metered` and the meter's id:

```bash theme={null}
curl https://bouclay.com/api/v1/products/prod_…/prices \
  -H "Authorization: Bearer $BOUCLAY_KEY" \
  -H "Idempotency-Key: price-sms-v1" \
  -H "Content-Type: application/json" \
  -d '{
    "planId": "plan_…",
    "type": "recurring",
    "usageType": "metered",
    "meterId": "mtr_…",
    "pricingModel": "standard",
    "unitAmount": 3.5,
    "currency": "NGN",
    "billingInterval": "month"
  }'
```

Usage is always billed at the end of the period. Use `graduated` tiers for included units and volume discounts, or `package` for blocks. See [Pricing models](https://docs.bouclay.com/billing/catalog.md#pricing-models).

### Pricing per a number of units

When a unit costs less than a kobo, quote the rate per a number of units with `unitDivisor`. ₦4,500 per 1,000,000 tokens is `"unitAmount": 4500, "unitDivisor": 1000000`. Bouclay bills `usage × unitAmount ÷ unitDivisor`, adds up every tier first, and rounds half up to the kobo once: 2,345,678 tokens bill ₦10,555.55. The invoice line says the rate: "Input tokens · 2,345,678 tokens · NGN 4,500.00 per 1M tokens".

### Fees billed at the end

A fixed fee can also be billed at the end of the period with `billingTiming: arrears`, prorated to the time the subscription was live. This is how "pay as you go" plans with no upfront charge are made.

## 3. Subscribe the customer

Subscribe them as usual. A plan with nothing billed up front has nothing to charge today, so it starts `active`. To make sure there is a card for the first invoice, set `requirePaymentMethod: true` (or turn it on for every subscription in **Billing settings → Signups**): the customer saves a card through a small refunded charge, and the subscription starts once it settles.

To bill several kinds of usage on one plan, such as a platform fee plus SMS plus lookups, see [Sell several kinds of usage in one plan](https://docs.bouclay.com/usage-plans.md).

## 4. Send usage events

```bash theme={null}
curl https://bouclay.com/api/v1/meter-events \
  -H "Authorization: Bearer $BOUCLAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "eventName": "sms.sent",
    "customer": "ctm_…",
    "identifier": "sms_8f2c1a",
    "timestamp": "2026-10-31T09:15:00Z"
  }'
```

* **No `Idempotency-Key` needed.** `identifier` is your own unique id for the event. Sending the same one again returns the stored event (`200`) and counts it once. Send events again freely after a timeout.
* `customer` is the Bouclay id or the `externalRef` you gave the customer.
* `value` is for `sum`, `max` and `last` meters. Whole numbers only, so pick a unit that makes it one (tokens, not thousands of tokens; kobo, not naira).
* `timestamp` defaults to now and can't be more than 5 minutes ahead.

Send up to 500 at once with `POST /meter-events/batch`. Each event is judged on its own, so one bad event never fails the batch, and the response gives each one's outcome: `created`, `duplicate` or `rejected`.

### Refused events

A refused event answers `422` with a code:

| Code | Means |
| - | - |
| `meter_not_found`, `meter_archived` | No active meter has this event name. |
| `customer_not_found` | No such customer. |
| `timestamp_in_future` | More than 5 minutes ahead. |
| `missing_property` | A `unique_count` meter's property is missing. |
| `invalid_value` | Not a whole number from 0 to 1,000,000,000,000. |
| `usage_period_closed` | The period it falls in has already been invoiced. |
| `subscription_paused` | The subscription that bills this meter was paused at that time. |

### Correcting a mistake

`POST /meter-events/{identifier}/cancel` stops an event counting. It is kept, never deleted, and its identifier stays used. Events in a period that is already invoiced can't be cancelled; correct the invoice with a [credit note](https://docs.bouclay.com/billing/refunds-and-chargebacks.md#credit-notes) instead.

## Show customers their usage

`GET /customers/{id}/usage` returns each meter's usage this period, with `estimatedAmount`: what it would bill now, priced exactly as the invoice line will be. `GET /subscriptions/{id}/upcoming-invoice` shows the whole next invoice. Both are good for a usage page in your app.

## Billing large usage early

A customer can run up a large bill before the period ends. `invoicingThreshold` on the subscription bills usage early once the unbilled amount reaches it. The period's own invoice then bills only the rest. Fixed fees never count toward it.

## Minimums, caps and credit

* Hold a customer to a minimum spend, or cap what they can be billed: see [Minimums and spending caps](https://docs.bouclay.com/billing/minimums-and-caps.md).
* Let customers pay for usage up front and stop them when it runs out: see [Prepaid credit](https://docs.bouclay.com/credits/prepaid-credit.md) and [Credit holds](https://docs.bouclay.com/credits/holds.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.