ProxonProxon
Open Proxon
Documentation

OpenTelemetry

Send model usage and cost to Proxon from anything that emits OpenTelemetry.

If your agent, service, or AI tool already emits OpenTelemetry, Proxon can read its model usage and cost directly, in any language. That includes server-side AI that never runs on anyone's device, and tools that already speak OTLP such as Claude Code and GitHub Copilot. There is no new agent, no proxy, and no certificate. You mint a credential and set a few standard OTLP environment variables.

From a general OpenTelemetry exporter, Proxon reads only the structured usage it needs to attribute cost, which is the model and the token counts, and you decide what the rest of your telemetry sends. Claude Code is the exception. It stamps its own account, organization, and session identity on every record it sends, and Proxon keeps those fields so it can tell which Claude plan paid for the usage. What Claude Code sends lists them, and Putting a plan on Claude Code usage explains the one thing that path still asks of you.

This takes about five minutes. You mint a credential, point your existing OpenTelemetry exporter at Proxon, and confirm the usage lands.

Step 1: Mint a credential

Which credential you send with decides whose usage this becomes, so choose before you wire anything up.

For a tool on your own machine, use a personal credential. Open Preferences, then CLI Telemetry, and create one. Everything sent with it is attributed to you, and no administrator is in the path. Your organization has to have CLI Telemetry turned on, so ask an admin if you do not see the screen. This is the right choice for Claude Code, Codex, or anything else running on a laptop.

For a shared service, a CI job, or a server-side agent, mint an organization credential. Open Org Settings, then Credentials, and choose Generate. Proxon issues a bearer token that starts with prx_svc_, scoped to your organization. Only organization owners and admins see Credentials, so ask an admin if you do not.

An organization credential carries no person. Usage sent with one belongs to the organization and never appears under anybody's name, which is right for a shared service and wrong for one developer's machine, where it hides who is spending the money.

The token is shown once. Copy it and store it as a secret, such as an environment variable or an entry in your secrets manager. Proxon keeps only a hash, so it cannot show the token to you again. If you lose it, rotate it or generate a new one. You can revoke or rotate a credential from the same screen at any time.

Step 2: Point your OTLP exporter at Proxon

Set the standard OpenTelemetry environment variables below. Any OTLP/HTTP exporter reads them on its own, and there is nothing Proxon-specific to import. Proxon accepts both an agent's native OTLP and stock OpenTelemetry spans, in either JSON or protobuf encoding.

Give the exporter the base URL rather than a signal path. Exporters add /v1/traces or /v1/logs themselves, and one base URL covers both. That matters for Claude Code, which reports its per-call cost on the logs signal rather than on traces, so a wiring that names only the traces endpoint captures none of the money.

bash
# Point your OTLP/HTTP exporter at Proxon.
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.proxon.ai"

# Authenticate with the credential you minted in Step 1.
# The value is percent-encoded per the OTLP spec, so Bearer%20<token> means Bearer <token>.
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer%20prx_svc_<prefix>_<secret>"

# Optional. Name the agent this telemetry belongs to, since the rollup keys on it.
# This sets the standard service.name resource attribute that Proxon reads.
export OTEL_SERVICE_NAME="my-agent"

Swap the placeholder for the token from Step 1. The next batch your exporter flushes will land in Proxon.

The Claude Code block goes in ~/.claude/settings.json. Merge it into the env object you already have rather than replacing the file, since that file is strict JSON and Claude Code stops reading all of your settings if it will not parse. Keep OTEL_LOGS_EXPORTER set, because per-call cost rides on the logs signal and a metrics-only wiring gives you totals with no per-call rows and no error to tell you so. OTEL_LOG_USER_PROMPTS is off above, which means prompt text stays on the machine. Claude Code reads this file at the start of a session, so start a new one rather than continuing an old conversation.

The header value is written with a plain space here and percent-encoded in the shell block above. Both are correct in their own context, since the percent-encoded form is what the OTLP spec asks of an environment variable and a JSON settings file needs no encoding.

Step 3: Confirm it landed

Turn on OpenTelemetry in Settings, then Data Collection, so Proxon shows the Agent Cost view. Then open Cost Intelligence. Your agent's spend appears there, broken down by model and by the agent name you set, usually within a minute of the first flush.

What Proxon reads from your spans

Proxon turns each span into one usage row, using the standard OpenTelemetry GenAI attributes. Anything a normal GenAI instrumentation already sets is enough.

Attributes Proxon reads
gen_ai.provider.name       # e.g. "anthropic" or "openai"
gen_ai.request.model       # e.g. "claude-opus-4-8" or "gpt-4o"
gen_ai.usage.input_tokens  # integer
gen_ai.usage.output_tokens # integer
gen_ai.operation.name      # e.g. "chat"
proxon.agent               # optional, a per-span agent name that overrides OTEL_SERVICE_NAME

Proxon reads only the usage attributes it needs to attribute cost. Everything else your spans carry is set by your own instrumentation. If you do not want prompt or response text leaving your environment, keep it out of the telemetry you export.

What Claude Code sends

