Billing is a nightmare, and if I had one piece of advice for people building a pay-for-what-you-use system like most SaaS, it's this:
DO NOT bill against your business logic entities. They change, and doing a COUNT at the end of the month won't catch all things which changed or which cost you money during the month. Instead, figure out what you bill for and and when you do that thing, record a row in a DB or into a steam of that "billable event".
Reconciling billable events is much easier to do, and it's tolerant of all the weird edge cases (such as a support person hard deleting data when they should soft delete, which would otherwise throw off your end of month counts).
There's a reason AWS (in general) can produce a log of everything you did which cost you money. It's painful, but it's less painful than the alternative.
Sound advice. Anything to do with accounting, you’ll probably want to treat as an append-only log of events. (Note, you can also use event-sourcing and have your domain entities _be_ events, in a billing bounded context that might make sense. Not usually the first approach I’d recommend though.)
On a similar note, make sure you think about bitemporality as well. In other words, “effective_at” vs. “”created_at”. You might learn that due to a bug, you didn’t record a billable event, and you need to insert it into the history (say, to put it in the correct billing period). But setting the “created_at” in the past brings a bunch of issues; it’s confusing and you’ll soon hit issues where lying about created-time trips you up. (Migrations, reasoning about what version of the code applied what events, etc).
If you squint, this is similar to how e-commerce billing is done. You have stock keeping units that represent the logical item being sold, and every transaction clones that row as part of the order record.
This way, if the price changes, the item description changes, the images on the item change, etc, you can still have a record of what was actually sold and how much to refund a return etc.
And depending on how you do it, it's not as hard as it sounds - for example, the first minute of "cloud server V1" can get a row in the db, and each "period" that row gets updated with the current minutes.
Or you can log them into tables that get processed into other invoice tables.
This also lets you keep grandfathered customers around as long as you want.
Couldn't agree more!
I do think the best way to do it is to log ingested events in a db, and decide which way you want to aggregate a billable feature at a defined billable period. This way lets you (i) keep track of everything, (ii) invoice complex behaviors and (iii) provide great granularity to your customers inside a final invoice.
DO NOT bill against your business logic entities. They change, and doing a COUNT at the end of the month won't catch all things which changed or which cost you money during the month. Instead, figure out what you bill for and and when you do that thing, record a row in a DB or into a steam of that "billable event".
Reconciling billable events is much easier to do, and it's tolerant of all the weird edge cases (such as a support person hard deleting data when they should soft delete, which would otherwise throw off your end of month counts).
There's a reason AWS (in general) can produce a log of everything you did which cost you money. It's painful, but it's less painful than the alternative.