Pricing

How Trodo turns tokens into dollars: report tokens or a cost, set per-model prices your team controls, and track cost per category.

Every LLM span carries a per-span cost in USD. The SDK never hardcodes prices: you report token counts (or a final cost), and Trodo computes the dollars from prices you control. This works on every ingestion path, the SDKs and OTLP /v1/traces alike.

How cost is resolved

Each LLM span takes its cost from the first source that applies, in priority order:

1
Explicit cost

A final USD number you send. Used as-is, never recomputed.

2
Team Model Price

Your configured rate for the model, from Configuration → Model Price.

3
Built-in default

Trodo's default price for that model.

4
Unset

Unknown model: cost left blank. Never a false $0.

In detail:

  1. Explicit cost: a final USD number you send. Used as-is, never recomputed.
  2. Token pricing: you send token counts and Trodo prices them, using your team's configured Model Price (Configuration → Model Price), then Trodo's built-in default, then left unset if the model is unknown.

Prices apply going forward. Changing a price affects new spans only; it does not retroactively recompute past runs.

Token categories

Tokens live in an open usage_details map. input and output are the defaults; you can also price cache_read, cache_write, reasoning, audio, image, or any custom key. Raw provider field names are accepted and normalised server-side:

You send (raw provider field)Normalised to
prompt_tokens, promptTokenCountinput
completion_tokens, candidatesTokenCountoutput
cache_read_input_tokens, prompt_tokens_details.cached_tokens, cachedContentTokenCountcache_read
cache_creation_input_tokenscache_write
reasoning_tokensreasoning

A custom category is only priced if its key matches a category you add in the Model Price UI.

Report cost from the SDK

The llm helper and auto-instrumentation capture usage for you, including cache and reasoning tokens, so most of the time you send nothing extra. When you need control, trackLlmCall and setLlm accept several forms.

// (a) Tokens only — priced from the model name; cache tokens captured automatically.
const answer = trodo.llm('answer', callAnthropic, {
  model: 'claude-sonnet-4', provider: 'anthropic',
});

// (b) Raw provider usage object — auto-normalised.
await trodo.trackLlmCall({
  model: 'gpt-4o', provider: 'openai',
  usage: resp.usage,                 // { prompt_tokens, completion_tokens, prompt_tokens_details: { cached_tokens } }
  prompt: body, completion: resp,
});

// (c) Explicit usage map + cache shorthands.
await trodo.trackLlmCall({
  model: 'claude-sonnet-4', provider: 'anthropic',
  usageDetails: { input: 1000, output: 500 },
  cacheReadTokens: 200, cacheWriteTokens: 80,
});

// (d) Pin the final cost (skips server-side pricing).
await trodo.trackLlmCall({ model: 'gpt-4o', provider: 'openai', cost: 0.0123 });

// (e) Record a per-category cost breakdown.
await trodo.trackLlmCall({
  model: 'gpt-4o', provider: 'openai',
  costDetails: { input: 0.0003, output: 0.0005, cache_read: 0.00001 },
});

// Inside a manual span:
span.setLlm({ model: 'gpt-4o', provider: 'openai', usageDetails: { input: 1000, output: 500 }, cacheReadTokens: 200 });
# (a) Tokens only — priced from the model name; cache tokens captured automatically.
answer = trodo.llm('answer', call_anthropic, model='claude-sonnet-4', provider='anthropic')

# (b) Raw provider usage object — auto-normalised.
trodo.track_llm_call(model='gpt-4o', provider='openai', usage=resp['usage'],
                     prompt=body, completion=resp)

# (c) Explicit usage map + cache shorthands.
trodo.track_llm_call(model='claude-sonnet-4', provider='anthropic',
                     usage_details={'input': 1000, 'output': 500},
                     cache_read_tokens=200, cache_write_tokens=80)

# (d) Pin the final cost (skips server-side pricing).
trodo.track_llm_call(model='gpt-4o', provider='openai', cost=0.0123)

# (e) Record a per-category cost breakdown.
trodo.track_llm_call(model='gpt-4o', provider='openai',
                     cost_details={'input': 0.0003, 'output': 0.0005, 'cache_read': 0.00001})

# Inside a manual span:
s.set_llm(model='gpt-4o', provider='openai',
          usage_details={'input': 1000, 'output': 500}, cache_read_tokens=200)

Fields

trackLlmCall / track_llm_call and setLlm / set_llm accept:

Field (Node / Python)Meaning
model, providerUsed to match a price
inputTokens / input_tokens, outputTokens / output_tokensScalar token counts
cacheReadTokens / cache_read_tokens, cacheWriteTokens / cache_write_tokensFolded into cache_read / cache_write
usageDetails / usage_detailsOpen { category: count } map
usageRaw provider usage object (auto-extracted into the map)
costFinal USD cost. Highest priority; never recomputed
costDetails / cost_detailsPer-category USD breakdown, rolled into the run's cost breakdown

To override how the llm helper reads usage, pass extractUsage (scalar in/out) or extractUsageMap (open map) in its options.

cost is the only field that overrides token pricing. cost_details records a per-category breakdown that rolls up into the run's total_cost_details, but it does not by itself pin the span's total. To set an exact total, send cost.

Configure model prices in the app

No code required. In the app, go to Configuration → Model Price.

  • Add a model by name and set USD-per-1,000-token prices for any category: Input, Output, Cache Read, Cache Write, or a custom key. Match a model by exact name or by prefix, and optionally scope a rule to one provider (leave it blank to match any).
  • Auto-detected models — models seen in your spans (last 30 days) with no rule appear automatically tagged Unpriced. Open one and set prices to start pricing it; nothing is stored until you save.
  • Aliases and merge — fold model-name variants (for example gpt-4o-2024-11-20) under one canonical model so they're priced and charted together.
  • Priority — when more than one rule could match, the most specific wins (exact over prefix, provider-specific over any-provider), with priority breaking ties.
  • Drill-down — open a model to see its calls, cost, latency (average and p95), tokens, and error rate over time.

Models without a configured price fall back to Trodo's built-in defaults, so cost still appears out of the box. Configure prices only to override: negotiated rates, self-hosted or fine-tuned models, and cache pricing.

Via the API

The same rules are available at /api/config/model-prices for automation:

MethodPathPurpose
GET/api/config/model-pricesList your team's price rules
POST/api/config/model-pricesCreate a rule
PATCH/api/config/model-prices/:idUpdate a rule
DELETE/api/config/model-prices/:idDelete a rule
GET/api/config/model-prices/metricsPer-model usage time series

A rule is { provider?, model_pattern, match_type, prices: { input, output, cache_read, … }, priority, aliases }. Every change is written to an append-only history for audit and rollback.

Run rollups

Each run sums its spans into total_cost, and merges the per-category breakdowns into total_cost_details, so a run's cost always matches the spans that explain it.

Next

On this page