# How to Implement Metered Billing with Stripe: A Step-by-Step Guide

> A practical how-to guide for implementing metered billing with Stripe — event ingestion, aggregation, pricing config, and invoice delivery for SaaS teams.

- **Published:** 2026-02-01
- **Author:** Clixo
- **Reading time:** 5 min read
- **Tags:** metered-billing, stripe, saas-billing, usage-based-pricing
- **Canonical URL:** https://clixo.sh/blog/how-to-implement-metered-billing-stripe

You built a product that charges based on usage — API calls, seats, tokens, records processed — and now you need the billing system to keep up. Stripe's metered billing tools are capable, but the documentation makes it look simpler than it is in production. Here is a real-world walkthrough.

## How Metered Billing Works in Stripe

Stripe separates the concern of counting usage from the concern of charging for it. You report usage events throughout the billing period; Stripe aggregates them and includes the total on the invoice at period end.

The core objects involved are:

- **Product** — what you are selling (e.g., "API Compute Units")
- **Price** — the pricing config attached to the product, set to `usage_type: metered`
- **Subscription** — the customer's active subscription referencing the metered price
- **Usage Record** — the events you push during the billing period

```mermaid
sequenceDiagram
  participant App as "Your App"
  participant Redis as "Redis buffer"
  participant Stripe as Stripe
  participant Customer as Customer
  App->>Redis: Increment usage counter on each action
  Redis-->>App: Acknowledged
  App->>Stripe: Flush aggregated usage records on interval
  Stripe-->>App: Usage recorded
  Stripe->>Stripe: Aggregate totals at period end
  Stripe->>Customer: Finalize and send invoice
  Customer-->>Stripe: Payment collected
```

Setting the price's `aggregate_usage` field controls how Stripe calculates the billable total: `sum` adds every event value, `max` takes the peak, and `last_during_period` takes the final reported value.

## Step 1: Create a Metered Price in Stripe

When creating the price via API or Dashboard, set:

```
usage_type: metered
billing_scheme: per_unit   # or tiered
aggregate_usage: sum
```

For tiered pricing — where the per-unit rate drops at higher volumes — use `billing_scheme: tiered` and define your tiers. Tiered metered pricing requires you to also set `tiers_mode` to either `graduated` (each tier rate applies only to units in that tier) or `volume` (the rate of the tier reached applies to all units).

## Step 2: Subscribe the Customer

Create a subscription with the metered price as a line item. The subscription's `items[0].id` is the `subscription_item_id` you will reference every time you report usage.

Store this ID in your database against the customer record. You will need it on every usage report call.

## Step 3: Report Usage Events

Post usage to Stripe via the Usage Records API:

```
POST /v1/subscription_items/{subscription_item_id}/usage_records
{
  "quantity": 42,
  "timestamp": 1700000000,
  "action": "increment"
}
```

`action: increment` adds to the running total. `action: set` replaces the total — useful for gauge-style metrics like active seats.

### High-Volume Aggregation

At scale, sending one API call per user action is a fast path to Stripe rate limits and unnecessary latency. Accumulate usage in your application layer — Redis is a practical choice — and flush aggregated totals on a short interval (every minute or every hour depending on your volume). A single batch flush per interval keeps you well inside rate limits and reduces per-event overhead.

## Step 4: Give Customers Real-Time Visibility

Customers on metered plans get anxious when they cannot see their running total. Fetch the current period's usage from Stripe and surface it in your product dashboard:

```
GET /v1/subscription_items/{subscription_item_id}/usage_record_summaries
```

This endpoint returns period-to-date totals. Show this data alongside the projected cost so customers can make informed decisions before the invoice arrives.

## Step 5: Handle Invoicing and Webhooks

Stripe finalizes the invoice at the end of the billing period. Subscribe to `invoice.created` and `invoice.finalized` webhooks to trigger any pre-charge logic — for example, flagging unusually large invoices for a human review step before Stripe attempts to collect.

Also listen to `invoice.payment_failed` so your dunning flow can kick in immediately. Failed payments on metered invoices require the same retry and notification logic as any subscription payment failure.

## Common Implementation Pitfalls

- **Timestamp drift**: Usage records with future timestamps are rejected. Always use server-side UTC timestamps, never client-supplied values.
- **Missing idempotency keys**: If your flush job retries on failure, duplicate events will inflate the customer's bill. Set an idempotency key derived from your internal event batch ID.
- **Delayed reporting**: Stripe's billing period closes at the subscription's anchor date. Events reported after the period closes are applied to the next invoice. Build monitoring that alerts if usage reports fall behind.
- **No usage floor**: Some metered plans carry a minimum monthly commitment. Model this as a flat-fee line item on the same subscription, not as a price floor on the metered price — it gives you cleaner reporting and a clearer customer invoice.

## Reconciliation

Automated reconciliation is not optional at any meaningful scale. Compare your internal usage logs against the usage record summaries Stripe returns. Run this daily. Revenue mismatches compound quickly and are expensive to dispute retroactively.

If you are building metered billing infrastructure from scratch and want to get it right the first time, [start a build conversation with Clixo](https://clixo.sh/#contact). We design and ship billing systems that handle the edge cases before they become customer complaints.

---

Clixo · 1141 W Bryn Mawr Ave, Itasca, IL 60143, US · [hello@clixo.sh](mailto:hello@clixo.sh)
[Start a build](https://clixo.sh/#contact) · [All services](https://clixo.sh/services) · [Agent guide (llms.txt)](https://clixo.sh/llms.txt)
