An open standard for recording who initiated an agent run and what each step cost, across every system the run passes through.
A single agent run touches several systems. The application knows the customer and the feature. The router knows the model, the tokens and the price. The provider knows the cache split. The harness knows whether the run actually resolved anything. Every layer is observable on its own, and none of them can tell you what that customer's agent cost you last month.
AUDR is one JSON record per metered operation, carrying enough identity and attribution that the records join.
{
"spec_version": "1.1.0",
"record_id": "01K4N8D2J4P7Q9R3S6T8V1W5XY",
"emitter": { "component": "router", "name": "@audr/openrouter", "version": "0.5.1" },
"timing": { "event_time": "2026-09-08T12:00:00.000Z" },
"resource": {
"provider": "anthropic",
"type": "model",
"name": "claude-sonnet-4-20250514",
"operation": "generation",
"modality": "text"
},
"run": { "run_id": "01K4N8B0M2C5F7H9J1L3N6P8QR", "span_id": "model-call-1" },
"attribution": { "environment": "production", "account_id": "account-42" },
"usage": { "llm": { "input_tokens": 1200, "output_tokens": 300 } }
}Each participating layer — harness, router, provider — may emit its own AUDR
record for an operation, each with its own record_id. In this example, the
harness creates a run_id for the run and a distinct span_id for each
operation, passing both along the request path. The sink deduplicates replayed
records by record_id and joins records from different components that share
(run.run_id, run.span_id); separate operations remain separate. Pricing the
joined usage happens downstream and is outside AUDR. See
SPEC.md §1.2,
§1.4, and the
Merge key definition for the normative
description.
sequenceDiagram
participant App as Application
participant Harness as Agent Harness
participant Router as Router / AI Gateway
participant Provider as Model Provider
participant Sink as Sink
participant Rating as Rating<br/>(outside AUDR)
App->>Harness: Start an agent run
Harness->>Harness: Create run_id
Note over Harness,Provider: span model-call-1: a model call
Harness->>Router: Model request<br/>with run_id and span_id
Router->>Provider: Forward request<br/>with the same IDs
Provider-->>Router: Result and usage
opt Provider also reports
Provider--)Sink: AUDR record (provider's view)
end
Router--)Sink: AUDR record (router's view)
Router-->>Harness: Result / tool request
Harness--)Sink: AUDR record (harness's view)
Note over Harness: span tool-call-2<br/>A tool in the same run
Harness->>Harness: Run tool<br/>parent_span_id: model-call-1
Harness--)Sink: AUDR record (tool usage)
Harness-->>App: Response
Note over Sink: Deduplicate replays by record_id<br/>Join records sharing<br/>run_id and span_id
Sink->>Rating: Joined usage, ready to price
| Path | Contains |
|---|---|
spec/ |
The standard: SPEC.md to implement it, audr.schema.json to validate records, examples/record.json for a complete record |
conformance/ |
Language-neutral fixtures every implementation must reproduce |
adapters/ |
Things that produce records — the Python and TypeScript SDKs and runtime adapters |
sinks/ |
Things that consume records — destinations such as Chargebee and Lago |
tools/ |
The specification generator and the repository checks, driven by the Makefile |
The schema's canonical URL is its $id:
https://openaudr.dev/spec/v1.1.0/audr.schema.json
Validate records with a JSON Schema Draft 2020-12 validator. Repository setup, verification and specification generation are documented in CONTRIBUTING.md.
Three parts work together. An adapter observes an agent runtime and builds a record per
metered operation; the core SDK validates, batches and accounts for records through a
Client; a sink delivers each batch to a destination. Install the core and a sink, wrap
the sink in a client, and either call client.record() yourself or let an adapter do it.
pip install audr audr-sink-chargebeeimport asyncio
import audr
from audr_sink_chargebee import ChargebeeSink
# The record shown above, built with the SDK. record_id, spec_version and
# timing.event_time are defaulted; Chargebee additionally routes on subscription_id.
record = audr.AUDR(
timing=audr.Timing(),
resource=audr.Resource(
provider="anthropic",
type="model",
name="claude-sonnet-4-20250514",
operation="generation",
modality="text",
),
run=audr.Run(run_id="01K4N8B0M2C5F7H9J1L3N6P8QR", span_id="model-call-1"),
attribution=audr.Attribution(
environment="production", account_id="account-42", subscription_id="sub-42"
),
usage=audr.Usage(llm=audr.LlmUsage(input_tokens=1200, output_tokens=300)),
)
async def main() -> None:
sink = ChargebeeSink(site="acme", api_key="cb_live_...") # any Sink: a file, a queue, Chargebee
async with audr.Client(
sink,
emitter=audr.Emitter(component="router", name="openrouter", version="1.12.1"),
) as client:
result = client.record(record) # an adapter makes this call on your behalf
assert result.queued, result.issues
print(client.stats)
asyncio.run(main())| Part | Reference implementation | Guide |
|---|---|---|
| Core SDK | audr (Python)@openaudr/audr (TypeScript) |
adapters/core/README.md — the Client, the sink contract, delivery states |
| Adapters | audr-adapter-litellm (Python)audr-adapter-nemo-relay (Python)@openaudr/audr-adapter-merge-gateway (TypeScript)@openaudr/audr-adapter-openrouter (TypeScript)@openaudr/audr-adapter-vercel-ai (TypeScript)@openaudr/audr-adapter-mastra (TypeScript) |
adapters/README.md |
| Sinks | audr-sink-chargebee (Python)@openaudr/audr-sink-chargebee (TypeScript)@openaudr/audr-sink-lago (TypeScript) |
sinks/README.md |
Adapters, sinks and tools maintained outside this repository are listed in
IMPLEMENTATIONS.md.
The current specification version is 1.0.0.
AUDR was drafted at Chargebee, and is being improved with collaboration across the ecosystem. Granular cost and usage instrumentation are foundational to agent unit economics — the infrastructure every team building or monetizing agents will need. We believe that infrastructure should be open, neutral, and community-owned. As adoption grows, the goal is to move cost governance to an independent foundation.
Stewarded by Chargebee. Contact us at audr@chargebee.com.
Tell us where AUDR breaks for a cost model you have and we haven't imagined. Open an issue or email audr@chargebee.com. See CONTRIBUTING.md; participation is governed by the Code of Conduct.
To report a vulnerability, follow SECURITY.md. It also states the data-handling rules the format depends on: records carry no prompt content, no key material, and no PII.
Apache 2.0. See NOTICE.