Building a pay-as-use billing system on Stripe
Stripe, as we all know, is incredible. It allows complete flexibility to build over it with neatly designed APIs. At ShopSocially, as we are looking to scale up with a lot many customers we felt to need to have a completely automated billing system - the requirements of which sounded pretty complex when we began. Being the application architect, I was responsible for designing the solution and I am proud of the solution which we built - it is elegant and simple. This post attempts to outline the requirements of the system and how we designed the solution. Hopefully, it will be an indication on what you can build on Stripe.
We have two classes of customers whom we need to bill.
- Customers with a credit card on file - These types of customers need to have a monthly base price and overage charges based on their usage for the month.
- Customers on Manual Invoice - These types of customers do not have a credit card and we need to email an invoice against which they make a cheque payment. These customers also need to have a monthly base price and overage charges based on the usage for the month.
For each of these classes of customers we needed the following.
- Charging the credit card.
- Sending them an email with their invoice attached.
- Showing the monthly billing amounts on the billing dashboard with the ability to download the invoice.
- Every customer has a billing start date indicating when to start the billing and recurrent month-on-month thereafter. The billing start date could a date in the future (from when the customer is being signed up) or it could be the day the customer is being singed up.
The solution we came up with is pretty simple actually. The following describes how we used the features already available in Stripe with a little tinkering to suit our requirements. Let’s just focus on the customers with a credit card on file at this moment to understand the solution.
As we had a base price for each customer, we made plans on Stripe to represent the base prices. It is easy this way because if we ever have a customer on a different base price, all we could do is create a new plan on Stripe. As each of our customers will have a different trial period (based on the billing start date), we did not have any trial period on the plans we created in Stripe.
When a customer signs up, we create a customer in our database and we create a Stripe Customer and associate the Stripe Customer with ours in our database. Based on the billing start date, we give a trial period on each customer. Let’s say for example if today is 29th March and the billing start date for a customer is to be 1st April, we associated a trial period of 3 days with the Stripe Customer.
If the billing start is today, we associated a 10 minutes trial period for the stripe customer. We will come to why we needed to do this.
After you subscribe a customer to a plan, Stripe automatically raises invoices for the customers and tries to charge the credit card.
When an invoice is raised, Stripe sends a webhook to one of our URLs with the invoice details and the invoice is kept open for an hour. When we receive the webhook we run our own business logic to find the overage charges that we need to charge for this month and we add this overage charge as an invoice line item to the invoice that was raised and ask Stripe to pay the invoice (make the actual charge). We store the complete invoice details in our database to enable our billing dashboard and letting our customer downloads invoices later.
There are some catches that we figured out.
- The first invoice raised for any customer will always be closed / paid. That means you cannot make any changes to the invoice which essentially means that you cannot add invoice line items.
- The first invoice will be raised as soon as you subscribe the customer to a plan. So,
- If a customer has a trial period associated, the first invoice raised will be a $0 invoice which will be closed.
- If there is no trial period associated with the customer, the first invoice raised will be equal to the plan amount and it will also be closed.
- For customers whose billing start date is in the future, this worked well because they have a positive trial period and so we could just ignore the first invoice raised which will be of $0. The next invoice will be raised on the billing start date with the plan amount.
- For a customer whose billing start date is today, we needed to be able to add invoice items to the first invoice raised and so it cannot be closed. So, we allowed a 10 minutes trial period to such customers. The first closed invoice of $0 will be raised as soon as the customer is subscribed. The next invoice with the plan amount will be raised when the trial period ends. Clever!
Reporting and Creating Invoices
When we get the webhook with the invoice details, we add the overage charges as a line item and ask stripe to charge the invoice. We store all these invoice ids in our database and for generating billing reports and invoices, we could query Stripe with the invoice ids. Again, neat APIs!
This was a bit tricky at first. We did not want to build the complete system ourselves – periodic tasks to check if we need to invoice a customer today, have our database designed to keep the invoice details etc. We were looking to leverage the system we had already built over Stripe.
Finally, we were able to use the entire design we had done for our credit card merchants and leverage Stripe. Here is what we did.
- For manual invoicing customers, we created a Stripe Customer which did not have a credit card. Stripe allows to have customers without a credit card.
- Stripe will not allow to put these customers on a plan with a positive amount as Stripe will not be able to charge them.
- We subscribed these customers to a $0 plan on Stripe. When subscribed to a $0 plan, Stripe raises invoices exactly as in case of a non-zero plan.
- When we get a webhook for an invoice raised in this case, we do add positive line items (in this case, there are two invoice line itesm – the base price for the month as well as overages). But we cannot ask Stripe to charge this invoice, we just tell Stripe to close this invoice.
Rest everything remains the same here – we still have all the invoices with the amounts in Stripe and we do not have to maintain those. This allowed to have a single design for both our classes of customers.
After designing this solution, I am sure that you can easily build any kind of sophistication very easily using Stripe.
If you are having trouble streamlining your billing solutions and need some advice, [I’d be happy to help](mailto: firstname.lastname@example.org). :)
You can discuss this on HackerNews.