Enable flexible behavior for subscriptions
Use billing mode to control how prorations and invoices for subscriptions are calculated and orchestrated.
Currently, Stripe calculates credit proration amounts based on the value of the subscription item’s current price, tax, quantity, and the last discounts used.
You can configure billing_
to enable a different proration logic that calculates credit prorations based on the original amount previously debited to a customer.
Public preview
To enable the new proration calculation logic by configuring billing_
, you must upgrade your API version to 2025-04-30.
or later.
The current behavior could lead to unexpected prorations when a customer’s tax rates change, you disable debit prorations, or you use complex amounts off coupons. The improved proration logic calculates credit prorations based only on the original amount previously debited to a customer. When a customer makes a change to their subscription that results in a credit, Stripe calculates the proration using the amount they were previously billed. This calculation occurs regardless of subsequent changes made to the subscription. Stripe recommends using billing_
if the limitations of the public preview don’t apply to you.
Public preview limitations Public preview
During public preview, billing_
isn’t compatible with all of Stripe Billing’s functionality.
When you configure billing_
:
- Usage-based billing isn’t supported.
- Automatic tax calculation isn’t supported.
- Trials isn’t supported.
- Quotes endpoints isn’t supported.
- You can’t create backdated subscriptions.
- You can’t pause payment collection on subscriptions.
If you use these features with billing_
, they return a 400 error code.
Configure billing mode Public preview
You can configure billing_
on specific subscriptions, and you can have multiple subscriptions with different billing_mode configurations. You can’t change the billing_
from flexible
to classic
. This ensures consistent logic and behavior throughout each subscription’s lifecycle. You can migrate existing subscriptions from billing_
to billing_
.
When you configure billing_
, it also updates subscription.trial_start to reflect the most recent trial start date.
Migrate subscriptions to flexible billing mode Public preview
You can migrate existing subscriptions from billing_
to billing_
using the Subscription migration endpoint. Migration to flexible
billing mode is a one-way process. After you migrate a subscription to flexible
mode, you can’t revert it to classic
mode. This ensures consistent proration logic throughout the subscription’s lifecycle.
When you migrate a subscription, the billing_
timestamp updates to reflect when the billing_
changes.
Flexible billing mode changes
Setting billing_
on a subscription changes how Subscription objects behave throughout their lifecycle and in response to upgrades, downgrades, and cancellations.
Calculation logic with no prorations
In the following scenario, you upgrade a 10 EUR monthly subscription to 20 EUR with the proration_
set to none
for 10 days. There’s no previous debit to base it on. Later, you downgrade the subscription to 10 EUR a month with the proration_
set to always_
.
To set up this scenario, first you create a subscription for 10 EUR/month on 2025-04-01:
The response includes the invoice that’s created for this subscription:
{ id: "sub_123", latest_invoice: { id: "in_123", total: 10_00, currency: "usd" } }
Then, on 2025-04-11, you upgrade the subscription to 20 EUR/month without creating prorations:
The latest invoice remains unchanged because proration_
is none
:
{ id: "sub_123", latest_invoice: { id: "in_123" } }
Finally, on 2025-04-21, you downgrade the subscription to 10 EUR/month and create prorations:
The default proration calculation logic creates a credit proration based on the current price, even though the customer never paid the 20 EUR/month rate. The latest invoice credits a third of the month for 20 EUR (-6.67 EUR), even though the customer never paid for the price_
price. It also debits a third of the month for 10 EUR (3.33 EUR).
The calculation logic enabled with billing_
creates a credit proration based on the last price billed for the subscription item. In this case, the latest invoice credits a third of a month for the 10 EUR/month price billed on 2025-04-01 (3.33 EUR) and debits a third of the month for the 10 EUR price (3.33 EUR). The credit and debit cancel out so the invoice total is 0 EUR.
# Default behavior # billing_mode = classic { id: "sub_123", latest_invoice: { id: "in_456", total: -3_34, currency: "usd" } }
# New behavior # billing_mode=flexible { id: "sub_123", latest_invoice: { id: "in_456", total: 0, currency: "usd" } }
Calculation logic for coupons applied to multiple subscription items
Stripe weights the amount_
coupon on the credit proration to prevent over-billing.
In the following scenario, a 5 EUR coupon is unevenly allocated to a 25 EUR monthly subscription for a 10 EUR item and 20 EUR item.
To set up this scenario, you create a subscription with multiple items and a coupon on 2025-02-01:
Which returns this response:
{ id: "sub_123", latest_invoice: { id: "in_123", total: 25_00, currency: "usd", lines: { data: [ { id: "ili_1", amount: 10_00, price: "price_10_monthly", discount_amounts: [{ discount: "di_a", amount: 1_66 }] }, { id: "ili_2", amount: 20_00, price: "price_20_monthly", discount_amounts: [{ discount: "di_a", amount: 3_34 }] }, ] } } }
To cancel the 10 EUR/month subscription item using billing_
:
To cancel the same item using billing_
:
The default behavior distributes a 5 EUR coupon to each item (2.5 EUR each), canceling the cheaper item (5 EUR) and resulting in a refund of 2.5 EUR. Stripe calculates the total with the formula -0.
The new behavior reflects the proportional discount applied to the canceled item, rather than potentially applying the full discount amount to the proration calculation. Stripe calculates the total using the formula -0.
.
# Default behavior # billing_mode = classic { "id": "sub_123", "latest_invoice": { "id": "in_456", "total": -250, "currency": "usd" } }
# New behavior # billing_mode = flexible { "id": "sub_123", "latest_invoice": { "id": "in_789", "total": -417, "currency": "usd" } }
Billing cycle anchor resets
When you make changes to a subscription, the billing_cycle_anchor isn’t implicitly reset. For example, switching a subscription to a different price with a different recurring interval or moving cancel_at to a date before the next time the subscription cycles doesn’t reset the billing_
.
Trial start and end dates
The subscription.
uses the most recent trial start date for subscriptions with subsequent trials.