Back to Explore
GuideVibeFix 编辑部Updated Nov 6, 2026

Upgrades, Downgrades, and the Math in Between: Proration for Vibe Projects

A user changes tiers mid-cycle — how much do they actually owe? This guide covers the one top-up formula for upgrades, the trade-offs between the three ways to handle a downgrade, how annual, quarterly, and team-seat billing convert, how coupons and taxes fit into the math, the three payment-platform switches people get wrong, and a pre-launch checklist to tick off item by item.

Real photograph of hands checking paper bills with a pencil and a phone calculator beside a laptop

Upgraded, Then Charged for a Whole Extra Month: A Fictional Lesson First

Here is a fictional teaching example. A Yuan built a notes app on his own with AI, called "Yunshan Notes," with three tiers: a free tier, a Basic tier at 30 yuan a month, and a Pro tier at 90 yuan a month. In the third week after launch, a user upgraded from Basic to Pro and wrote in the same day: I already paid 30 yuan this month, so why did upgrading charge me another full 90 yuan? A Yuan checked the billing records and found the problem: the upgrade code the AI had written simply charged the full new price the moment a user upgraded, and the 30 yuan already paid counted for nothing.

A Yuan rushed to fix it. Two days later, another user downgraded from Pro back to Basic and asked: I have only used 10 days this month, shouldn't I get some of the remaining 20 days back? The downgrade code, it turned out, had no refund logic at all: the user was still charged the full 90 yuan for the month, but the tier had already dropped. The user's own words were: you charge the full price and drop the tier on the same day — what kind of deal is that?

Both stories are the same problem: when a subscription changes tiers mid-cycle, nobody did the math on "how many days were used, and how many days are left." When a user upgrades, the money already paid has to count toward the new tier. When a user downgrades, the unused days need an answer. Whether it is an overcharge or a missing refund, a user's first reaction is not "there must be a bug" — it is "this shop is ripping me off." One person thinking that is enough for a one-star review and an angry post, and repairing that costs far more than writing the code right.

This guide is about getting that math right: how much extra an upgrade costs, whether a downgrade refunds anything, how annual billing and team seats convert, how coupons and taxes stay out of trouble, what the three switches in your payment platform actually do, and a pre-launch checklist you can tick off item by item. Every person, product name, and number in this guide is a fictional teaching example, used only to make the ideas clear; the day counts, amounts, and ratios are engineering rules of thumb from experience, not any official standard, so verify them against your own price list before you use them.

Real photograph of hands checking paper bills with a pencil and a phone calculator beside a laptop

1. Draw the Boundary First: Proration Only Covers Mid-Cycle Tier Changes

Before writing anything, draw the boundary clearly, because several different jobs look alike and get mixed into one calculation. Proration covers exactly one thing: when a user changes tiers before a billing cycle has finished, how is the rest of that cycle charged? A user moving from a 30-yuan tier to a 90-yuan tier mid-month and paying the difference, or moving from 90 down to 30 and asking what comes back — that is what this guide is about.

Several things that look similar are not this guide's job. First, what happens when a payment fails — an empty card, a bank decline, how many retries, when to send reminders — that is subscription dunning, covered by another guide on recovering failed renewals, and this guide will not repeat it. Second, downgrades when a trial ends — a 14-day trial finishes and the user drops back to the free tier — that is about trial expiry reminders and timing, covered by the trial-expiry guide. Third, when you raise your own prices — Pro goes from 90 to 110 yuan, and old users ask whether they keep the old price — that belongs to the guide on price changes and grandfathering. Fourth, adding and removing team members — the seat math appears in section 5, but the full rules for per-seat billing have their own guide. Fifth, credits and balances — leftover points and top-up balances — that is the credits-ledger guide's territory.

The boundary matters in practice: the math of a mid-cycle tier change is already messy enough, and mixing in failed renewals, trial expiry, and official price rises means no single if-branch in your code stays readable. Get the one scenario of "changing tiers mid-cycle" right and transparent first, and deal with the neighbors after that.

2. What Proration Actually Calculates: Just One Formula

The whole idea fits in one sentence: for the days of this cycle the user spent on the old tier, they pay the old tier's price; for the days left on the new tier, they pay the new tier's price. Money already paid is not thrown away — it is deducted from the new tier's charge. Written as a formula: top-up = (new monthly price - old monthly price) x days remaining / total days in the cycle.

