TL;DR: Stripe removed the legacy Usage Record resources from API version 2025-03-31.basil. During migration, Stripe tells legacy integrations to keep reporting Usage Records on 2025-02-24.acacia or earlier while they also begin sending Billing Meter events. This is not just a URL rename: meters are customer/event based, support different aggregation and ingestion modes, and legacy fields such as aggregate_usage and billing_thresholds were removed from the Basil contract.
This is the migration most teams discover by trying to upgrade their Stripe SDK and finding that a resource they depend on no longer exists.
What was removed, exactly
In API version 2025-03-31.basil, Stripe removed:
UsageRecordandUsageRecordSummary, and their endpointsaggregate_usageon pricesbilling_thresholds
Billing meters are the replacement, and Stripe is explicit that they are now the only solution for usage-based billing. There is no parallel track being maintained.
The old API version is migration debt, not an outage
Stripe's migration guide explicitly allows legacy Usage Records to keep running while you adopt Billing Meters, but those calls must use 2025-02-24.acacia or earlier because Basil removes the old resources. That makes version pinning a legitimate migration bridge.
The important constraint is narrower than "all new Stripe features disappear": the production paths that still depend on removed legacy resources prevent you from moving those API/webhook integrations cleanly onto the Basil contract. The longer those call sites remain, the more upgrade and test work accumulates around them.
Use the pin to create a controlled dual-reporting window, not as the final architecture.
The part that is not a URL swap
This is where the migration bites, and it is skipped in most write-ups because it only shows up once you look at your own call sites.
| Usage records (old) | Meter events (new) | |
|---|---|---|
| Keyed on | Subscription item | Customer, plus a meter event name |
| Needs a subscription first | Yes — no subscription item, nowhere to report | No. You can collect usage before the subscription exists |
| Authoritative / pre-aggregated values | action: 'set' with legacy last-style aggregation |
No 1:1 field rename. Current meters support last aggregation and raw or hourly/daily pre-aggregated ingestion; choose semantics deliberately. |
| Deduplication | Effectively your problem | identifier on the event |
| Late arrivals | Legacy rules depend on aggregation mode and billing period | Invoice finalization has a 1-hour default grace period that can be configured up to 72 hours |
If you used action: 'increment'
You are in the easy case. Increment maps onto meter events almost directly: each report becomes an event with a value, and the meter sums them. The work is plumbing — resolve the Stripe customer instead of the subscription item, name your meters, and start sending an identifier.
If you used action: 'set'
Stop before converting each authoritative total into an additive meter event. The current Billing Meter model has more options than the first meter release: aggregation formulas include sum, count, and last, while event ingestion can be raw or pre-aggregated into hourly/daily windows.
That means set is a semantics review, not automatically a rewrite to deltas. Ask what the old total represented:
- A true last-known gauge: investigate a meter configured with
last. - An hourly/daily authoritative bucket: investigate pre-aggregated ingestion, where a newer value replaces the earlier value inside that time window.
- A cumulative month-to-date counter: you may still need to emit deltas or transform the counter before reporting it, because repeatedly sending a growing total into a summed meter would overcount.
Stripe's own migration guide also calls out one legacy aggregation it does not support in Billing Meters: max. Inventory the old aggregate_usage value rather than assuming every legacy Price has the same migration shape.
The grace period is billing configuration, not a fixed constant
Stripe currently defaults invoice finalization to a one-hour grace period, during which usage for the previous billing period can still be reported. That default is configurable: Stripe documents finalization delays up to 72 hours.
So do not encode "one hour" into your transport design as if it were a protocol guarantee. Read the account's invoice-finalization configuration, size your queue/reconciliation policy around it, and remember that the first automatically collected subscription invoice finalizes immediately rather than following those normal delay rules.
This is the same question every metering system has to answer, and it is worth reading the general version of it before you decide.
A migration order that does not risk revenue
- Inventory your call sites and actions. Specifically: how many use
set. That number decides whether this is a week or a quarter. - Create meters and prices alongside the old ones. Do not modify live prices; make new ones.
- Dual-report. Send usage records and meter events for a full billing period. Stripe's own guidance is to keep sending usage records until the migration is complete — take that literally.
- Reconcile per customer, per meter, per period. Matching grand totals is not agreement. Check each key, and expect the discrepancies to cluster around retries and period boundaries.
- Plan the subscription cutover deliberately. Stripe's migration guide uses subscription schedules to move subscriptions to the new meter-backed price at the end of the current phase.
- Bump the API version last, once nothing calls the old resources.
- Keep the old data readable for at least one dispute cycle. The first argument about a number will happen after you have cut over.
The question worth asking while you are in here
You are about to re-instrument every usage call site in your product. That is the expensive part, and it is the part you would have to repeat if you ever changed billing vendor — which, after Stripe bought Metronome, Adyen bought Orb and Salesforce bought m3ter, is no longer a hypothetical.
So it is a reasonable moment to ask whether product code should post its only copy of usage directly into the payment processor, or whether an independent metering layer should preserve the quantity first and let Stripe remain the pricing/invoice system. UsageBox does not rate Stripe prices or rewrite subscriptions; the value of that boundary is that your product's measurement contract and raw usage evidence do not have to move at the same time as the biller.