# 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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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/{{SUBSCRIPTIONSCHEDULE_ID}} \
  -u "<<YOUR_SECRET_KEY>>:" \
  -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/{{SUBSCRIPTIONSCHEDULE_ID}} \
  -u "<<YOUR_SECRET_KEY>>:" \
  -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).
2. Click **+ Add customer**.
3. Enter the name of the customer.
4. Go to the new customer.
5. Next to the Subscriptions header, click **+** to open the subscription drawer.
6. Select the old price.
7. Click **Create test subscription**.

#### API

Create the test customer.

```curl
curl https://api.stripe.com/v1/customers \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "name=John Doe"
```

Create a subscription associated with the old price.

```curl
curl https://api.stripe.com/v1/subscriptions \
  -u "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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](https://docs.stripe.com/billing/testing/test-clocks.md) to test different scenarios, including mock usage reporting.

If you upgraded your Stripe SDK but still need legacy UsageRecords APIs, see [Upgrade your SDK without migrating from usage records](https://docs.stripe.com/billing/subscriptions/usage-based-legacy/sdk-upgrade.md).
