Why proration is so hard to get right

Billing

Why proration is so hard to get right

Why proration is so hard to get right

Read time: 7 min

Subscribe to our newsletter
Photo of Arnon Shimoni

Arnon Shimoni

✓ Expert opinion

In theory, proration sounds easy. If something changes, you take the monthly price and divide by the number of days in the billing period, multiply by the days remaining.

For example, imagine a user getting added on a $300/month/user plan on March 16th.

Take $300, divide by 31 days to get the daily price, then multiply by the 16 remaining days, $154.84. Done. But only in the most trivial situations…

Within 3 months of building billing at Pleo, I made Proration a forbidden word. I didn't want to hear about it anymore.

(This was a real sign I had near my desk…)

Proration ends up being a big bunch of policy decisions (we prorate new users but not old ones, we only prorate in full days, etc.). Underneath them sit edge cases in accounting and customer trust problems that no customer support rep can resolve with a formula.

This post is an attempt to walk through those layers. If you're building billing or evaluating a billing system, the goal is to save you weeks of fighting over this.

Layer 1: the denominator changes

Let's start with the most basic of proration. $300 divided by how many days left?

Calendar days in the month give you 28, 29, 30, or 31 depending on the month, as you know. Stripe uses this approach.

However, you may want a fixed 30-day period instead, because that's what some other billing systems use.

The per-invoice difference is small but across thousands of customers over a year, it adds up: your February invoices are 7-10% higher per day than your March invoices for the same plan, on the same tier, for the same customer.

(Did you know there are dozens of Telegram groups that tell you how to make the most of some of the B2C subscriptions with regards to this? This is called friendly fraud!)

Let me layer in another thing. Time zones. My second least-favourite concept.

Because when does the prorated period begin? At Pleo, we used UTC but a customer in Eastern Europe adding a user at 1am on Tuesday (this really happened) would see a Monday start date on their invoice and this caused some issues.

Mostly, very few customers complained about it (at least as far as I know), but it's the kind of thing that can really confuse customer support. And the invoices were really hard to decipher when we used Stripe.

So even before you get to anything complicated, the "simple" proration formula has at least two ambiguities that produce different invoice amounts.

It's fine to pick one convention and move forward, but you will face these problems and you need to have answers for why you picked something.

Layer 2: mid-cycle plan changes

The previous layer was easy… Now, let's imagine a customer changing plans mid-cycle.

Say a customer is on your $100/month plan, and you're now 10 days into the 30-day billing period. When they upgrade to the $200/month plan. You now calculate:

  • Unused credit from the old plan: $100 x 20/30 = $66.67

  • Prorated charge for the new plan: $200 x 20/30 = $133.33

  • Amount to bill: $66.67

Right? Easy enough. But this isn't how all of it works in many real scenarios:

  1. Some companies net the credit against the new charge immediately (that $66.67 net), which is a fairly clean customer experience but means your invoice for this period has three line items where it used to have one. And the amount of support requests you field on this can be overwhelming. We'd have dozens of these every day at Pleo.

  2. You can apply the credit to the next invoice instead, which simplifies the current invoice but means the customer pays more now and less later, and then you are carrying a credit liability. Some customers hate this too.

  3. You can charge the full $200 and start a new billing cycle from the upgrade date, which is the simplest for your systems but means the customer's billing anniversary shifts every time they change plans. If they upgrade twice in a quarter, their billing date has moved twice, and they have to file these as expenses, which can be annoying.

At Pleo, we had an additional wrinkle. Some plans would prorate, some wouldn't. I don't even want to tell you why that is… But the per-seat pricing we had also meant we had to track individual users within a single company's subscription. It was normal for some of our larger customers to add dozens of users in a day and deactivate a dozen others.

Most billing systems including Stripe think in subscriptions, not in individual seat occupancy over time. What we had to do is hack around Stripe, and build a second billing system that that tracked per-user activation dates asynchronously, compute the delta each billing cycle, and fed the result into Stripe as a single line item because otherwise it'd result in a 15 page invoice.

This was a real invoice with ±15 pages of prorations added

(This was a real invoice with ±15 pages of prorations added)

