# Migrate to billing meters Learn how to migrate from usage records to billing meters. Stripe is deprecating usage-records billing. Moving forward, you can migrate to billing meters, our only solution for usage-based billing. Billing meters provide the following advantages: - High-throughput usage reporting - One-hour reporting [grace period](https://docs.stripe.com/billing/subscriptions/usage-based/configure-grace-period.md) for generating invoices - [Collect usage](https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage.md) before creating a subscription However, we don’t support the following feature: - `max` [aggregation formula](https://docs.stripe.com/api/billing/meter/object.md#billing_meter_object-default_aggregation) You can continue to use usage records as you adopt billing meters. ## Billing meter overview Billing meters allow you to track usage of a particular event. It supports high-throughput event ingestion and aggregation. Unlike usage records, billing meters don’t require customers to have subscriptions before reporting usage and a single meter can track usage across multiple customers. Learn more about billing meters in our [implementation guide](https://docs.stripe.com/billing/subscriptions/usage-based/implementation-guide.md). ## Create a meter Create a [billing meter](https://docs.stripe.com/api/billing/meter.md). Learn more about [configuring meters](https://docs.stripe.com/billing/subscriptions/usage-based/meters/configure.md). ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. meter = client.v1.billing.meters.create({ "display_name": "Hypernian", "event_name": "api_request", "default_aggregation": {"formula": "sum"}, }) ``` ## Create a new price Create a new price associated with the billing meter. Make sure that the new price is on the same product as your old price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. price = client.v1.prices.create({ "product": "{{PRODUCT_ID}}", "recurring": {"interval": "month", "usage_type": "metered", "meter": "{{METER_ID}}"}, "currency": "usd", "unit_amount": 100, }) ``` ## Start recording usage > You must continue to send [usage records](https://docs.stripe.com/billing/subscriptions/usage-based-legacy/recording-usage.md) to Stripe until the migration is completed. The legacy usage records APIs are removed in Stripe version [2025-03-31.basil](https://docs.stripe.com/changelog/basil/2025-03-31/deprecate-legacy-usage-based-billing.md). To continue to send usage records, you need to use an API version on or before [2025-02-24.acacia](https://docs.stripe.com/changelog/acacia.md#february-24-2025). Start reporting usage to the Billing Meter API. Stripe doesn’t reflect this usage on customer invoices until they’re subscribed to the new price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. meter_event = client.v1.billing.meter_events.create({ "event_name": "api_request", "timestamp": 1712096183, "identifier": "{{IDEMPOTENCY_KEY}}", "payload": {"stripe_customer_id": "{{CUSTOMER_ID}}", "value": "1"}, }) ``` Learn more about [recording usage](https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage.md). ## Optional: Query reported usage To retrieve usage for a custom time period, use the [Meter Event Summary](https://docs.stripe.com/api/billing/meter-event-summary.md). ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. meter_event_summaries = client.v1.billing.meters.event_summaries.list( "{{METER_ID}}", { "customer": "{{CUSTOMER_ID}}", "start_time": 1717249380, "end_time": 1717249440, }, ) ``` ## Plan subscription schedules Use subscription schedules to automatically migrate to the new price at the end of the billing period. Learn more about [subscription schedules](https://docs.stripe.com/billing/subscriptions/subscription-schedules.md). List the subscriptions associated with the old price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscriptions = client.v1.subscriptions.list({ "price": "{{OLD_PRICE_ID}}", "expand": ["data.schedule"], }) ``` Stripe returns a list of subscriptions associated with the old price. For example: ```json { "object": "list", "data": [ { "id": ""sub_1P1Y6gDxxK6kAaV0rS7ojBjh"", "object": "subscription", ... "items": { "object": "list", "data": [ { "id": ""si_PrGdqMmuM1DGbQ"", "object": "subscription_item", ... "price": { "id": "{{OLD_PRICE_ID}}", "object": "price", ... "recurring": { "aggregate_usage": "sum", "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "metered" }, ... }, ... } ], ... }, ..."schedule": { "id": ""sub_sched_1P1XxjDxxK6kAaV0YygN4tf7"", "object": "subscription_schedule", ... "current_phase": { "end_date": 1714759200, "start_date": 1712167200 }, ... "phases": [ { ... "end_date": 1714759200, ... "items": [ { ... "price": "{{OLD_PRICE_ID}}", ... } ], ... "start_date": 1712167200, ... "trial_end": 1712772000 } ], ... }, ... }, ... ], "has_more": false, "url": "/v1/subscriptions" } ``` If a subscription has a [schedule](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-schedule), you must update the existing [subscription schedule](https://docs.stripe.com/api/subscription_schedules.md) to migrate to the new price at the end of a billing period. If no schedule exists for a subscription, create a new one. > You must update the subscription schedule using a Stripe version on or before [2025-02-24.acacia](https://docs.stripe.com/changelog/acacia.md#february-24-2025). Starting with Stripe version [2025-03-31.basil](https://docs.stripe.com/changelog/basil/2025-03-31/deprecate-legacy-usage-based-billing.md), metered prices must be backed by meters. #### Create subscription schedules Create a subscription schedule for each subscription associated with the old price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription_schedule = client.v1.subscription_schedules.create({ "from_subscription": "{{SUBSCRIPTION_ID}}", }) ``` Stripe returns a new subscription schedule object: ```json { "id": ""sub_sched_1P1H37DxxK6kAaV0Iggc537m"", "object": "subscription_schedule", ... "current_phase": { "end_date": 1714693634, "start_date": 1712101634 }, ... "phases": [ { ... "end_date": 1714693634, ... "items": [ { ... "price": "{{OLD_PRICE_ID}}", ... } ], ... "start_date": 1712101634, ... } ], ... "status": "active", ... } ``` Update the subscription schedule to add a `phase` with the new price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription_schedule = client.v1.subscription_schedules.update( "sub_sched_1P1H37DxxK6kAaV0Iggc537m", { "phases": [ { "start_date": 1712101634, "end_date": 1714693634, "items": [{"price": "{{OLD_PRICE_ID}}"}], }, {"items": [{"price": "{{NEW_PRICE_ID}}"}]}, ], }, ) ``` #### Update existing subscription schedules The following subscription schedule is provided as an example. Your subscription schedule might be different. Let’s say you have a subscription schedule that starts a monthly subscription with a trial period: ```json { "id": ""sub_sched_1P1XxjDxxK6kAaV0YygN4tf7"", "object": "subscription_schedule", ... "current_phase": { "end_date": 1714759200, "start_date": 1712167200 }, "customer": ""{{CUSTOMER_ID}}"", ... "phases": [ { ... "end_date": 1714759200, ... "items": [ { ... "price": ""{{OLD_PRICE_ID}}"", ... } ], ... "start_date": 1712167200, ... "trial_end": 1712772000 } ], ... } ``` To migrate the price at the end of the billing period, add a `phase` with the new price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription_schedule = client.v1.subscription_schedules.update( "sub_sched_1P1XxjDxxK6kAaV0YygN4tf7", { "phases": [ { "start_date": 1712167200, "trial_end": 1712772000, "end_date": 1714759200, "items": [{"price": "{{OLD_PRICE_ID}}"}], }, {"items": [{"price": "{{NEW_PRICE_ID}}"}]}, ], }, ) ``` ## Test the migration Create a test customer with a subscription associated with the old price. #### Dashboard 1. Go to the [Customers tab](https://dashboard.stripe.com/test/customers). 1. Click **+ Add customer**. 1. Enter the name of the customer. 1. Go to the new customer. 1. Next to the Subscriptions header, click **+** to open the subscription drawer. 1. Select the old price. 1. Click **Create test subscription**. #### API Create the test customer. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. customer = client.v1.customers.create({"name": "John Doe"}) ``` Create a subscription associated with the old price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription = client.v1.subscriptions.create({ "customer": "{{CUSTOMER_ID}}", "items": [{"price": "{{OLD_PRICE_ID}}"}], }) ``` Create a subscription schedule from the subscription. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription_schedule = client.v1.subscription_schedules.create({ "from_subscription": "{{SUBSCRIPTION_ID}}", }) ``` Add a `phase` to the subscription schedule to migrate to the new price. ```python # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = StripeClient("<>") # For SDK versions 12.4.0 or lower, remove '.v1' from the following line. subscription_schedule = client.v1.subscription_schedules.update( "{{SUBSCRIPTIONSCHEDULE_ID}}", { "phases": [ { "start_date": 1710952582, "end_date": 1713630982, "items": [{"price": "{{OLD_PRICE_ID}}"}], }, {"items": [{"price": "{{NEW_PRICE_ID}}"}]}, ], }, ) ``` [Simulate the subscription change](https://docs.stripe.com/billing/testing/test-clocks/simulate-subscriptions.md) with a simulation. Learn more about [testing subscriptions integrations](https://docs.stripe.com/billing/testing.md). You can use [simulations]((/billing/testing/test-clocks) to test different scenarios, including mock usage reporting.