Btw how do you handle idempotency with time series? I think replays and least-once delivery in distributed systems can be challenging around usage collection if you don't have a key to deduplicate by.
I'm fond of SQL, but I'd be ok with some other way to express "aggregate my usage into an invoice".
Continuously aggregating smaller windows and sending them off is roughly how we send usage to Stripe right now (which, let's be clear, is not working for us AT ALL). We've resigned ourselves to having to do the same thing if we want to use a billing SaaS, but I don't love it.
A pure SaaS model for billing doesn’t do much more for you at then end of the day other than to apply billing ratings and generate an invoice (which Stripe can and is doing for you already).
I’d love to learn more about what you’d like to do with Stripe and how you are handling entitlements, plan versioning, etc
* Lago - https://www.getlago.com
* Octane - https://www.getoctane.io
* Metronome - https://metronome.com
We're a hosting platform for AI Agents and in practice that means keeping track of a stream of usage events across agents, microservices (equivalent of Fly's VMs), and third-party services (OpenAI, Eleven Labs, D-ID, Pinecone, Replicated, etc) that roll up into an itemized consumption bill.
It might be this is just a super-niche billing situation, but we also haven't yet found an open-source solution that fits. Fully agree that a query layer atop a time-series database is the style of product that we're craving.
Metronome comes very close, but since it's not open source we're hesitant to make the jump before it's a perfect fit.
Congrats on the launch! It looks very cool!
We’re working hard to make it easy to send data to us (e.g. just drop it in S3). Granted, this isn’t ideal per your note of already throwing it into VictoriaMetrics, but we’re finding that often times companies don’t have the optimized in-house infra to run the sort of usage metric queries to go from raw events -> invoice, especially when you get to >100k events/second scale. It often makes sense for us to control the storage (and sharding) format — and we can bring those costs down over time.
Given the usage events and the SQL queries over them, we then focus a bunch on making the core billing interactions work well, do invoice delivery for you (example: https://invoices.withorb.com/view?token=IlJwOVRSdWhEQ3NiRUVH...), and make it easy for you to do financial reporting & rev-rec (honestly, this is its own rabbithole — but we find it’s extremely outside the core competency of eng/product teams)
We track everything as metrics, then hook up functions to read from the TSDB each billing period. How it works:
- One Inngest function runs each billing period (scheduled), and "fans out" by creating an event for each user we want to charge.
- A billing function reacts to these individual user events, queries metrics, queries our plans, and then generates a stripe invoice
- This is then charged by stripe.
- We have other functions that respond to other billing events and do dunning like flows.
We only have to focus on the small amount of billing code required. We don't have to handle scheduling, state, retries, or the event flows — that's built into Inngest.
I'd really like to make this more robust. We had to put in the work on emails, billing, and dunning, even if it is simple function code. It would be nice to have someone "productize" this. I feel your pain.
In general, it definitely makes sense to read from our own metrics stores to charge for our products. Very much agree with everything you've said. There's not the most joy in billing.
I'd have said if you want to gracefully deal with a system that loses events, a timer-based system can ensure the errors from lost events will always be in your customer's favour.
The last thing you'd want is to start the taximeter with a start-pod event, then lose the stop-pod event and end up billing the customer for nothing, forever.
We run millions of tiny VMs. Each gets billed on a number of dimensions: egress, runtime (per cpu / memory combo), storage / io. We also have other metered services: ssl certificates, IP addresses, etc.
The thing is, we _already_ have metrics for everything we want to bill. They're in a time series DB (VictoriaMetrics, in this case). Sending a shit ton of events to yet-another-system is complicated and brittle.
Your k8s pods example is a good source of my hives. Anything that runs on a timer to fire off events is going to get bogged down and lose data at our scale. And we're not very big!
This is a somewhat solved problem for metrics stacks. It's relatively straightforward to scale metrics scrapes. And once we have that infra, it's pretty easy to just start pushing "events" to it when events become useful. We don't end up needing Kafka and its complexity.
My dream for billing is: a query layer on top of a time series database that takes data I already have and turns it into invoices.
One thing about your post that struck me – the last mile to billing and reporting is the thing we're most interesting in buying. It's less specialized. There also aren't any products out there that have really figured this out, I don't think (we've evaluated pretty much all of them).
Usage tracking and reporting is a thing we're ok building, because it's core to our product.