Skip to main content

RunCost

CI GitHub release npm PyPI Go Reference License: MIT Python 3.9+ TypeScript types Playground

RunCost Ledger is an auditable LLM API cost calculator for answering one question:

What did this LLM or agent API call cost, and why?

It turns provider responses, framework usage objects, or normalized usage into a componentized cost ledger with input, cached input, output, reasoning, tool units, batch results, discounts, dated price sources, and warnings. It runs in Python, JavaScript/TypeScript, Go, the CLI, browsers, and edge runtimes without requiring a proxy or hosted account.

Install

Install from package registries:

pip install runcost-ai
npm install runcost
go get github.com/adamallcock/runcost/packages/go/ledger

Source checkout development paths:

python3 -m pip install git+https://github.com/adamallcock/runcost.git
PKG_TGZ=$(npm pack ./packages/javascript/core --silent)
npm install "./$PKG_TGZ"

The Python distribution name is runcost-ai; the import package and CLI are runcost. The npm package is runcost. The Go package is github.com/adamallcock/runcost/packages/go/ledger.

60-Second Quickstart

The convenience APIs resolve current public pricing from genai-prices, then models.dev, then LiteLLM, and cache the selected source for 24 hours. Pass the response you already receive; RunCost never sends it to a pricing source.

Python:

from runcost import from_response_auto

response = {
    "id": "resp_example",
    "object": "response",
    "model": "gpt-4.1-mini-2025-04-14",
    "usage": {
        "input_tokens": 36,
        "input_tokens_details": {"cached_tokens": 6},
        "output_tokens": 87,
        "output_tokens_details": {"reasoning_tokens": 12},
    },
}

ledger = from_response_auto(response, provider="openai")
print(ledger["total"], ledger["components"], ledger["warnings"])

JavaScript/TypeScript:

import { fromResponseAuto } from "runcost";

const response = {
  id: "resp_example",
  object: "response",
  model: "gpt-4.1-mini-2025-04-14",
  usage: {
    input_tokens: 36,
    input_tokens_details: { cached_tokens: 6 },
    output_tokens: 87,
    output_tokens_details: { reasoning_tokens: 12 }
  }
};

const ledger = await fromResponseAuto(response, { provider: "openai" });
console.log(ledger.total, ledger.components, ledger.warnings);

CLI (Python install or npx runcost):

runcost quote response.json --provider openai
cat batch-results.jsonl | runcost quote - --jsonl --provider openai

Try the same flow without installing anything in the browser playground.

External Price Resolution

Published RunCost packages contain no provider price database. The auto APIs select exactly one upstream catalog per calculation, record attempted-source and cache metadata, and fall back to the next source only when the earlier one cannot price the requested model. OpenRouter-billed responses try OpenRouter's models API first; direct-provider responses do not silently use OpenRouter rates.

Python: resolve_price_catalog(...), from_response_auto(...)

JavaScript/TypeScript: resolvePriceCatalog(...), fromResponseAuto(...)

Go: ResolvePriceCatalog(...), FromResponseAuto(...)

Node, Python, Go, and the CLIs use an OS cache with conditional refresh and a last-known-good fallback. Browser/edge builds use an in-memory cache. Use runcost prices status|refresh|clear to inspect or manage the CLI cache.

Explicit Custom Prices

Explicit cards remain the deterministic, network-free path for negotiated rates, unpublished models, reviewed snapshots, or fully self-contained tests.

Python:

from runcost import from_response

response = {
    "model": "gpt-4.1-mini-2025-04-14",
    "usage": {
        "input_tokens": 36,
        "input_tokens_details": {"cached_tokens": 6},
        "output_tokens": 87,
        "output_tokens_details": {"reasoning_tokens": 12},
    },
}

