Skip to main content

Metrics & Cost Tracking

Patter automatically tracks cost and latency for every call, broken down by provider component (STT, TTS, LLM, telephony).

How It Works

Metrics are collected automatically during calls. When a call ends, the on_call_end callback receives a CallMetrics object with the full breakdown:

Cost Breakdown

The CostBreakdown object provides per-component costs in USD:

Latency Breakdown

The LatencyBreakdown object provides per-component latency in milliseconds: CallMetrics exposes the full distribution: latency_avg, latency_p50 (median / typical UX), latency_p90 (steady-state outliers), latency_p95 (SLA), and latency_p99 (cold-start outliers).

Per-Turn Metrics

Each conversation turn is tracked individually:

Custom Pricing

Override default provider pricing estimates:

PricingUnit

The pricing tables expose a PricingUnit StrEnum so overrides don’t depend on raw strings:
Subclassing str keeps the values JSON-serialisable and backward-compatible with code that compares against the literal strings (config.get("unit") == "minute").

Model-Aware Pricing

Patter’s pricing tables are model-aware: every entry in DEFAULT_PRICING carries provider-level defaults plus an optional models map keyed by model identifier. When the agent’s adapter exposes a model attribute, the metrics layer threads it through the cost-calc functions and the dashboard bills with model accuracy out of the box — no manual override required.

How resolution works

The cost-calc helpers (calculate_stt_cost, calculate_tts_cost, calculate_realtime_cost, calculate_realtime_cached_savings) accept an optional trailing model arg. The internal _resolve_provider_rates(config, model) helper merges per-model overrides on top of provider defaults using:
  1. Exact match in the provider’s models dict.
  2. Longest-prefix matchgpt-realtime-2-2026-05-08 resolves against gpt-realtime-2.
  3. Provider defaults — fallback when the model is unknown or omitted.
CallMetricsAccumulator auto-tracks stt_model, tts_model, and realtime_model from the agent’s adapter model attribute (agent.stt.model, agent.tts.model, agent.model for Realtime). On every record_realtime_usage(usage) call the realtime model is also pulled from the response.done payload itself, overriding the call-level default — so mid-call model switches are billed correctly.
The optional model argument defaults to None, which preserves the legacy provider-rate behaviour. Existing callers compile and run unchanged.

Example A — Just select a model

The most common case: pick a model on your adapter, and Patter bills the right rate automatically.

Example B — Override one model, keep siblings intact

merge_pricing overlays the nested models dict shallowly. Overriding a single model leaves the other rates inside the same provider untouched.

Example C — Register a brand-new model rate

Add a model that isn’t in the built-in table without touching SDK source.

Default Pricing (2026.3)

Provider-level defaults are listed below. Per-model rates live under DEFAULT_PRICING[provider]["models"] and are auto-resolved when the adapter exposes its model identifier.

STT — per-model rates

TTS — per-model rates

OpenAI Realtime — per-model rates

gpt-4o-realtime-preview is roughly 10x the cost of gpt-realtime-mini for audio. Switching realtime models has direct billing impact — confirm the model on agent.realtime.model matches the rate you expect.

xAI Realtime — rates

Unlike OpenAI Realtime (token-based), the xAI Grok Voice Agent is billed per minute of session audio, so Patter meters it from the call’s duration_seconds rather than token counts.
Twilio defaults match US inbound local. Override pricing.twilio.price for US toll-free inbound (~0.022/min)orUSoutboundlocal( 0.022/min) or US outbound local (~0.014/min). Default pricing is based on publicly listed provider rates and may become stale — check the provider’s pricing page or pass your own overrides for authoritative numbers.

Real-Time Metrics

Use the on_metrics callback for live cost updates during a call:
The cost_so_far value is a CostBreakdown dataclass, so access its fields as attributes (e.g. cost.total, cost.stt) rather than dictionary keys.

Data Types

CallMetrics

TurnMetrics