Run the numbers with the Yunshan Notes example. Basic is 30 yuan a month, Pro is 90 yuan a month, and one cycle is 30 days. A user upgrades on day 10: the first 10 days were on Basic, the remaining 20 days are on Pro. Top-up = (90 - 30) x 20 / 30 = 40 yuan. The user pays 30 + 40 = 70 yuan in total for the cycle, which is exactly 10 days of Basic (10 yuan) plus 20 days of Pro (60 yuan). The numbers reconcile to the last cent, and the user can check them with a pocket calculator — that is the whole point of proration: the user should be able to verify the bill without you explaining it.

Diagram: upgrading on day 10 of a monthly cycle — how the 40 yuan prorated charge is calculated

Three places are where this calculation most often goes wrong. First, count days by the actual cycle, not by the calendar month. February has 28 days and January has 31; if the code hard-codes 30 days a month, a user who upgrades in February overpays by a few days. Count from the user's real billing cycle: however many days sit between the last charge date and the next one, that is the denominator. Second, "which day is it" should follow the user's local time, not the server's time. A server on UTC and a user eight hours ahead can disagree by a full day when an upgrade lands exactly on the boundary between two days. Third, keep amounts precise to the cent and round only once, at the very last step. Rounding at every step leaves the bill a few cents away from what the user calculates, and support will spend forever explaining the difference.

One more rule of thumb: when the top-up is tiny, do not charge it. If a user upgrades on the last day of a cycle, the top-up is (90 - 30) x 1 / 30 = 2 yuan. A separate invoice and a separate charge for 2 yuan puts an extra 2-yuan line on the bill, and that feels worse than charging nothing. The engineering suggestion is: waive top-ups under 5 yuan, or roll them into the next cycle, and say so on the page — "this upgrade is free; the new tier applies from next cycle." Five yuan is not a standard, just a rule of thumb, and the goal is a clean bill.

3. How to Charge an Upgrade: Top Up Now, or Wait Until Next Cycle

There are two ways to charge an upgrade, and each has a cost. The first is to top up immediately: the moment the user upgrades, calculate the top-up with the formula from section 2, charge it, and switch the tier on the spot. The user gets the Pro features right away, and you get the money right away. The second is to take effect next cycle: the user upgrades now, but the current cycle continues on the old tier, and the new price and the new tier only start at the next charge date. The books stay perfectly clean, but the user has to wait — and if they upgraded because they urgently need a Pro feature, making them wait half a month is a good way to lose them.

The engineering suggestion is: upgrades top up immediately and take effect immediately. That is what most users expect by default: I clicked upgrade, I paid the difference, the features should work now. Doing it the other way around — taking the money and still making the user wait — draws more complaints than overcharging. There are two exceptions. First, moving from the free tier to a paid tier is a first payment, not a top-up: charge the full new price and do not drag the free tier into the formula. Second, if the user is still inside a trial when they upgrade, do not rush to charge — let the trial finish, then charge the new tier when it ends, and say so on the page: "after the trial ends, you will be charged 90 yuan a month for Pro."

One more detail for immediate top-ups: what happens when the top-up charge fails? A 40-yuan top-up fails, and you must neither silently drop the user back to the old tier nor let them believe they are already on Pro. The right behavior is: do not upgrade the tier yet, and tell the user plainly on the page — "upgrade incomplete: the 40-yuan top-up failed, please change your payment method" — then upgrade once the charge succeeds. Keep this message separate from the failed-renewal message and do not share the same copy: the user is not facing a "failed renewal" here, they are facing an "upgrade that did not go through," and the wrong wording makes them think they will be charged twice next month.

4. Downgrades Cause the Most Arguments: Refund, Credit, or Wait Until Next Cycle

Downgrades are harder than upgrades, because a downgrade means giving money back, and there are three ways to do it — each of which annoys somebody. The first is an immediate refund: return the price difference for the remaining days to the original payment method. Users love it, but your cash flow hates it, and refunds cost another round of processing fees, so the more you refund, the more fees you eat. The second is account credit: instead of cash back, the difference becomes balance used against the next charge. Cash flow is protected, but the user feels their money is locked inside your product. The third is to take effect next cycle: keep charging the old tier and keep the old features for the rest of this cycle, and only charge the new tier from the next charge date. The books are simplest and nothing needs refunding, but the user asks: I already downgraded, why am I still being charged 90 yuan this month?

