Commet
  • Pricing
Log InTry out

Usage Event Ingestion Without Billing Drift

How Commet turns product events into billable usage with clear event codes, idempotent tracking, and batch ingestion that scales.

G
Guido Irigoyen·@guidooirigoyen·March 20, 2026
Blog

Usage-based billing fails quietly.

Not at checkout. Not on the pricing page. Not when the plan is created.

It fails when product activity and billable activity drift apart.

An event gets sent twice. A metric name stops matching the billing model. A queue retries without idempotency. A developer thinks they are tracking "usage" when they are really just logging product analytics.

That is how teams end up with billing systems they do not trust.

At Commet, usage ingestion is built around a simpler rule:

Track the product event that should create billable consumption, and make that mapping explicit.

Billing events are not analytics events

This distinction matters more than most teams think.

Analytics events answer questions like:

  • which feature is popular?
  • where do users drop off?
  • what did the user click?

Billing events answer a different question:

What happened that should affect what this customer owes or has consumed?

Those are not interchangeable systems.

If your billing logic depends on analytics-style event streams with vague names and inconsistent semantics, you are going to create reconciliation work later.

The Commet model: feature event code -> usage event -> billing

In Commet, every metered feature has an event code.

That code is the contract between your product and your billing model.

Examples:

  • api_calls
  • storage_gb
  • emails_sent
  • compute_minutes

When your application records usage against that code, Commet aggregates it for billing over the subscription period.

That gives you a direct path from product action to billable usage without inventing a second translation layer.

Track a single event when the product action happens

If one user action maps cleanly to one billable event, the simplest thing is usually the right thing.

await commet.usage.track({
  externalId: "user_123",
  feature: "api_calls",
  value: 1,
  idempotencyKey: "req_abc123",
})

This is the core idea:

  • identify the customer
  • identify the billable feature
  • send the quantity consumed
  • make retries safe

That is enough to keep the billing model explicit and inspectable.

Batch when throughput matters

When volume increases, you do not want event ingestion to become a bottleneck.

Commet supports batch tracking for the same reason product teams batch other write-heavy operations: better efficiency, less overhead, simpler ingestion pipelines.

await commet.usage.trackBatch({
  events: [
    { externalId: "user_123", feature: "api_calls", value: 1 },
    { externalId: "user_456", feature: "api_calls", value: 3 },
    { externalId: "user_123", feature: "storage_gb", value: 0.5 },
  ],
})

If your product generates consumption in bursts, or you are syncing from internal jobs rather than direct user requests, batching is usually the right operational choice.

Idempotency is not optional

If you only remember one thing about usage ingestion, make it this:

Retries are normal. Duplicate billing is not.

Networks fail. Workers retry. Queues redeliver. Background jobs get resumed.

Without idempotency, every one of those normal system behaviors can become a billing defect.

That is why Commet supports idempotencyKey on usage tracking.

await commet.usage.track({
  externalId: "user_123",
  feature: "api_calls",
  value: 1,
  idempotencyKey: "job_7845_event_12",
})

This gives you a reliable way to tell the billing system: "If this exact event already landed, do not count it twice."

That is the difference between a system you hope is correct and a system you can operate with confidence.

Event naming is product design

Bad event names usually signal bad billing design.

These are useful:

  • api_calls
  • storage_gb
  • emails_sent
  • compute_minutes

These are not:

  • metric
  • usage
  • feature1
  • event_x

Event codes live in code and in your billing model. If they are vague, every downstream system gets harder to reason about.

Good naming does two things:

  • it makes implementation easier for developers
  • it makes the billing model easier to audit later
Commet metered feature configuration showing an event code and usage settings.

A good ingestion system removes reconciliation work

The point of usage tracking is not just to capture data.

It is to avoid the operational tax of asking:

  • did we track the right thing?
  • did we track it once?
  • does the pricing model still match the product?
  • why does the invoice not match what support sees?

When the event contract is explicit, those questions get easier.

That is why Commet keeps the model narrow:

  • billable features have event codes
  • your app reports consumption against those codes
  • Commet aggregates usage for billing

No fake abstraction. No hidden translation layer. No need to rebuild billing logic inside your analytics stack.

The practical standard

If you are building a usage-based product, your ingestion setup should meet a simple standard:

  • billable events are named clearly
  • retries are idempotent
  • batching exists when you need it
  • the customer mapping is explicit
  • the billing model matches the product behavior

That should be normal infrastructure, not custom billing archaeology.

Read the Track Usage documentation, review Consumption Models, explore the usage-based template, or try Commet in sandbox.

Developers

  • Documentation
  • Templates
  • GitHub

Resources

  • Blog
  • Changelog
  • Pricing

AI

  • Agents
  • MCP Server
  • Agent Skills
  • Claude Code
  • Codex

Learn

  • Guides
  • Glossary
  • Solutions
  • Billing for AI Models
  • Comparison

Company

  • About
  • Open Source
  • Terms
  • Privacy
XLinkedInGitHub