Your real bill, every seller
What your LLM usage would cost at every seller
Price the tokens you actually used at every company that sells the same model: the official list price, the cheapest seller we have verified, and what you could save. Only totals are used, nothing is stored, and we never ask for an API key.
Ask your coding agent
Paste this line into your agent. It reads the token counts it keeps on your computer, adds them up per model and month, prices them here and shows you the table. Only the totals leave your machine.
price my LLM usage using easiapiai.com/billNo agent? The open-source tool does it in one command: uvx --from git+https://github.com/brokonado/easiapiai easiapiai bill
(GitHub).
Using Claude Code on a Pro or Max plan? You are not billed per token there, so the result is what the same usage would cost through the API, not what you pay.
For the agent: how to do it
- Claude Code: run the script below (Python 3, standard library). It reads every
*.jsonlunder~/.claude/projects/(sub-agent folders included, plus~/.config/claude/projectsand$CLAUDE_CONFIG_DIR), keeps onlytype: "assistant"lines, skips the model<synthetic>, de-duplicates one API response across lines and files bymessage.id+requestIdkeeping the line with the largest token total, and adds upmessage.usageper model and month:input_tokens(cache excluded),cache_read_input_tokens, the 5-minute and 1-hour cache writes, andoutput_tokens(thinking included). - Codex CLI (experimental: built from Codex's published source, not yet checked on a real log): in
~/.codex/sessions/**/rollout-*.jsonl(or$CODEX_HOME/sessions), the lines withtype: "event_msg"andpayload.type: "token_count"carrypayload.info.last_token_usageand a runningtotal_token_usage. Countlast_token_usageonly whentotal_token_usagechanged (the event repeats), skip identical events repeated across files (sub-agent logs replay their parent), and take the model from the latestturn_contextline'spayload.model. Itsinput_tokensincludescached_input_tokens, so send input minus cached; reasoning is already inoutput_tokens. - A usage file the user points you to: see "Drop a usage file" below for the formats we read.
- Show the user the totals per model and month before sending anything.
- Send only the totals, never prompts, file names, project names or API keys:
POST https://easiapiai.com/api/billwith{"usage": [{"model", "label", "input_tokens", "output_tokens", "cached_input_tokens", "cache_write_tokens", "cache_write_1h_tokens"}], "current_seller": "Anthropic"}, or call the MCP toolestimate_bill. Nothing is stored. - Show the user the answer: per model, the official list price, the cheapest seller we have verified and the saving, and link easiapiai.com/bill for the full table.
The Claude Code script
#!/usr/bin/env python3
"""Claude Code token usage per model and month, from its own logs on this computer. Prints totals only.
easiapiai.com/bill. Rules (checked against real logs and the open-source ccusage, 2026-10-20):
- every *.jsonl under the projects folders, sub-agent folders included (they are not repeated in the parent);
- only lines with type "assistant"; skip model "<synthetic>";
- one API response appears on several lines (one per content block): key (message.id, requestId) across all
files, keep the line with the largest token total (output grows from line to line);
- input_tokens excludes cache reads and writes; thinking is part of output_tokens."""
import datetime, glob, json, os, sys
from collections import defaultdict
home = os.path.expanduser("~")
roots = [os.path.join(home, ".claude", "projects"), os.path.join(home, ".config", "claude", "projects")]
roots += [os.path.join(p.strip(), "projects") for p in os.environ.get("CLAUDE_CONFIG_DIR", "").split(",") if p.strip()]
best = {}
for root in dict.fromkeys(roots):
for path in glob.glob(os.path.join(root, "**", "*.jsonl"), recursive=True):
with open(path, encoding="utf-8", errors="replace") as fh:
for line in fh:
if '"assistant"' not in line:
continue
try:
d = json.loads(line)
except ValueError:
continue
m = d.get("message") if d.get("type") == "assistant" else None
u, model = (m or {}).get("usage"), (m or {}).get("model")
if not u or not model or model == "<synthetic>":
continue
cc = u.get("cache_creation") or {}
w5, w1 = cc.get("ephemeral_5m_input_tokens"), cc.get("ephemeral_1h_input_tokens")
if w5 is None and w1 is None:
w5, w1 = u.get("cache_creation_input_tokens") or 0, 0
row = (u.get("input_tokens") or 0, u.get("output_tokens") or 0,
u.get("cache_read_input_tokens") or 0, w5 or 0, w1 or 0)
try:
month = datetime.datetime.fromisoformat(d["timestamp"].replace("Z", "+00:00")).astimezone().strftime("%Y-%m")
except (KeyError, ValueError, AttributeError):
month = "unknown"
key = (m.get("id"), d.get("requestId")) if m.get("id") else (path, line)
if key not in best or sum(row) > sum(best[key][2]):
best[key] = (model, month, row)
tot = defaultdict(lambda: [0, 0, 0, 0, 0])
for model, month, row in best.values():
t = tot[(model, month)]
for i, v in enumerate(row):
t[i] += v
usage = [{"model": mo, "label": mn, "input_tokens": t[0], "output_tokens": t[1], "cached_input_tokens": t[2],
"cache_write_tokens": t[3], "cache_write_1h_tokens": t[4]} for (mo, mn), t in sorted(tot.items())]
json.dump({"usage": usage, "current_seller": "Anthropic"}, sys.stdout, indent=1)
print()
Drop a usage file
Read in your browser, never uploaded; only the totals are priced. We read:
- Claude Code logs: choose your
~/.claude/projectsfolder below (on a Mac, press Cmd+Shift+. in the file dialog to see hidden folders) or drop.jsonlfiles. - OpenAI Usage API JSON (
/v1/organization/usage/completionswithgroup_by=model). - Anthropic Usage report JSON (
/v1/organizations/usage_report/messagesgrouped by model). - OpenRouter activity JSON (
/api/v1/activity). - Any CSV with a header row:
model,input_tokens,output_tokens, and optionallycached_input_tokensandcache_write_tokens.
The CSV downloads from the OpenAI, Anthropic and OpenRouter dashboards publish no column list we could check, so we do not read them yet; their usage APIs above are documented. Cursor and Gemini CLI usage files: not yet, for the same reason.
Type it in
One row per model. Token totals for the period, e.g. 12M or 350k. Input means input not read from a cache.
| Model | Input | Output | Cached input | Cache writes |
|---|
Prices are standard list prices per 1M tokens as each seller publishes them, checked every 6 hours
(last 20 Oct, 06:19 UTC); a gateway's fee is included. "Verified" means we have reviewed the seller. Check a seller before you
switch: speed, limits and model versions differ. Agents can also call POST /api/bill or the
MCP tool estimate_bill.