# Usage-based billing (https://docs.billwave.example/subscriptions/billing)

How to implement usage-based billing [#how-to-implement-usage-based-billing]

This guide shows how to meter usage against a quota, enforce limits, and handle overages.

Define a metered feature [#define-a-metered-feature]

In the dashboard, create a feature with type **Metered**. Then attach it to a plan with a limit and reset interval.

Or define it in code:

```ts
import { metered, plan } from "@digvijay-x1/billwave";

const apiCalls = metered("api-calls", { name: "API Calls" });

plan("pro", {
  name: "Pro",
  price: 2000,
  currency: "USD",
  interval: "monthly",
  features: [
    apiCalls.limit(10000, { reset: "monthly" }),
  ],
});
```

The counter resets to zero at the start of each billing period.

Gate requests with check() [#gate-requests-with-check]

Before performing an expensive operation, verify the customer has remaining quota:

```ts
const access = await billwave.check({
  customer: "user_123",
  feature: "api-calls",
});

if (!access.allowed) {
  console.log("Quota exceeded", access.balance, access.resetsAt);
}

// Proceed with the operation...
```

Record usage with track() [#record-usage-with-track]

After a successful operation, record the usage:

```ts
const result = await billwave.track({
  customer: "user_123",
  feature: "api-calls",
  value: 1,
});

// result.allowed — whether the usage was accepted
// result.balance — remaining quota after this usage
```

Check-then-track pattern [#check-then-track-pattern]

The most common pattern combines both calls:

```ts
async function handleApiRequest(userId: string) {
  // 1. Check quota
  const access = await billwave.check({
    customer: userId,
    feature: "api-calls",
  });

  if (!access.allowed) {
    throw new Error(`Quota exceeded. Resets at ${access.resetsAt}`);
  }

  // 2. Do the work
  const result = await doExpensiveWork();

  // 3. Track usage (only after success)
  await billwave.track({
    customer: userId,
    feature: "api-calls",
    value: 1,
  });

  return result;
}
```

Track variable amounts [#track-variable-amounts]

Not all operations cost one unit. Pass a custom `value`:

```ts
// AI token usage — variable cost per request
await billwave.track({
  customer: "user_123",
  feature: "ai-tokens",
  value: response.usage.total_tokens,
});

// Storage — track in MB
await billwave.track({
  customer: "user_123",
  feature: "storage-mb",
  value: fileSizeInMb,
});
```

Enable overages [#enable-overages]

To charge customers for usage beyond their limit instead of blocking them, set the overage policy on the feature:

```ts
apiCalls.limit(10000, {
  overage: "charge",
  overagePrice: 50, // price per unit in minor currency
  maxOverageUnits: 100000, // optional hard cap
});
```

With `overage: "charge"`, `track()` continues to accept usage beyond the limit and returns `code: "tracked_overage"`. The overage amount is billed at the end of the period.

Reset intervals [#reset-intervals]

How often the usage counter resets:

* `monthly` — resets on the subscription billing cycle anchor
* `weekly` — resets every week
* `daily` — resets every day
* `never` — usage accumulates indefinitely (good for lifetime limits)

Rollover [#rollover]

Allow unused usage to carry over to the next period:

```ts
apiCalls.limit(10000, {
  reset: "monthly",
  rollover: true,
  maxRollover: 20000, // cap at 2x monthly limit
});
```

Show usage in your UI [#show-usage-in-your-ui]

Use `check()` to display a usage bar or remaining count:

```ts
const usage = await billwave.check({
  customer: "user_123",
  feature: "api-calls",
});

// In your UI:
// Used: (usage.limit - usage.balance) / usage.limit * 100%
// Remaining: usage.balance
// Resets: usage.resetsAt
```