Subscribe
← All articles
Sep 8, 2026

Upgrade now, downgrade at renewal: the switch you have to design

By Built and shut down a subscription platform on Stripe Connect, Telegram Stars and crypto payouts

A black automatic gear selector lit against a dark car interior, the P R N D gate visible beside it

Between April and June 2026 we built Volta, a subscription platform for creators selling access to an audience. It was ours, we retired it in August, and along the way we shipped the parts nobody demos: refunds, disputes, failed renewals, and the one this article is about, a member moving between tiers in the middle of a billing period.

Here is the situation the code has to answer. A member is on your $12 tier. On day nine of a thirty-day cycle they tap the $29 tier. They have already paid for the $12 month. They are about to consume three more weeks of a plan that costs more. Some amount of money should change hands, at some point, and every part of that sentence is a decision you make rather than a default you accept.

What Stripe does when you say nothing

Stripe's word for the money math is proration: the member "is charged a percentage of a subscription's cost to reflect partial use."[1] Change the price on a subscription item and, unless you tell it otherwise, Stripe builds two line items. One credits the unused time on the old price. One debits the remaining time on the new price. Stripe's own example is a $10 plan going to $20 at the halfway mark: a -$5 credit for the unused half, a +$10 debit for the new half, $5 owed on balance.[1]

Run our numbers through it. Twenty-one days left, $12 tier to $29 tier, and the member owes roughly $11.90 for the upgrade. The question is when they pay it, and the default answer surprises people. The setting that governs this is proration_behavior, its default value is create_prorations, and those proration items "are only invoiced immediately under certain conditions."[1] Absent those conditions, nothing is charged today. The member is on the $29 tier immediately, and the $11.90 rides along on their next renewal invoice, which will read $40.90 instead of $29.

Downgrades are quieter and stranger. Move the same member from $29 back to $12 mid-cycle and Stripe issues a credit proration for the unused expensive time.[1] It does not refund it. "Negative prorations aren't automatically refunded",[1] so the member carries a balance that gets subtracted from future invoices. Their next charge is smaller than $12, maybe zero, sometimes for two cycles running, and your revenue dips without a cancellation anywhere to explain it.

The four ways a switch can land

The default is one option. Here are the others, each a different value of the same parameter.

Bill it now. Set proration_behavior to always_invoice and Stripe "calculates the proration, then immediately generates an invoice."[1] The member pays the $11.90 on the spot and the renewal date does not move.

Bill it now and restart the clock. Set billing_cycle_anchor to now. This sets "the billing cycle anchor to the time of the update request", and "after you reset the billing cycle anchor, Stripe immediately sends an invoice",[2] so the member pays a full $29 today and their renewal date shifts to today's date. Proration still matters here: enable it on the reset "to credit the customer for any days already paid", because disabling it "might result in overcharging your customer."[2]

Have it forced on you. If the upgrade also changes the interval, monthly to annual, the reset is not optional. Different billing periods mean "the new price is billed at the new interval, starting on the day of the change",[3] and the anchor "resets to the current time when switching to a price with a different" recurring interval.[2] A member clicking from your $29 monthly to your $290 annual gets a $290 charge that day, whatever you set.

Don't prorate at all. Set proration_behavior to none and there is no credit and no debit. Customers "are billed the full amount at the new price when the next invoice is generated."[1] The member is on the $29 tier for the rest of this cycle at no extra cost, then renews at $29. Generous on an upgrade. On a downgrade it means they keep the tier they are leaving until the period ends, which is usually what both sides expect.

One more thing the API will do behind your back. When you swap a price you have to name the subscription item you are replacing. Skip that and Stripe adds the new price instead of swapping it, and "both prices are active for the subscription."[3] The member is now billed for both tiers. This is a real bug we have seen in other people's integrations, and it renews cleanly every month until someone reads an invoice closely.

Why we made upgrades charge now and downgrades wait

We picked two of the four and held to them.

Upgrades billed immediately, with always_invoice. If a member asks for more, they get more the moment the payment clears, not three weeks later on a confusing invoice. We paired it with pending updates so "the subscription doesn't update unless payment succeeds on the new invoice."[3] That pairing exists because of the failure mode: when a switch bills immediately and the card is declined, "the subscription change request succeeds and the subscription transitions to past_due."[3] Without pending updates, a member with a bad card taps upgrade and lands on the higher tier in a delinquent state, which is the worst of both. With it, a failed payment leaves them exactly where they were.

