AI workloads¶
Every tool in this section ships on every plan. Cost tracking for AI is commodity; what LumaTrack adds is the other column: the value those runs produced, in the same auditable ledger as the rest of your automation.
Token-priced run events¶
Add an ai object to any run event and LumaTrack prices
it server-side from a maintained table of 2,400+ models (sourced from the
open LiteLLM dataset, refreshed weekly), as Decimal, stamped with the
price-table version in force so the figure stays auditable when prices move:
curl -X POST "$LUMATRACK_URL/api/v1/runs" \
-H "Authorization: Bearer $LUMATRACK_KEY" \
-H "Content-Type: application/json" \
-d '{
"automation": "phishing-triage-agent",
"status": "success",
"ai": {
"model": "claude-sonnet-5",
"input_tokens": 10000,
"output_tokens": 2000,
"cached_tokens": 50000
}
}'
input_tokens are non-cached input tokens; cached_tokens are cache reads,
billed at the model's cache rate (or the input rate when the model has none).
Send "cost" to override the computation with your own figure (stamped
client). An unknown model is stored unpriced and flagged in the response;
LumaTrack never guesses a price. Set your negotiated rates per model under
your organization's price overrides.
The computed cost lands in the ledger's per-run cost bucket, next to labor value, so an AI automation's net is real: value minus what the tokens cost.
Flat-rate subscriptions (billing basis)¶
Agents that run on a flat-rate plan (Claude Max seats, Copilot) cost you nothing per call; pricing their tokens at API list would book a number you never paid. Mark the usage instead:
"ai": {"model": "claude-opus-4-8", "input_tokens": 120000,
"output_tokens": 50000, "billing": "subscription"}
LumaTrack then books $0 marginal cost to the ledger and records the
API-equivalent as list_cost on the run: the repricing exposure, kept
with the same price-version audit stamp. Model the plan fee itself as a
recurring cost component on the automation, which is where a subscription
honestly belongs. Set a per-automation default under the automation's
settings (ai_billing) so flag-less flows (OTLP spans, n8n) inherit it;
an explicit billing on the event always wins. On the LiteLLM proxy, use
lumatrack_billing: subscription in request metadata or
LUMATRACK_AI_BILLING=subscription for the whole proxy.
The counterpart is "billing": "metered": API-billed traffic, priced from
the model table and booked as real spend. It is the default, so you only
send it explicitly to override an automation whose ai_billing default is
subscription. The common case is a mostly-flat-rate agent whose overflow
calls fall through to the API and should book their actual cost.
"ai": {"model": "claude-opus-4-8", "input_tokens": 120000,
"output_tokens": 50000, "billing": "metered"}
Why this matters: flat-rate AI pricing is being repriced across the industry (GitHub Copilot moved every plan to usage-based billing on 2026-06-01; Anthropic capped and then re-worked subscription agent usage through 2025 to 2026). The scenarios page prices exactly that risk.
What-if scenarios (Team and above)¶
The Scenarios page re-evaluates your as-reported ledger under conditions you choose (an AI repricing, an assumption haircut, a volume drop) without changing a booked number, and shows which automations survive each. The flat-rate toggle prices your subscription-covered usage at list, so you can see your exposure if a provider moves you to usage-based billing.
Full walkthrough: What-if scenarios.
MCP server¶
LumaTrack ships a stateless MCP endpoint at POST /mcp (Streamable HTTP,
JSON responses, no sessions), authenticated with your existing API key:
{
"mcpServers": {
"lumatrack": {
"url": "https://lumatrack.io/mcp",
"headers": {"Authorization": "Bearer lmt_..."}
}
}
}
Tools: record_run (file run evidence, tokens included; the exact ingestion
the REST API uses), list_automations, get_roi_summary,
get_automation_roi, and get_scenario_stress (the what-if engine: an agent
can ask whether it would still be net-positive if its own tokens cost five
times as much). An ingest-scope key sees only the first two, mirroring
the REST scope rules, so an agent can file its own evidence with a key that
cannot read your ledger.
OpenTelemetry ingest¶
If your stack already emits OpenTelemetry GenAI spans, you do not need our SDK.
Point an OTLP/HTTP exporter at POST /otel/v1/traces (JSON encoding) with your
API key as a bearer token. Spans carrying gen_ai.* attributes become priced
run events; traceId:spanId is the idempotency key, and an OTLP error status
maps to a failed run. Unmatched spans are rejected and counted in the response,
never guessed.
Point the exporter at LumaTrack (works for any language SDK):
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://lumatrack.io/otel/v1/traces"
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="Authorization=Bearer lmt_..."
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL="http/json"
Route each span to an automation in one of two ways: set the
lumatrack.automation span attribute to the automation's slug (per call), or
name your service.name resource attribute after the slug (per service). The
automation must already exist. The span's billing basis follows the
automation's ai_billing default (see above); mark flat-rate services
subscription on the automation.
Both /mcp and /otel/v1/traces share your organization's
API rate limit with the REST API; a 429
with a Retry-After header means back off that many seconds. OTel SDK
exporters batch spans (many spans per request) and retry on 429 on their
own, so at the plans' limits this is not something a normal setup hits.
What LumaTrack reads (OTel GenAI semantic conventions, so we never invent a
convention that drifts): gen_ai.request.model (or gen_ai.response.model)
for the model; gen_ai.usage.input_tokens and gen_ai.usage.output_tokens
for tokens; gen_ai.usage.cache_read_input_tokens (or gen_ai.usage.cached_tokens)
for cache reads.
Supported AI vendors and instrumentations¶
Any library that emits the gen_ai.* conventions works. Verified paths:
- OpenAI and Anthropic via OpenLLMetry (Traceloop):
pip install traceloop-sdk, thenTraceloop.init(app_name="password-reset-agent"): the app name becomesservice.name, so name it after the automation's slug. It auto-instruments the OpenAI and Anthropic Python SDKs and emitsgen_ai.usage.*per call. - OpenAI and Anthropic via OpenInference (Arize/Phoenix): the
openinference-instrumentation-openai/-anthropicpackages emit the same attributes; add alumatrack.automationspan attribute via a span processor. - LangChain / LlamaIndex: both OpenLLMetry and OpenInference ship framework instrumentors; the underlying OpenAI/Anthropic calls carry the token attributes LumaTrack prices.
- The Claude Agent SDK and Claude Code fleets: set the three
OTEL_EXPORTER_OTLP_TRACES_*variables above and aservice.nameper agent; their gen_ai spans price automatically. - Bedrock / Vertex-hosted OpenAI or Anthropic models: instrument at the SDK
layer (OpenLLMetry/OpenInference) so the
gen_ai.request.modelreflects the model you want priced. Unknown model ids are stored unpriced and flagged; add a per-org price override for a private model id.
Tokens are the source of truth; if your instrumentation also emits a cost
attribute you trust, send it through the REST ai.cost override instead.
LiteLLM callback¶
Running the LiteLLM proxy? One callback turns every proxied LLM call into a run event, with LiteLLM's own cost figure attached:
Download litellm_lumatrack.py next to your
proxy config (or anywhere on the proxy's PYTHONPATH), then:
litellm_settings:
callbacks: ["litellm_lumatrack.LumaTrackLogger"]
Set LUMATRACK_URL and LUMATRACK_KEY in the proxy environment and put
lumatrack_automation: <slug> in request metadata (per key, team, or call).
Calls without a mapping are skipped.
Billed spend and coverage¶
Token math estimates drift 1 to 3% from the invoice. Paste an OpenAI or Anthropic admin key under Settings and LumaTrack imports your billed daily AI spend (keys are encrypted at rest and never displayed again). The analytics page then shows the honest FinOps number: how much of your billed AI spend is attributed to tracked automations, and how much nothing is measuring yet.