DEV Community

Cover image for How to track and bill real-time usage metrics in cloud services
Flexprice
Flexprice

Posted on Originally published at flexprice.io

How to track and bill real-time usage metrics in cloud services

Every API call, GPU minute, and gigabyte stored in a cloud product is a unit of value and a unit of accounting. Flat subscriptions let you ignore the second part. Usage-based pricing does not: the events have to be captured as they happen, aggregated with the right function, and converted into an invoice the customer believes.

The gap between "we log requests" and "we can defend this invoice" is where most teams discover they've built a data platform by accident.

What does real-time usage billing actually require?

It requires a pipeline with six stages: a defined billable event, an idempotent ingestion path, an aggregation layer that supports more than summing, a mapping from aggregated usage to prices or credits, invoice generation that draws down entitlements, and a customer-facing view of the meter. Skipping any stage moves the work somewhere worse, usually into a reconciliation script at month-end.

Why the real-time part matters

Customers on consumption pricing carry the spend risk. That changes what they expect from you. They want to see the meter while it runs, get warned before a threshold, and cap spend rather than discover it.

Batch billing breaks all three. A usage dashboard that updates nightly tells a customer what they spent yesterday, which is useless for controlling what they spend today. A quota that's evaluated in a nightly job can be blown through by lunchtime. And a surprise invoice is the most reliable churn trigger in consumption pricing.

Real-time here means the meter is current enough that a customer can act on it. That's a latency requirement on an aggregation path, not a marketing adjective.

The failure modes

Event volume. Cloud and AI workloads produce millions of micro-events a day. Each one has to be logged, attributed to a customer, and counted exactly once.

Aggregation variety. Some metrics sum. Some are unique counts, like monthly active users. Some take the latest value, like concurrent connections. Some need a formula, like tokens weighted by model. A system that only sums forces the rest into application code.

Mapping to price. Prepaid credits, entitlements, and tiers all sit between a quantity and a charge. This is where improvised systems usually break, because each pricing construct gets added as a special case in a different place.

Reconciliation. Events arrive late, arrive twice, or don't arrive. Without idempotency and a retry story, invoices drift and no one can say by how much.

Change. You charge per API call now. Next quarter it's per token, or a hybrid of both with a credit wallet in front. Pricing logic hardcoded into services means every pricing change is a deploy across every service that emits usage.

Most teams meet these with a few scripts and a usage add-on bolted onto a subscription tool. Those patches quietly become the revenue engine.

The pipeline, stage by stage

1. Define the billable event

Decide what counts, and attach enough metadata to bill and to audit: a customer identifier, a timestamp, the unit, and any dimension you might want to price or group by later.

{
  "event_name": "gpu.seconds",
  "external_customer_id": "cust_123",
  "properties": {
    "seconds": 420,
    "instance_type": "a100",
    "region": "us-east-1"
  },
  "event_id": "evt_7c31bd",
  "timestamp": "2025-10-07T11:04:12.001Z",
  "source": "scheduler"
}
Enter fullscreen mode Exit fullscreen mode

Adding a dimension later is cheap. Backfilling one you didn't record is not, because the events are gone. Err toward recording the dimension.

2. Ingest in real time, idempotently

Events flow from your services into the pipeline through direct API calls, an event stream, or a collector. Whatever the transport, the ingestion contract has to be idempotent. A client-supplied event_id is the usual mechanism: the same identifier arriving twice resolves to one billable event.

For high-frequency emitters, batch rather than sending per event.

curl --request POST \
  --url https://api.cloud.flexprice.io/v1/events/bulk \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <your_api_key>' \
  --data '{
    "events": [
      { "event_name": "gpu.seconds", "external_customer_id": "cust_123", "event_id": "evt_7c31bd", "properties": { "seconds": 420 } },
      { "event_name": "gpu.seconds", "external_customer_id": "cust_456", "event_id": "evt_7c31be", "properties": { "seconds": 95 } }
    ]
  }'
Enter fullscreen mode Exit fullscreen mode

The bulk endpoint accepts up to 1,000 events per request. That host serves the India region; https://us.api.flexprice.io/v1 serves the US. The API key goes in the x-api-key header on both.

If usage already flows through Kafka, a webhook, a database, or files, a collector avoids instrumenting emitters a second time. Flexprice documents that path in Collectors, which is built on Bento and handles retries and delivery guarantees for you.

3. Aggregate

Pick the function per metric rather than per system.

  • Sum for total requests or compute seconds in a period.
  • Count unique for distinct users or agents.
  • Latest for concurrent sessions or seat count.
  • Max for peak usage in the period.
  • Sum with multiplier when a summed property needs scaling by a rate, such as tokens weighted by model.
  • Weighted sum for time-proportional totals, such as capacity held over part of a period.

These belong in configuration on the metered feature, not in a query someone wrote once. The aggregation reference lists what each function does to the event stream.

4. Map usage to pricing

Aggregated quantity becomes a charge through tiers, entitlements, or credits.

Credit models are common in AI products because they decouple the price the customer sees from the unit you meter. A conversion rate turns metered units into credits, and grants add balance on a recurring or one-time basis.

Flexprice models this with wallets. A wallet can be scoped to recurring charges, usage charges, or both, and credits deduct automatically before the default payment method is charged. Prepaid and promotional credits covers how that scoping works.

5. Generate invoices

Usage flows into invoice line items with credits deducted as they're consumed rather than reconciled afterwards. Calendar billing periods are easier to operate than per-customer anniversary cycles, because every customer's period closes on the same boundary and a late event has one obvious home.

Invoices should be previewable before they finalize. A number you can inspect on the 28th is cheaper than a correction issued on the 3rd.

6. Expose the meter to customers

Live usage views, threshold alerts, and spend caps are the customer-facing half of the pipeline, and they're what stop billing disputes before they start.

Alerts need suppression logic. A customer who receives six notifications about the same threshold stops reading the seventh, including the one that matters.

One detail that catches teams out: a credit wallet has two balances, and they answer different questions. The settled balance only moves when a transaction completes, which makes it the right number for accounting and reconciliation. The ongoing balance subtracts in-period usage and pending invoices continuously, which makes it the right number for entitlement checks, low-balance alerts, and auto top-up. Reading the wrong one is how a low-balance alert fires late. Wallet balance types spells out the difference.

What this looks like as infrastructure

Flexprice is enterprise-grade, open source usage based billing infrastructure for AI and SaaS companies. It can be deployed in your own VPC, on-prem, or on Flexprice's managed cloud. Flexprice offers three deployment options, and all three run the same engine.

Against the pipeline above: ingestion accepts single or bulk events with duplicate handling, aggregation strategies are configuration on a metered feature, wallets handle credit conversion and scoping across recurring and usage charges, invoices assemble from billable records with credit drawdown applied, and usage is queryable for customer-facing views. Because Flexprice is open source and self-hostable, usage and revenue data can stay entirely inside your own infrastructure and never reach a vendor's cloud.

The decision worth making early is not which vendor to use. It's whether pricing logic lives in your services or in a layer you can change without a deploy. The second option stays cheap as pricing evolves.

Start with the architecture overview if you want to see the components before running anything.

Top comments (0)