How metering works

CLIMeter records usage events as your tools execute and transforms them into billing data. Here is the full lifecycle of a metering event, from function call to invoice line item.

Event lifecycle

  1. Tool function called
         │
         ▼
  2. @meter.track() intercepts the call
         │
         ├── Extract: tool_id, timestamp, caller API key
         ├── Validate: API key (cached, no round-trip)
         │
         ▼
  3. Tool function executes (your code)
         │
         ▼
  4. Function returns (success) or raises (error)
         │
         ▼
  5. SDK creates Event object
         │
         ├── Fields: tool_id, price_usd, duration_ms, success, metadata
         ├── Tags: env, SDK version, caller_id
         │
         ▼
  6. Event added to in-memory buffer
         │
         ▼
  7. Background flush thread sends batch to CLIMeter API
         │
         ├── POST /v1/events
         ├── Authorization: Bearer <token>
         ├── Retry on 5xx (3 attempts, exponential backoff)
         │
         ▼
  8. CLIMeter stores event, increments usage counter
         │
         ▼
  9. CLIMeter invoices consumer, pays builder via Stripe Connect

Buffering

Events are never sent synchronously during your function call. Instead, the SDK buffers events in memory and flushes them in a background thread. This means:

  • Zero network overhead during your function execution
  • Events are batched for efficiency (up to 50 per request by default)
  • Temporary network issues do not affect your tool performance
SettingDefaultDescription
batch_size50Flush when buffer reaches this many events
flush_interval10sFlush regardless of buffer size after this interval
max_buffer1000Maximum events in memory; oldest dropped if exceeded
retry_count3Retry failed flushes this many times
retry_backoff1s, 2s, 4sExponential backoff between retries

Fire-and-forget model

By default, CLIMeter uses a fire-and-forget model for the SDK. When your function returns, the event is queued — not sent. This means your function latency is never affected by network conditions between your tool and the CLIMeter API.

CLI tools
For short-lived CLI processes, call meter.flush() or use atexit.register(meter.flush) to ensure all events are sent before the process exits.

Deduplication

CLIMeter deduplicates events using an idempotency key. If the same event is submitted twice (e.g., due to a retry), only one is recorded. This prevents double-billing.

Python
import uuid

# Provide your own idempotency key
event_id = meter.record(
    "my-tool",
    duration_ms=142,
    idempotency_key=f"call_{request_id}",  # stable, unique per invocation
)

# The SDK auto-generates idempotency keys for @meter.track() decorators
# based on: tool_id + timestamp + process_id + call_count

Delivery guarantees

ScenarioBehavior
Network blipRetried 3x automatically; events queued in buffer
CLIMeter API downEvents buffered in memory; flushed when API recovers
Process crashIn-memory buffer is lost; use flush() before exit
Duplicate submissionDeduplicated by idempotency key; only one charged
Clock skewEvents accepted up to 24h in the past; future timestamps normalized
How metering works — CLIMeter Docs