The engineering suggestion is: downgrades take effect next cycle by default, with no refund and no credit. This is the hardest to get wrong and the easiest to explain on the page: "downgrade requested — you keep Pro until the end of this cycle, and from next cycle you are charged 30 yuan a month for Basic." The user loses nothing right now — the Pro features they paid 90 yuan for keep working until the end of the month — so acceptance is better than most people expect. Support can also use one fixed line: a downgrade is not "downgrade now," it is "start charging the lower tier next month," with the higher features running until the cycle ends.

But the next-cycle default has two exceptions where money should go back. First, annual billing: a user who paid 900 yuan for the year and downgrades after 100 days has 265 days of difference left, and that is not small change — making them wait 265 days is not fair. For an annual downgrade, offer credit or a pro-rata refund, calculated the same way as the annual formula: price difference x days remaining / 365. Second, when the user downgrades because the product broke — say the Pro tier's core feature was down for three days — do not haggle over days; refund it. Refunding more or less in that case is a matter of attitude, and support should have a standing permission: "for a fault-driven downgrade, refund the remaining difference directly."

Whichever approach you choose, one thing is not optional: the downgrade confirmation page must spell out the money. Before the user confirms, the page should state three things in plain text: how much this cycle still costs, when the new tier's price starts, and whether there is a refund and how much. Many complaints are not really about "how much was refunded" — they are about "nobody told me beforehand." Put that line on the page and complaints fall by at least half.

5. Annual, Quarterly, and Team Seats: The Same Formula With a Different Denominator

Once you know the monthly formula, annual, quarterly, and team seats are the same formula with a different denominator and unit price. Annual first. Yunshan Notes charges 900 yuan a year for Pro and 300 yuan a year for Basic. A user upgrades from annual Basic to annual Pro on day 100, with 265 days left: top-up = (900 - 300) x 265 / 365, about 436 yuan. Note the denominator is 365, not 12 months; in a leap year it is 366 — do not hard-code it. One more trap: after an annual upgrade, when is the next charge date? The suggestion is to keep the billing anchor unchanged — the charge date stays what it was, only the difference is topped up, and the cycle does not restart. That way the user has one date to remember each year, and support has one date to explain.

Quarterly billing works the same way, with the denominator as the actual days in that quarter. The first quarter has 90 days and the second has 91; let the denominator follow the real calendar instead of hard-coding 90. Quarterly billing has the same small-top-up trap: a user upgrading in the last two days of a quarter owes only a few yuan, and by the rule at the end of section 2, anything under 5 yuan should be waived or rolled into the next cycle rather than billed on its own invoice.

Team seats are a different variation: the unit price is per person, and the days are the days left in the cycle. Yunshan Notes charges 199 yuan per person per month for the team tier. A 5-person team grows to 8 people on day 10, adding 3 people: top-up = 3 x 199 x 20 / 30, about 398 yuan. Removing people follows the advice in section 4 and takes effect next cycle: all 8 seats keep working for this cycle, and the next cycle bills for 5. The most common bug with seats is charging the full per-person price — adding 3 people and charging 3 x 199 = 597 yuan without pro-rating the remaining days — and the user spots the overcharge the moment they read the bill. One more detail: when seats go up and down on the same day, charge only the final net change. Adding 2 people in the morning and removing 2 in the afternoon is a net change of zero, so the bill should show zero — not two separate invoices in one day.

6. Coupons, Taxes, and Currency: Keep Discounts From Breaking the Math

The math of a tier change is already messy enough; coupons, taxes, and multiple currencies make it easy to get wrong. Coupons first. Yunshan Notes charges 90 yuan a month for Pro, and the user holds a 20%-off coupon; Basic at 30 yuan a month has the same 20% off. Should the upgrade top-up be calculated on the full price or the discounted price? The engineering suggestion is: calculate the difference on the discounted price. Discounted Pro is 72 yuan, discounted Basic is 24 yuan, so the difference is 48 yuan, and a day-10 upgrade tops up 48 x 20 / 30 = 32 yuan. Calculating the difference on the full price and then discounting it gives the same number, but the invoice is harder to write — a user can follow "price difference 60 yuan at 20% off is 48 yuan," and can also follow "top-up 40 yuan at 20% off is 32 yuan," but the worst outcome is the code mixing both methods, so some bills use the full price and others the discounted one, and nothing reconciles.

