The 4 biggest problems with homemade billing systems

September 22, 2022
Product & Billing

This article was written by Vincent Pochet, Senior Backend Developer at Lago.


In 2017, I joined Qonto, a B2B neobank in the making (now worth more than $5B), and got involved in the design of the billing system.

As the company was scaling from cradle to unicorn, we faced many billing challenges: monthly and yearly plans, “pay-as-you-go” components (percentage on FX transfers, fixed fee on ATM withdrawals, user seats, printed cards, etc.), creation of invoices at scale, taxes, accounting… It was a never-ending nightmare.

Now, when someone asks for advice about their billing system, my answer is clear: DO NOT build it yourself.

It may look like an interesting project at the beginning, but you’ll soon regret it. And believe me, it only gets worse. As an engineer, if you’re told it’s a “two-month project”, run as far as you can before it’s too late and you become the “billing guy”!

#1 Pricing changes all the time and billing needs to follow

After creating the first billing engine of Qonto, we were pretty happy with what we had built. We could ingest millions of events every week, our calculations were correct, we could generate sequential invoices, we were able to apply marketing coupons and we managed to debit our internal ledger. Everything was going well!

But then…

The marketing team came up with a new yearly plan

Billing was performed on a monthly basis. At the end of each month, we had to query the database to compute fees and display them as billing items on the invoices. Customers were able to switch from a “monthly_solo” plan to a “monthly_premium” plan (and vice versa), and the upgrade/downgrade logic was working well (although it had been difficult to implement).

When the marketing team devised a new yearly plan to secure revenue for the next 12 months, I started to freak out: the entire billing logic was based on monthly boundaries. It took us two months to modify this logic. The hardest part was that the subscription fee had to be billed in advance, at the beginning of the annual period, but the overage related to usage-based features still had to be billed on a monthly basis.

The finance team asked to switch from anniversary to calendar dates

At the time, customers were billed based on the anniversary date of their contract. For instance, if a customer had signed up for a monthly plan on March 16th, they were billed on the 16th of each month.

One day, the finance team requested a meeting with the engineering team and the CFO said:

“It would be easier for everyone if we switched from anniversary dates to calendar dates for subscriptions. Right now it’s a mess from an accounting perspective, so let’s bill everyone at the beginning of the calendar period.”

In other words, they wanted to switch from this…

Anniversary billing periods

To this...

Calendar billing periods

100,000 customers were affected by this migration. The accounting mess turned into an engineering nightmare, resulting in a three-month project.

Implementing billing logics takes time and things get incredibly complicated over time. Other typical organic changes include (but are not limited to):

• New features to be added to the pricing;
• New country launch, with a different pricing;
• New business line, when you start selling a white-label version of your product for instance;
• Changes in tax legislation; and
• Custom plans for “Enterprise” customers.

#2 Your billing system needs to scale with your user base

A home-made billing system is not scalable if you don’t maintain it. At Qonto, our billing database contained millions of rows. This database was linked to our internal ledger, which was used to deduct fees from our customers’ accounts. Processing high volumes of events is hard, and when something breaks, you need to check whether past events need to be computed again (but you can’t afford to ingest the same event twice).

Generating invoices is also an important task. It’s not hard to create PDF files with line items on it. We used a library called Gotenberg to display backend aggregations on a beautiful HTML template. However, it’s hard to process fees and generate millions of invoices at the same time. Your backend queries and aggregates millions of rows asynchronously, and the calculation must be correct for each customer.

The more complex the pricing, the more complicated the calculations. And the more customers you have, the more IT resources you need.

#3 Grandfathering causes headaches

A few weeks ago, we interviewed Nicolas Dessaigne, founder of Algolia and Group Partner at YC. He told us about their terrible experience with pricing and billing. After a series of “minor” changes to their price plans, they decided a few months ago to adopt a full usage-based pricing model and had to rebuild the entire billing logic.

As most customers had signed long-term contracts based on existing plans, they had to exclude them from the migration. This is called “grandfathering”. In this situation, engineers must not only implement new billing rules, but they also need to maintain the old logic for grandfathered plans.

In 2013, the pricing of Algolia was like this...

The pricing of Algolia in 2013

Then in 2015 it was like this...

The pricing of Algolia in 2015

And here is the 2022 update!

The pricing of Algolia in 2022

#4 You must be prepared to staff an entire team

Billing is never considered an expertise. It’s perceived as a background task and not as a prestigious project that engineers will fight for (they may even leave if they’re forced to work on it for a long time).

However, sooner or later, billing will be a full-time job for at least one engineer. Because of pricing changes, scalability challenges and grandfathered plans, complexity increases and so does the workload. Billing is built around your company’s product, it’s a living organism, not a feature.

At Qonto, the billing project was supposed to be completed by a single backend engineer in only two months. One year later, two backend engineers were still working on it full time.

Then the team of two backend engineers grew into a team of 20 people, including product managers, backend engineers and frontend engineers as well. Hiring, onboarding and retaining people to take care of our billing system was a constant challenge. They would have preferred to work on our core product, and our management team also wanted to downsize the team.

We considered implementing an off-the-shelf billing solution but there was nothing flexible enough and the switching costs were too high. Algolia also tried to migrate to Zuora before backing out and rebuilding their billing system for the fourth time. This is a decision you have to make in the early days, otherwise, at some point, your billing will be too complex and won’t fit any software product.

I left Qonto in March 2021 and I still get phone calls from engineers currently working there and struggling with billing. They learned these four lessons the hard way. They now know what it costs to build a homemade billing system.

Automate billing with our open-source API