We did this to reduce the support requests. So the customer saw "Pro plan: 47 users, Pro-rata adjustments: -$312.50" instead of the whole math.

Layer 3: the "direction" problem you need to decide on

For some of our plans, we prorated in one direction only. Adding a user mid-cycle triggered an immediate prorated charge. Removing a user mid-cycle did nothing until the next renewal. This was somewhat to prevent fraud, but also because we wanted to give customers time to actually make the change.

When customers notice that adding a seat charges them immediately, prorated to the day but removing a seat does nothing until renewal - some don't mind, some argue.

It also made sense for us operationally too because issuing a micro-refund every time an admin deactivates an employee's expense card becomes this awful reconciliation puzzle that finance hates and rightfully so.

The operational cost of computing, issuing, and tracking those credits exceeds their value in most cases.

(This was a real slide explaining proration)

Layer 3.5: Let's add annual and semi-annual plans and tiers

Until now we thought about things in months. What happens in longer periods?

You typically don't want to wait 6 or 12 months to issue a correction - so you perform "true ups" a bit more regularly to make sure you don't accumulate too much operational mess.

(again, this is a real slide I used to explain concepts).

So what happens if a customer then also moves on to the next discount tier? More fun math!

That's the thing about proration… It's not "just math". You have to think about all of the policies, how they are perceived by customers, how customer support can answer questions about it, and how it affects your product. I am certain most if not all companies make the policy decision implicitly, by choosing whatever their billing system defaults to, without realizing they made a choice.

Layer 4: credits makes it even harder

Everything above assumes seat-based or flat-rate subscriptions. But we're in a post-seat world mostly, and credits and usage-based models add a second dimension on top of everything else and this is where I've watched teams burn months of work.

Say you sell 1,000 credits per month for $100. Every time you get an invoice, you get a new set of credits. But if a customer wants to upgrade to a plan with more credits mid-cycle, you need to figure out:

Do they get a prorated amount of credits (e.g., 500 for the remaining half-month) or the full 1,000?

  1. If prorated, when do those credits expire:

    1. at the end of the current billing cycle?

    2. a full month from the grant date?

  2. If not prorated, meaning they get the full 1,000, do you:

    1. charge the full fee and reset their cycle?

    2. charge $50 for the prorated period and let the 1,000 credits expire at the original cycle boundary?

Each of these variations is fine but you need to consider them. For example:

  1. Prorated credits with cycle-end expiry: you might grant 500 credits for $50 that expire in 4 days. Bad customer experience.

  2. Full credits at full price with a cycle reset: the customer loses whatever was left of their existing grant, unless you add a rollover policy (which introduces its own accounting complexity).

  3. Full credits at prorated price: generous, but if you granted 1,000 credits for $50 and only 300 get used, your per-credit revenue recognition is based on $50/1,000, not $100/1,000.


And this is just one credit type! Lots of Solvimon customers now have multiple credit types, multiple wallets, and different exchange rates, tiered pricing where the per-credit cost drops at volume, committed-use discounts spanning multiple billing periods... the combinatorial space grows so fast.

So, sounds like proration is necessary. What's there to hate?

The reason I'm writing this again is that proration touches every layer of a billing system simultaneously: the subscription engine, the invoice generator, the revenue recognition pipeline, the customer portal, entitlements, wallets, etc.

I have burned weeks of my life hacking this around Stripe in a second billing system because it wasn't supported natively. You can avoid my mistakes and do better.

A change in proration policy means changes in all four plus a bunch of change management because product teams experiment, finance teams adjust, and customers negotiate.

That's one of the reasons that we've built Solvimon with this configurability. The billing system you use needs to know (at the subscription level) whether a customer is on calendar billing or anniversary billing, and if changes apply immediately, at the end of the day, or maybe at the next billing cycle only. It also needs to know if credits are granted at cycle start or on demand with their own unique expiry windows.

Again, I highly recommend buying a system that handles the proration for you and not dealing with this yourself. If you need to change policies, you shouldn't have to rewrite all of your logic. That's what Solvimon is there for.

Ready for billing v2?

Solvimon is monetization infrastructure for companies that have outgrown billing v1. One system, entire lifecycle, built by the team that did this at Adyen.