# Stripe Usage-Based / Metered Billing — Official API Reference > Local reference distilled from official Stripe documentation for the Pro hybrid > (committed base + metered overage) billing slice. > > **Cited:** 2026-07-07 (Asia/Seoul). API surface: Billing Meters (v1) + Meter Events (v1/v2). > **Note:** Stripe now surfaces Metronome as its recommended platform for *new* high-volume > integrations, but the first-party **Billing Meters API documented here is fully supported** > and is the correct primitive for a self-serve metered-overage subscription. Sources below. ## Sources (official URLs) | # | Topic | URL | |---|-------|-----| | S1 | Usage-based billing overview | https://docs.stripe.com/billing/subscriptions/usage-based | | S2 | Create a Billing Meter (`POST /v1/billing/meters`) | https://docs.stripe.com/api/billing/meter/create | | S3 | Create a Meter Event (`POST /v1/billing/meter_events`) | https://docs.stripe.com/api/billing/meter-event/create | | S4 | Meter Event object v2 (dedup window) (`POST /v2/billing/meter_events`) | https://docs.stripe.com/api/v2/billing/meter-events/object | | S5 | Create a Price (metered / tiered) (`POST /v1/prices`) | https://docs.stripe.com/api/prices/create | | S6 | Create a Subscription (multi-item) (`POST /v1/subscriptions`) | https://docs.stripe.com/api/subscriptions/create | | S7 | Recording usage | https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage | | S8 | Advanced usage-based (flat fee + overage) | https://docs.stripe.com/billing/subscriptions/usage-based/advanced/compare | --- ## Data model (end to end) ``` Billing Meter ──defines──▶ event_name + aggregation (sum/count/last) ▲ │ │ recurring.meter │ meter events (usage) reference event_name │ ▼ Metered Price ──item──▶ Subscription ◀──item── Licensed base Price (committed fee) │ │ tiered/per_unit ▼ End of billing period: aggregated usage → invoice line item ``` The **hybrid** = one Subscription carrying **two items**: 1. a **licensed** base price (fixed committed fee, `usage_type` unset/licensed, has `quantity`), and 2. a **metered** price linked to a Meter (`usage_type=metered`, **no `quantity`**), whose graduated tiers make the *included allotment* cost 0 and only bill the **overage** per unit. --- ## 1. Create a Billing Meter — `POST /v1/billing/meters` (S2) A Meter specifies how to aggregate meter events over a billing period. Key parameters: - `display_name` (string, required) — internal name, not shown to customers. - `event_name` (string, required, max 100 chars) — links meter to its events. - `default_aggregation.formula` (enum, required) — `sum` | `count` | `last`. - `value_settings.event_payload_key` (string) — payload key holding the numeric value (default `value`). - `customer_mapping.type` (enum) — `by_id`. - `customer_mapping.event_payload_key` (string) — payload key holding the customer id (default `stripe_customer_id`). - `event_time_window` (nullable enum, optional) — `hour` | `day` for pre-aggregated events. Python signature: ```python stripe.billing.Meter.create( display_name="Pro API Calls", event_name="pro_api_call", default_aggregation={"formula": "sum"}, value_settings={"event_payload_key": "value"}, customer_mapping={"type": "by_id", "event_payload_key": "stripe_customer_id"}, ) # -> billing.meter { id: "mtr_...", status: "active", ... } ``` ## 2. Record a Meter Event — `POST /v1/billing/meter_events` (S3, S4) Reports one usage event. Aggregated into invoice line items at end of period. Key parameters: - `event_name` (string, required) — must match a Meter's `event_name`. - `payload` (object, required) — must contain the meter's `customer_mapping.event_payload_key` (default `stripe_customer_id`) and `value_settings.event_payload_key` (default `value`). - `identifier` (string, optional) — **idempotency / dedup key**. Uniqueness is enforced within a **rolling 24-hour window**; a repeated `identifier` is not counted twice. If omitted, Stripe generates one. Recommend a globally unique id (UUID / deterministic business key). (S4) - `timestamp` (unix seconds, optional) — must be **within the past 35 calendar days or up to 5 minutes in the future**; defaults to now. (S4) Python signature: ```python stripe.billing.MeterEvent.create( event_name="pro_api_call", payload={"stripe_customer_id": "cus_123", "value": "25"}, identifier="pro_api_call:cus_123:2026-07-07T09:00Z:req_abc", # dedup within 24h timestamp=1751878800, # optional ) ``` > v2 equivalent `POST /v2/billing/meter_events` returns `v2.billing.meter_event` and does > synchronous validation; same `identifier` 24h-uniqueness rule. (S4) ## 3a. Create a metered Price — `POST /v1/prices` (S5) Link a price to the meter and choose per-unit or tiered. Key parameters: - `currency` (required) — e.g. `usd`. - `product` or `product_data` (one required). - `recurring.interval` (required) — `day` | `week` | `month` | `year`. - `recurring.usage_type` = `metered` (required for usage billing). - `recurring.meter` = `` (required for metered) — ties price to the Meter from step 1. - `billing_scheme` — `per_unit` (with `unit_amount`) or `tiered`. - For tiered overage: `tiers_mode` = `graduated` | `volume`, and `tiers[]` = `{up_to, unit_amount}`. Graduated overage example (first N units free/included, rest billed): ```python stripe.Price.create( currency="usd", product="prod_pro", recurring={"interval": "month", "usage_type": "metered", "meter": "mtr_..."}, billing_scheme="tiered", tiers_mode="graduated", tiers=[ {"up_to": 10000, "unit_amount": 0}, # included allotment (covered by base fee) {"up_to": "inf", "unit_amount": 2}, # $0.02/unit overage above the allotment ], ) ``` ## 3b. Create the base (committed) Price — `POST /v1/prices` (S5) Fixed committed fee = a licensed recurring price (no `usage_type=metered`): ```python stripe.Price.create( currency="usd", product="prod_pro", unit_amount=2000, # $20.00 committed base recurring={"interval": "month"}, # licensed (default usage_type) ) ``` ## 4. Create the hybrid Subscription — `POST /v1/subscriptions` (S6) One subscription, two items. **Metered items must NOT include `quantity`.** ```python stripe.Subscription.create( customer="cus_123", items=[ {"price": "price_base", "quantity": 1}, # licensed committed fee {"price": "price_metered"}, # metered overage — no quantity ], idempotency_key="sub-create:cus_123:pro-v1", # safe retry (request header) ) ``` - Metered usage from the previous period is charged **alongside** the fixed base for the new period on a **single invoice** at each renewal. (S6, quantities doc) - Use the `Idempotency-Key` request header to safely retry create requests (returns the same object). --- ## Overage calculation (concept) Overage is computed by Stripe, not the app: it aggregates meter events per customer per period via `default_aggregation.formula`, then applies the metered price's tiers. With `graduated` tiers where tier-1 (`up_to = included_allotment`) has `unit_amount = 0`, the customer pays only for units above the allotment: ``` billed_overage = max(0, aggregated_usage - included_allotment) * overage_unit_amount invoice_total = committed_base_fee + billed_overage # single invoice at renewal ``` App-side we only *emit events* and (optionally) *mirror a usage estimate* for UX; the ledger of record is Stripe's aggregation. ## Idempotency & correctness rules (official) - **Meter events:** set a deterministic `identifier`; dedup is enforced for a rolling 24h window (S4). Choose one identifier per real-world usage unit so retries/at-least-once delivery never double-count. - **Timestamp:** only accepted within past 35 days / +5 min; late or clock-skewed events are rejected (S4). - **Write APIs (Meter/Price/Subscription create):** pass the `Idempotency-Key` header to make retries safe (S6).