price_cards = [{
    "schema_version": "0.1",
    "id": "openai:gpt-4.1-mini:example",
    "provider": "openai",
    "surface": "openai.responses",
    "model": "gpt-4.1-mini",
    "aliases": ["gpt-4.1-mini-2025-04-14"],
    "components": [
        {"usage_component": "input_uncached_tokens", "unit": "token", "price": {"amount": "0.40", "currency": "USD", "per": "1000000"}},
        {"usage_component": "input_cache_read_tokens", "unit": "token", "price": {"amount": "0.10", "currency": "USD", "per": "1000000"}},
        {"usage_component": "output_text_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
        {"usage_component": "output_reasoning_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
    ],
    "source": {"name": "example"},
}]

ledger = from_response(
    response,
    provider="openai",
    surface="openai.responses",
    model="gpt-4.1-mini",
    price_cards=price_cards,
)

print(ledger["total"])
print(ledger["components"])
print(ledger["warnings"])

TypeScript:

import { fromResponse } from "runcost";

// Using the same response and priceCards shape as the Python example above.
const ledger = fromResponse(response, {
  provider: "openai",
  surface: "openai.responses",
  model: "gpt-4.1-mini",
  priceCards
});

console.log(ledger.total);
console.log(ledger.components);
console.log(ledger.warnings);

Go:

package main

import (
    "fmt"

    ledger "github.com/adamallcock/runcost/packages/go/ledger"
)

func main() {
    priceCards := []any{
        ledger.Object{
            "schema_version": "0.1",
            "id":             "openai:gpt-4.1-mini:example",
            "provider":       "openai",
            "surface":        "openai.responses",
            "model":          "gpt-4.1-mini",
            "aliases":        []any{"gpt-4.1-mini-2025-04-14"},
            "components": []any{
                ledger.Object{
                    "usage_component": "input_uncached_tokens",
                    "unit":            "token",
                    "price": ledger.Object{"amount": "0.40", "currency": "USD", "per": "1000000"},
                },
                ledger.Object{
                    "usage_component": "output_text_tokens",
                    "unit":            "token",
                    "price": ledger.Object{"amount": "1.60", "currency": "USD", "per": "1000000"},
                },
            },
            "source": ledger.Object{"name": "example"},
        },
    }

    cost := ledger.FromResponse(
        ledger.Object{
            "model": "gpt-4.1-mini-2025-04-14",
            "usage": ledger.Object{
                "input_tokens":  36,
                "output_tokens": 87,
            },
        },
        ledger.Object{
            "provider": "openai",
            "surface":  "openai.responses",
            "model":    "gpt-4.1-mini",
        },
        priceCards,
        nil,
    )

    fmt.Println(cost["total"])
}

Already have normalized usage? Use the deterministic calculator directly:

from runcost import calculate_cost

ledger = calculate_cost(
    usage_ledger={
        "schema_version": "0.1",
        "provider": "openai",
        "surface": "openai.responses",
        "model": {"requested": "gpt-4.1-mini"},
        "components": [
            {"name": "input_uncached_tokens", "quantity": "30", "unit": "token"},
            {"name": "output_text_tokens", "quantity": "75", "unit": "token"},
        ],
    },
    price_cards=price_cards,
)

Main APIs

Job Python JavaScript/TypeScript Go
Price normalized usage calculate_cost(...) calculateCost(options) CalculateCost(options)
Price a provider response from_response(...) fromResponse(response, options) FromResponse(response, options, priceCards, discountPolicies)
Normalize batch results from_batch_results(...) fromBatchResults(items, options) FromBatchResults(items, options)
Adapt OpenTelemetry GenAI spans from_otel_genai_span(...) fromOTelGenAISpan(span, options) FromOTelGenAISpan(...)
Adapt Pydantic genai-prices price_cards_from_genai_prices(...) priceCardsFromGenAIPrices(...) PriceCardsFromGenAIPrices(...)
Estimate and check a budget estimate_cost(...), evaluate_budget(...) estimateCost(...), evaluateBudget(...) EstimateCost(...), EvaluateBudget(...)
Reconcile a provider total reconcile_cost(...) reconcileCost(...) ReconcileCost(...)
Resolve and cache external prices resolve_price_catalog(...) resolvePriceCatalog(options) ResolvePriceCatalog(ctx, options)
Price with automatic resolution from_response_auto(...) fromResponseAuto(response, options) FromResponseAuto(...)
Aggregate call ledgers aggregate_cost_ledgers(...) aggregateCostLedgers(options) AggregateCostLedgers(...)
Use framework outputs from_langsmith_run(...), track_langchain_costs(...), and more fromVercelAISDKStreamFinish(...), createRunCostVercelOnFinish(...), and more FromLangSmithRun(...), FromSemanticKernelTelemetry(...), and more
Load price sources price_cards_from_json_file(...), price_cards_from_openrouter_models(...) priceCardsFromJSONFile(...), priceCardsFromOpenRouterModels(...) PriceCardsFromJSONFile(...), PriceCardsFromOpenRouterModels(...)
Add custom prices Pass price_cards Pass priceCards Pass price_cards in options
Apply discounts Pass discount_policies Pass discountPolicies Pass discount_policies in options
Audit decisions debug_trace=True debugTrace: true "debug_trace": true
Fail on ambiguity mode="strict" mode: "strict" mode: "strict"
CLI quote/checks runcost quote, runcost price-cards, runcost fixture-check npx runcost quote N/A

Supported Inputs

Fixture-backed surfaces include OpenAI Responses, Chat Completions, Embeddings, Images, and Batch; Anthropic Messages and Message Batches; Gemini Developer and Vertex AI batch/generateContent; AWS Bedrock Converse and model-invocation batch; Kimi and DashScope batch; OpenRouter; Cohere Chat and Rerank, OpenAI-compatible providers such as Meta, Groq, xAI, Mistral, DeepSeek, Azure OpenAI, Hugging Face Inference Providers, Tinker, NVIDIA NIM, AI21, Arcee, DashScope, Inception, Poolside, Xiaomi, ZAI, and MiniMax, plus selected framework objects from LangChain, Vercel AI SDK, OpenAI Agents SDK, LlamaIndex, Haystack, LiteLLM, AutoGen/AG2, LangSmith, Semantic Kernel, and OpenRouter SDK paths.

Anthropic Messages includes generic per-attempt fallback attribution across raw responses, Python SDK objects, and final streaming events. Ledgers expose the requested, attempted, serving, and pricing models; Message Batch refusals remain visible as successful provider results that require a separate retry.

See supported surfaces for the current matrix.

Custom Prices And Discounts

RunCost treats provider pricing as data. You can pass user price cards for private rates, exact aliases, service tiers, long-context prices, historical effective dates, tool units, or internal billing units.

discounts = [{
    "schema_version": "0.1",
    "id": "openai-contract-4pct",
    "match": {"provider": "openai"},
    "adjustment": {"type": "percentage_discount", "value": "4"},
}]

The returned ledger records selected price sources, applied discounts, and any warning that prevents the total from being fully explained.

Fixtures are behavioral conformance tests, not a complete model-price database. Use the external resolver, a caller-owned reviewed source-cache snapshot, or explicit contract cards; see price data strategy.

Python:

from runcost import from_response_auto

ledger = from_response_auto(
    response,
    provider="openai",
    surface="openai.responses",
    model="gpt-4.1-mini",
    sources=["genai-prices", "models.dev", "litellm"],
)

TypeScript:

import { fromResponseAuto } from "runcost";

const ledger = await fromResponseAuto(response, {
  provider: "openai",
  surface: "openai.responses",
  model: "gpt-4.1-mini",
  sources: ["genai-prices", "models.dev", "litellm"]
});

Warnings

RunCost is designed to be boring. When it cannot confidently price something, it returns a structured warning such as unknown_model, component_unpriced, price_stale, stream_usage_missing, or provider_reported_cost_mismatch. Use strict mode in tests or reconciliation flows when warnings should fail.

CLI

The Python and npm packages install equivalent quote CLIs:

runcost quote response.json --provider openai
runcost quote - --jsonl --provider openai < responses.jsonl
runcost price-cards --source-type user-pricing --input prices.json
runcost fixture-check fixtures/my-case.json
npx runcost quote response.json --provider openai

Read Next

Status

RunCost 0.2.x is public beta. The strict live-smoke, release, and real dashboard-comparison gates pass, and the core behavior is fixture-backed across Python, JavaScript/TypeScript, and Go. The public conformance report inventories 202 cases without claiming unsupported behavior. Packages are published to PyPI, npm, and Go module tags. Use provider-reported costs, exports, or dashboard reconciliation before treating any independent calculation as invoice-exact.

Release files for runcost-ai 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for runcost-ai 0.2.1
File Size Uploaded
runcost_ai-0.2.1.tar.gz 72.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for runcost-ai 0.2.1
File Interpreter ABI Platform
runcost_ai-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 143.7 kB

Release files / runcost_ai-0.2.1.tar.gz

Download URL runcost_ai-0.2.1.tar.gz
Size 72.9 kB
Tags Source
SHA-256 checksum
How to use checksums
4c9ef602c41501c1db745c1b2634267cf560627f05cee4c319f80ce1df629219
BLAKE2b-256 checksum
How to use checksums
743c001b00a612b44d053188b3ebfb9c51160b0193af6ec9c20d24b0aa159573
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 31, 2026.

Transparency log

Release files / runcost_ai-0.2.1-py3-none-any.whl

Download URL runcost_ai-0.2.1-py3-none-any.whl
Size 70.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d4786126259faa038b70c5426159cb56ea0602a2338567e1d5f2007b76e05506
BLAKE2b-256 checksum
How to use checksums
29e4b9cc91e8ca5646ba77e4580277eb39320155c5468f9e90dc2eda799c4719
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 31, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.13

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page