Downgrades went the other way. We scheduled them for the period end and left proration off, so there is no mid-cycle credit, no sub-$12 invoice, and no revenue dip with no story behind it. The member keeps the tier they paid for until the date they already know, and the smaller charge starts on the next real renewal. The alternative, an automatic credit, meant either paying cash out of the creator's balance or parking a balance the member did not ask for and would email us about. Neither was worth it on memberships priced in low double digits.

And before any upgrade committed, we previewed it. Stripe lets you generate the upcoming invoice without touching the subscription, and the docs are direct about why: "use this information to confirm the changes with the customer before modifying the subscription."[1] We showed the member the exact figure and the exact next-invoice total on the confirm screen. The one trap is that Stripe "prorates to the second", so "prorated amounts might change between the time they're previewed and the time the update is made."[1] Pin the proration timestamp when you preview and pass the same one when you commit, or the number the member agreed to is not quite the number they get.

The rail with no mid-cycle at all

All of the above is card infrastructure. Telegram Stars and crypto have no processor running a billing period on your behalf, so there is no partial period to split and nothing to prorate. Changing what a member pays means starting a fresh purchase and winding down the old one, and the reconciliation between the two is manual work you do by hand.

The only clean lever is a full refund. Telegram's terms let a bot return Stars to the buyer "in full via the relevant Telegram Bot API method, with no penalty",[4] so a Stars tier change is: refund the remainder of the old purchase, sell the new one, hope the member does both steps. Crypto does not even give you that. There is no reverse on a chain, so a downgrade refund is an operator deciding an amount and sending it.

Mid-cycle proration is a feature of the card rail specifically. On the other two, "change your plan" becomes an operation someone runs by hand rather than a setting you expose, and the cost of supporting tier changes at all is a reason those rails suit lifetime and one-off pricing better than a ladder of memberships.

Before you ship a tier ladder

Decide the upgrade timing and the downgrade timing before a member ever asks, because the first time you find out what your integration does is otherwise a support ticket. Write both into the checkout copy so the member reads "you'll be charged $11.90 now" or "your new rate starts on the 30th" and there is no surprise to answer for.

Preview every proration and show the member the number. Pin the proration date across the preview and the commit.

Watch for the sub-$12 invoice after downgrades if you ever leave proration on. That is a credit being spent down. In your revenue chart it looks exactly like a billing failure.

And read one real invoice after you wire up price changes, all the way down, to make sure a switch replaced the old tier instead of stacking a second one on top of it.

Disclosure. Volta was our product, it is retired, and nothing here is a recommendation to use it. The choice to bill upgrades immediately, schedule downgrades for period end, turn proration off on the way down, and preview every change is from our own build rather than anyone's documentation, so it carries no citation. Everything attributed to Stripe or Telegram is quoted from public documentation, listed and dated below.

Sources

Every external figure in this article is cited to the provider's own published terms, checked 8 September 2026.

  1. 1.Stripe, Prorations - proration charges a percentage of a subscription's cost to reflect partial use; an upgrade halfway through a period credits unused time on the old price and debits remaining time on the new one; negative prorations aren't automatically refunded and positive prorations aren't immediately billed; the default proration_behavior is create_prorations and those items are only invoiced immediately under certain conditions; always_invoice calculates the proration then immediately generates an invoice; with prorations disabled the customer is billed the full new price on the next invoice; credit prorations are issued on downgrades before period end; Stripe prorates to the second and previewed amounts can change before the update is made; preview to confirm the change with the customer first
  2. 2.Stripe, Set the subscription billing renewal date - setting billing_cycle_anchor to now moves the anchor to the time of the request and Stripe immediately sends an invoice; enable proration on that reset to credit days already paid or risk overcharging; the anchor resets to the current time when switching to a price with a different recurring interval
  3. 3.Stripe, Change the price of existing subscriptions - same billing periods keep the same billing dates, different periods bill the new price at the new interval starting the day of the change, so monthly to yearly moves the billing date to the switch; Stripe attempts payment immediately when the anchor is reset and if it fails the change still succeeds and the subscription goes past_due; replacing a price requires naming the subscription item or Stripe adds the new price alongside the old one; combine always_invoice with pending updates so the subscription doesn't change unless payment succeeds
  4. 4.Telegram, Bot Developer Terms of Service - Stars can be returned to the purchaser in full via the Bot API with no penalty