← LLMWatch
LLM API Monitoring · September 2026

Why Your LLM API Bill Is Unpredictable (And How to Fix It)

You ship a feature that uses GPT-4o. Three weeks later you have a $2,000 bill and no idea which feature caused it. This is a solvable problem — it just requires instrumentation that OpenAI doesn't provide by default.

The visibility gap in LLM billing

OpenAI's billing dashboard gives you total spend per day. Anthropic's is similar. Neither tells you which endpoint, which feature, or which user was responsible for a spike.

Compare this to how infrastructure costs work. AWS Cost Explorer lets you tag resources and see spend by tag — by service, by environment, by team. CloudWatch gives you per-Lambda invocation metrics. You can pinpoint exactly which part of your system is costing what.

LLM APIs have no equivalent. You get a daily total, a running monthly total, and a PDF invoice. That's it.

This isn't a complaint about OpenAI or Anthropic — it's a gap that exists because LLM API clients are a thin layer: you call an endpoint, you get tokens back, you pay per token. The attribution layer has to be built by the application developer.

What happens when you don't monitor

Scenario 1: The feature you forgot about

A team ships a "smart search" feature using GPT-4o with a large context window. Traffic is low at launch — $30/month. Six months later, search usage grows 10x. The feature now costs $300/month. Nobody noticed the gradual increase until the quarterly review. The feature was still on GPT-4o because nobody had a reason to revisit it. Switching to GPT-4o-mini (with a tuned prompt) would have saved $250/month with no visible quality difference.

Scenario 2: The accidentally expensive endpoint

A developer adds an "explain this error" feature to a developer tool. The prompt includes the full stack trace, the surrounding code, and the last 20 log lines — sometimes 8,000 tokens of context. At 500 uses/day, this generates $40/day in input tokens alone. The team didn't realize because there was no per-feature tracking. Total cost to find the bug: the next monthly invoice arriving $1,200 over budget.

Scenario 3: The runaway batch job

A nightly job summarizes customer support tickets from the previous day using Claude 3.5 Sonnet. A bug causes it to reprocess all historical tickets instead of just the last 24 hours. 180,000 tickets × average 2,000 tokens = 360M tokens. At $3/M input tokens, that's $1,080 — charged overnight. Discovered the next morning. No alert fired.

How to add LLM cost monitoring today

The pattern is straightforward: wrap your LLM client calls with a function that records usage and calculates cost before returning the response.

Python (OpenAI)

from openai import OpenAI
import time

client = OpenAI()

# Prices per 1K tokens (update as rates change)
MODEL_PRICES = {
    "gpt-4o":       {"input": 0.0025, "output": 0.010},
    "gpt-4o-mini":  {"input": 0.000150, "output": 0.000600},
}

def tracked_chat(feature: str, model: str, messages: list, **kwargs):
    start = time.time()
    response = client.chat.completions.create(
        model=model, messages=messages, **kwargs
    )
    elapsed = time.time() - start
    usage = response.usage
    prices = MODEL_PRICES.get(model, {"input": 0, "output": 0})
    cost = (usage.prompt_tokens / 1000 * prices["input"] +
            usage.completion_tokens / 1000 * prices["output"])
    
    # Log to your metrics system
    record_cost(feature=feature, model=model, cost_usd=cost,
                prompt_tokens=usage.prompt_tokens,
                completion_tokens=usage.completion_tokens,
                latency_ms=elapsed * 1000)
    return response

TypeScript (Anthropic)

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const MODEL_PRICES: Record = {
  "claude-3-5-sonnet-20241022": { input: 0.003, output: 0.015 },
  "claude-3-haiku-20240307":    { input: 0.00025, output: 0.00125 },
};

async function trackedMessage(
  feature: string,
  params: Anthropic.MessageCreateParamsNonStreaming
) {
  const response = await client.messages.create(params);
  const prices = MODEL_PRICES[params.model] ?? { input: 0, output: 0 };
  const cost =
    (response.usage.input_tokens / 1000) * prices.input +
    (response.usage.output_tokens / 1000) * prices.output;

  recordCost({ feature, model: params.model, costUsd: cost,
               inputTokens: response.usage.input_tokens,
               outputTokens: response.usage.output_tokens });
  return response;
}

What to record and where to store it

At minimum, capture per call: feature name, model, prompt tokens, completion tokens, cost in USD, timestamp. This gives you the raw material to answer questions like:

Storage optionLatency overheadQuery capabilityCost
Postgres (existing DB)~2msFull SQLFree if you have it
ClickHouse (self-hosted)~1msExcellent for aggregations~$20-40/mo
DataDog custom metrics~5ms asyncGood dashboards$0.05/metric/month
Simple JSON log file<1msgrep + jqFree

For most teams starting out, Postgres is the right answer. You almost certainly already have it, the schema is simple, and you can get per-feature aggregations with a single GROUP BY query.

Setting up alerts

Once you have per-feature data, alerting is straightforward. The two most useful alert types:

Daily spend threshold

Alert when any single feature exceeds a daily cost threshold. A simple cron job running once per hour that queries SUM(cost_usd) WHERE feature = 'X' AND date = today() and fires a Slack message when it exceeds your limit works well at small scale.

Cost rate spike (z-score)

Alert when a feature's cost in the current hour is more than 2 standard deviations above its 30-day hourly average. This catches runaway batch jobs and unexpected traffic spikes without requiring you to set manual thresholds for every feature.

Try the free calculator: Before you ship a new LLM feature, estimate its projected cost at your expected traffic volume: LLM Cost Calculator →

The ongoing maintenance burden

Building this infrastructure yourself is a few days of work — and then an ongoing maintenance burden as model prices change, new models are released, and your feature set grows. You'll need to:

This is solved infrastructure. The building blocks are simple enough that most teams do build it themselves — but it's the kind of work that lives in a maintenance purgatory once it's deployed.

LLMWatch: per-feature LLM cost attribution out of the box

One-line SDK wraps your OpenAI and Anthropic clients. Real-time dashboard shows cost by feature, user, and endpoint. Threshold alerts before your bill arrives.

Join the LLMWatch waitlist →