# 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). ```curl curl https://api.stripe.com/v1/billing/meters \ -u "<>:" \ -d display_name=Hypernian \ -d event_name=api_request \ -d "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. ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PRODUCT_ID}} \ -d "recurring[interval]"=month \ -d "recurring[usage_type]"=metered \ -d "recurring[meter]"={{METER_ID}} \ -d currency=usd \ -d 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. ```curl curl https://api.stripe.com/v1/billing/meter_events \ -u "<>:" \ -d event_name=api_request \ -d timestamp=1712096183 \ -d identifier={{IDEMPOTENCY_KEY}} \ -d "payload[stripe_customer_id]"={{CUSTOMER_ID}} \ -d "payload[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). ```curl curl -G https://api.stripe.com/v1/billing/meters/{{METER_ID}}/event_summaries \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d start_time=1717249380 \ -d 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. ```curl curl -G https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d price={{OLD_PRICE_ID}} \ -d "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. ```curl curl https://api.stripe.com/v1/subscription_schedules \ -u "<>:" \ -d 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. ```curl curl https://api.stripe.com/v1/subscription_schedules/sub_sched_1P1H37DxxK6kAaV0Iggc537m \ -u "<>:" \ -d "phases[0][start_date]"=1712101634 \ -d "phases[0][end_date]"=1714693634 \ -d "phases[0][items][0][price]"={{OLD_PRICE_ID}} \ -d "phases[1][items][0][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. ```curl curl https://api.stripe.com/v1/subscription_schedules/sub_sched_1P1XxjDxxK6kAaV0YygN4tf7 \ -u "<>:" \ -d "phases[0][start_date]"=1712167200 \ -d "phases[0][trial_end]"=1712772000 \ -d "phases[0][end_date]"=1714759200 \ -d "phases[0][items][0][price]"={{OLD_PRICE_ID}} \ -d "phases[1][items][0][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. ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d name="John Doe" ``` Create a subscription associated with the old price. ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d customer="{{CUSTOMER_ID}}" \ -d "items[0][price]"={{OLD_PRICE_ID}} ``` Create a subscription schedule from the subscription. ```curl curl https://api.stripe.com/v1/subscription_schedules \ -u "<>:" \ -d from_subscription="{{SUBSCRIPTION_ID}}" ``` Add a `phase` to the subscription schedule to migrate to the new price. ```curl curl https://api.stripe.com/v1/subscription_schedules/{{SUBSCRIPTIONSCHEDULE_ID}} \ -u "<>:" \ -d "phases[0][start_date]"=1710952582 \ -d "phases[0][end_date]"=1713630982 \ -d "phases[0][items][0][price]"={{OLD_PRICE_ID}} \ -d "phases[1][items][0][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.