Subscription Proration Calculation: Edge Cases Every Engineering Team Gets Wrong
A deep-dive into subscription proration calculation — the formulas, the common edge cases, and how to handle mid-cycle plan changes without billing errors.
Proration looks simple on the surface: a customer upgrades mid-cycle, so they pay for the remaining days at the new price. The math is a few lines. Then you hit production, and you discover that February has 28 days, a customer upgraded and immediately downgraded, two plan changes happened in the same request, and your MRR dashboard shows numbers that do not reconcile with Stripe. Proration is where billing systems get complicated fast.
The Standard Subscription Proration Formula
The baseline calculation for a mid-cycle plan change:
credit = old_plan_price x (days_remaining / days_in_period)
charge = new_plan_price x (days_remaining / days_in_period)
net_adjustment = charge - credit
If a customer on a $60/month plan upgrades to a $120/month plan on day 11 of a 30-day billing period, there are 19 days remaining. The credit is $60 × (19/30) = $38.00. The charge is $120 × (19/30) = $76.00. The net charge at upgrade time is $38.00.
At the next renewal, the customer is billed the full $120.
This formula works for the clean case. The edge cases are where systems fail.
Edge Case 1: February and Variable Month Lengths
Proration requires knowing the number of days in the billing period. If you hardcode 30, you will overbill customers in February and underbill in months with 31 days.
The correct approach is to compute days_in_period from the actual period start and end timestamps for that customer's billing cycle. Do not assume. A subscription anchored to January 31st will have a different days_in_period in February than in March.
Edge Case 2: The Change Day Boundary
Which plan does the customer pay for on the day they change plans — the old one or the new one? There is no universal right answer, but you must pick a convention and apply it consistently.
Most billing systems treat the upgrade as effective from the start of the change day. If a customer upgrades on day 11, days 1–10 are billed at the old rate and days 11–30 at the new rate. That means days_remaining = 20, not 19.
Whatever convention you choose, codify it, document it, communicate it to customers, and test it against your billing provider's behavior. Stripe's default convention may differ from your product's stated policy, and a mismatch will generate customer-facing billing inconsistencies.
Edge Case 3: Rapid Sequential Plan Changes
A customer upgrades to the Pro plan, then downgrades to the Starter plan three minutes later. A naive system processes both changes independently and generates double the prorations.
Handle this with a transaction model: accumulate all plan changes for a billing period, then compute a single net adjustment. If the customer ends the period on Starter, the net credit and charge calculations should reference the original plan and the final plan for the period — not every intermediate state.
At minimum, put a short debounce window (30 to 60 seconds) on plan change processing so that accidental double-clicks do not generate duplicate proration events.
Edge Case 4: Timezone Mismatch
A customer in Singapore changes their plan at 11:45 PM their local time. Your server records the change in UTC — which is the following day. Your accounting system uses Pacific time, which is yet another day. Three different systems, three different dates for the same event.
Set a canonical timezone for all billing events (UTC is the right answer) and never deviate from it. Store all billing timestamps in UTC. Calculate days_remaining from UTC timestamps. Display times to customers in their local timezone, but perform all calculations in UTC.
Edge Case 5: Mid-Cycle Changes with Tax Implications
Each proration event is a distinct taxable event. A credit for unused days on the old plan and a charge for remaining days on the new plan each carry their own tax calculation — potentially at different rates if the customer's tax status or jurisdiction changed.
Billing systems that apply a single tax rate to the net proration adjustment will generate incorrect tax amounts. Calculate tax on each component separately.
Edge Case 6: Multi-Currency Subscriptions
If a customer subscribed in EUR but your pricing changed since their original subscription, a mid-cycle upgrade needs to use the exchange rate at the time of the proration event — not the rate at the original subscription date.
For teams running multi-currency billing, store the currency and exchange rate alongside every billing event. Do not recalculate at a later exchange rate when generating invoices.
Edge Case 7: Prorations and MRR Reporting
Mid-cycle proration charges and credits will distort your MRR if your analytics tool treats them as revenue events rather than billing adjustments.
An upgrade proration generates a one-time charge that is not recurring revenue — it is a catch-up payment for the remainder of the current period. The true MRR change from an upgrade is the difference in plan price at renewal, not the proration amount charged today.
Configure your analytics tools to exclude proration line items from MRR calculations, or to categorize them explicitly as period adjustments.
Testing Your Proration Logic
Before shipping proration changes, run these test scenarios:
- Upgrade on day 1 of the billing period (charge is almost the full plan difference)
- Upgrade on the last day of the billing period (charge is near zero)
- Downgrade mid-cycle (a credit is owed — handle the refund path)
- February billing period (28 days)
- Upgrade then downgrade within the same minute
- Timezone boundary: change at 23:59 UTC
If your system handles all six correctly, you are covering the majority of real-world failure modes.
Proration logic that seems simple becomes a reliability issue at scale. If you are building or auditing a subscription billing system, Clixo can help you get the edge cases right before they become customer escalations.