Claude Code does not use GenAI spans. It reports each call on the OTLP logs signal with its own attributes, and it stamps identity on every record whether you ask it to or not. Proxon keeps those fields, because they are what lets it tell which Claude plan paid for a call.

Identity Claude Code puts on every record
user.email           # the signed-in person's email address
user.id              # Claude Code's own user id
user.account_uuid    # the Anthropic account id, which is the key to the plan
user.account_id      # a second account spelling Anthropic sends
organization.id      # the Anthropic organization the account belongs to
session.id           # the session the call was part of

These are identity, not attribution. Proxon still credits spend to the person or service that owns the credential it arrived on, which is the choice you made in Step 1, and never to an email address a tool reported about itself. What the account and organization ids buy you is the plan, described next.

This applies to Claude Code. Other tools' exporters are read for usage only, exactly as described above.

Putting a plan on Claude Code usage

Capturing Claude Code over OpenTelemetry needs no Proxon software on the machine. Labelling that usage with a plan does, and it is worth knowing which before you roll this out.

Proxon knows what a Claude Code call cost from the moment it arrives. What it cannot tell from the telemetry alone is whether that cost was company cash or value drawn from a subscription somebody already pays for, because Claude Code sends no plan, no billing mode, and no subscription hint of any kind. Until Proxon knows the plan, the usage shows up under Unclassified, priced but not placed.

Proxon resolves the plan for a Claude Code row in this order, and stops at the first one that answers.

  1. The Anthropic account's own plan. The Mac and Windows observer apps read the Claude config file on the machine and report the plan sitting in it. That works even with network capture switched off, so a machine can supply the plan without the app inspecting a single request.
  2. The Anthropic organization's plan. If nothing has been reported for the account itself, Proxon falls back to a plan reported for the same Anthropic organization.
  3. A plan declared for that person in Proxon. Used when no observed plan is available, since a plan Proxon measured outranks one somebody typed.
  4. A plan you put in the telemetry yourself. See Setting the plan by hand.

The second rung is what makes this path work at scale. One teammate who installs the observer app reports their Claude plan once, and from then on every Claude Code call from that Anthropic organization is classified, including calls from machines with no Proxon software on them at all. One install, and the whole organization is covered.

If nobody in the Anthropic organization runs the app and nothing is declared or hand-written, the usage is still captured and still priced. It just stays Unclassified.

What counts as one Anthropic organization

An individual Claude Pro or Max login gets an Anthropic organization of its own, containing one person. So the organization fallback only reaches across people who share a company organization, which means Claude Team or Claude Enterprise.

At a company where everyone signs in with a personal Pro or Max plan, each person is their own Anthropic organization, and one teammate installing the app classifies nobody else. Each person needs either the app on a machine of their own or a plan declared for them in Proxon.

Setting the plan by hand

If you cannot run the observer app anywhere, you can state the plan in the telemetry itself with two resource attributes.

bash
export OTEL_RESOURCE_ATTRIBUTES="proxon.plan_name=Claude Max (20x),proxon.billing_mode=subscription"

proxon.billing_mode is subscription for a plan that covers the usage or api_metered for usage billed at API rates. This is the lowest rung, so a declaration in Proxon and an observed plan both override it. Treat it as a stopgap, since it is a value somebody typed rather than one Proxon measured.

What a plan changes in your numbers

The plan does not just label the usage. It decides which lane the money lands in.

  • Claude Pro, Max, and Team are covered plans. The usage becomes notional, which is value consumed against a subscription you already pay for rather than a new cash charge.
  • Claude Enterprise is metered. Anthropic bills the seat and then bills the tokens, so Enterprise usage is company cash. If your organization moves from Max to Enterprise, a cash figure appears where notional value used to be. That is the bill changing, not Proxon changing its mind.
  • An Enterprise seat has no list price, since it is negotiated per customer. Proxon shows the plan name with the seat left unpriced rather than inventing a $0 you might reconcile against an invoice.
  • A Claude Team account books a seat. Installing the observer app on one machine of a Team account tells Proxon there is a seat to pay for, and that seat fee appears in your fixed costs as a floor under the usage. An Enterprise account adds no such fee, for the reason above.

When a plan starts to apply

A plan applies from its own date forward. Proxon resolves each call against the plan that was in effect on the day of the call, so upgrading from Pro to Max, or moving from a personal Max to a company Enterprise organization, changes how new usage is classified and leaves last month's page exactly as it was. Your history does not move under you.

The same rule sets where classification begins. Usage that predates the first plan Proxon ever saw for an account cannot be resolved, because there is nothing to resolve it against. Installing the observer app classifies from that point on rather than retroactively.

Claude Code usage exported before Proxon began keeping these identity fields carries no account id at all, so it can never be classified. Those rows stay Unclassified permanently. If your Cost Intelligence page shows a block of unclassified Claude Code spend that will not resolve no matter what you install, this is why.

SDK or OpenTelemetry?

The Proxon SDK for Agents and OpenTelemetry do the same job in two ways. For a Node app you control, the Proxon SDK for Agents auto-instruments it with one line. For anything else, such as another language or a tool that already emits OpenTelemetry, use this OTLP path. Either one is enough on its own, and running both adds detail rather than new coverage. See the data collection overview for the full picture.