Coupons have another trap: the expiry date. The user's 20%-off coupon expires at the end of this month, and they upgrade the day before it ends — the top-up is discounted, but when the next month's charge comes, the coupon is gone. Does the next charge use the full 90 yuan, or keep the 20% off? The suggestion is: a coupon only affects the payments inside its validity period, and after it expires the full price applies — and the page should say so in advance: "coupon valid until the end of this month; the full price applies from next cycle." Otherwise the user sees the bill jump from 72 back to 90 yuan next month and assumes you quietly raised the price.

Tax has exactly one rule: tax the amount actually collected. For a 40-yuan top-up, tax is calculated on 40 yuan — not on the new tier's full price of 90 yuan, and not on "the 70 yuan the user paid in total this cycle." On the invoice, split the tier change into two lines: one line reading "unused Basic portion credit -20 yuan" and one reading "Pro remaining-days charge +60 yuan," totaling 40 yuan. The user can reconcile the invoice at a glance, and finance can trace it later. Multiple currencies follow the same idea: if the user pays in US dollars, the top-up is calculated in US dollars too — do not calculate a dollar bill from the yuan price list, because exchange-rate movement makes the same charge come out differently in different places.

7. The Three Switches in Your Payment Platform: Do Not Let Defaults Decide for You

Many vibe projects collect subscriptions through a platform like Stripe, and tier changes come with ready-made switches — but AI-generated code often leaves them at their defaults, and the defaults may not be what you want. In Stripe, changing a subscription has a parameter called proration_behavior with three options. The first is create_prorations, which is also the default: calculate the pro-rata difference and create a pro-rata charge. The second is none: no difference is calculated — the tier changes but the money does not move, so the user pays nothing extra this cycle and the new tier's price only starts next cycle. The third is always_invoice: calculate the difference, open an invoice immediately, and charge it right away.

None of the three is wrong; what is wrong is not knowing which one you are using. The most common accident goes like this: the developer wants "upgrade and top up immediately," but the code never passes the parameter, so Stripe uses its default create_prorations — the difference is created but not charged at once, and instead rides along on next cycle's bill. The user is not charged this month, then sees an extra 40 yuan on next month's bill and reports an overcharge. The reverse happens too: a developer who wanted "take effect next cycle" left the default in place, the difference was created immediately, the user was charged 40 yuan this month, and complains "didn't you say it starts next cycle?" The advice in this section is a single sentence: write proration_behavior explicitly in the code that changes a subscription — never leave it to the default.

Another switch that is easy to miss is the billing cycle anchor, billing_cycle_anchor. When a user upgrades, the anchor has two choices: keep it unchanged, or reset it to the upgrade day. Keeping it unchanged means the monthly charge date stays the same and only the difference is topped up; resetting it means the upgrade day becomes the new charge date and the cycle restarts from today. The engineering suggestion is to keep it unchanged by default — the user is used to being charged on the 5th of each month, and if an upgrade moves that to the 17th, they will think the subscription broke when nothing is charged on the 5th, then think they were double-charged when the 17th arrives. The only case for resetting the cycle is when the user asks for it — "start a fresh year from today" — and even then they should confirm it with their own click on the page, not have it changed silently.

One last reminder: test tier-change logic with real tests, not just by clicking through it by hand. Subscription code written by AI looks right after two manual clicks, and the few cents of error only show up when the books are reconciled at month's end. Cover at least four cases in tests: a mid-cycle monthly upgrade, a mid-cycle monthly downgrade, an annual upgrade, and adding team seats. Write the expected value for each case by hand and put it in the test — use the formula from section 2, but do not let the test and the code share the same formula, or a mistake will be wrong in exactly the same way in both places and the test will catch nothing.

8. The Pre-Launch Checklist

This checklist is for the final pass before launch: twelve items, ticked off one by one, and nothing ships until every box is checked. Each item says how to verify it, so the check does not become a formality.

  1. Upgrade top-up formula verified by hand: calculate three cases yourself (early-cycle, mid-cycle, and late-cycle upgrades) and confirm the page, the bill, and the backend record all show the same numbers.
  2. Downgrade policy fixed in code: next cycle by default, credit or pro-rata refund for annual downgrades, direct refund of the remaining difference for fault-driven downgrades — and support has that permission.
  3. Downgrade confirmation page carries three lines: how much this cycle still costs, when the new tier starts charging, and whether there is a refund and how much.
  4. Top-ups under 5 yuan handled: waived or rolled into the next cycle, stated on the page, and never billed on a separate small invoice.
  5. Days counted by the actual cycle: the denominator is the real number of days between this user's last and next charge dates, not a hard-coded 30.
  6. "Which day is it" follows the user's local time: server and user time zones are aligned, and an upgrade at the boundary between two days cannot be off by one day.
  7. Amounts precise to the cent with a single rounding step: no rounding in the middle, and the invoice splits the change into two clear lines.
  8. Coupons applied to the discounted difference: the price returns to full after the coupon expires, and the page states the expiry date in advance.
  9. Tax calculated on the amount actually collected: the tax on a top-up follows the top-up, and invoice lines match the bill.
  10. Payment-platform parameters written explicitly: proration_behavior and the billing cycle anchor are both set in code, never left to defaults.
  11. Same-day tier changes counted by net change only: adding two seats in the morning and removing two in the afternoon is a net change of zero, and the bill shows zero — no extra invoices.
  12. Failed top-up has its own message: when an upgrade top-up fails, the tier does not change, and the page says "upgrade incomplete" instead of reusing the failed-renewal copy.

After the checklist, remember the five most common traps. First, charging the full new price on upgrade without deducting what was already paid — the accident this guide opened with, and the one AI-written subscription code makes most often. Second, refunding a downgrade on the same day while the user keeps the higher features until the end of the month — half a month given away for free. Third, counting days by the calendar month, so February users overpay by a few days. Fourth, misaligned time zones, so "day 10" is counted as day 9 or day 11, and a one-day error becomes a few yuan of wrong billing. Fifth, an invoice with a single line reading "subscription fee 40 yuan," from which the user cannot tell how the 40 yuan was calculated, leaving support to explain it sentence by sentence. Each of these five maps to one or two checklist items, and ticking the checklist is how they get stopped before launch.

One honest sentence to end on: proration is not hard as a technical problem — the hard part is "letting the user work it out for themselves." Anyone can write the formula; the hard part is the one line on the page, the two split lines on the invoice, and the confirmation page before a downgrade. The user is not an accountant and will not read your code — they only look at whether the few numbers on the bill match their intuition. Getting the math right matters, but making it readable matters just as much. Run the checklist, write the confirmation page properly, and then ship.

Views 0Comments 0

Comments (0)

ME
0/1000
Loading comments...
Browse projectsPublish your project

Related articles

Real photograph of a woman holding a credit card and looking puzzled at her laptop
Guide
The Charge Failed, and the Subscriber Quietly Walked Away: The Subscription Dunning Playbook for Vibe Projects

One failed charge, and the system treats the user as gone — involuntary churn, often twenty to forty percent of all churn. This guide builds the way back: telling soft declines from hard ones, retrying on days 2, 4, 8, and 15, three reminder emails that do not read like debt collection, a 7-to-14-day grace period, card-update links in three places, and a graceful goodbye when a save is not possible.

Payments & MonetizationIndie DevelopmentProduct Strategy
Real photograph of a woman shopping online at home on a laptop, holding a credit card
Guide
Added to Cart, Never Checked Out: The Cart and Checkout Playbook for Vibe Projects

Plenty of people add items to the cart; only three in ten actually pay. This guide smooths the road between the two: what belongs in the cart, whether stock is reserved at order time or deducted at payment, how many steps checkout should have, when to mention shipping and tax, how to keep an order alive when payment fails, how many abandoned-cart reminders to send, and what to do differently on a phone.

Payments & MonetizationDesign ExperienceIndie Development
Real photograph of labelled archive boxes stacked on pallets in a warehouse
Guide
How Long Data Lives and Where It Goes: Data Retention for Vibe Projects

Retention is invisible work: you never feel it until it breaks, and fixing it costs ten times more than setting the rules. Five rulers for setting retention periods, a copy-ready retention list, the hot-warm-cold-delete journey, legal holds, old data in backups, and four standards for deleting cleanly.

Data WorkflowsBackend EngineeringIndie Development