How to monitor AI API spend before it becomes a surprise
Token spend accrues invisibly inside loops. By the time the invoice arrives you cannot tell which feature caused it — which is why the fix is not a fancier dashboard, it is logging usage per request.
Three levels of monitoring
| Level | Tells you | Limitation |
|---|---|---|
| Provider dashboard | Accurate totals, per model | No attribution to features or customers |
| Per-request logging | Which feature and model drove it | Requires one wrapper in your code |
| Threshold alerts | That something changed today | Only useful if the baseline is right |
Most teams have the first and assume it is enough. It is not — it tells you the bill went up, not why.
The one wrapper that does most of the work
import time, json
def tracked_call(client, model, feature, **kwargs):
t0 = time.time()
resp = client.messages.create(model=model, **kwargs)
usage = resp.usage
log({
"ts": time.time(),
"feature": feature,
"model": model,
"input_tokens": usage.input_tokens,
"output_tokens": usage.output_tokens,
"latency_ms": int((time.time() - t0) * 1000),
})
return resp
Log input_tokens and output_tokens separately. Output costs several times more
per token, so a blended figure hides exactly the signal you need.
Turn tokens into money
RATES = { # USD per 1M tokens — keep in config, not in code
"claude-sonnet-5": (1.0, 5.0),
"claude-haiku-4-5": (0.5, 2.5),
}
def cost_of(model, in_tok, out_tok):
i, o = RATES.get(model, (0, 0))
return in_tok / 1_000_000 * i + out_tok / 1_000_000 * o
Check the current numbers on the price index — rates move, so hard-coding them in your billing code is how cost reports silently drift out of reality.
Alert on change, not on totals
A fixed threshold ("alert above $500/month") only fires when it is already expensive. Alert on day-over-day change instead — a 3x jump on a Tuesday is the shape of a bug, and it is worth knowing about even when the absolute number is small.
What to review weekly
- Cost per completed task, not cost per token — the only number that reflects value
- Which model drove the most spend, and whether that matches where the value is
- Any feature whose tokens per task are trending up — usually creeping context
- Retry volume: retries are spend that produced nothing
FAQ
Why is API spend so hard to control?
Because it is invisible by default. Unlike a subscription, cost accrues per token inside a loop, and by the time the invoice arrives you cannot tell which feature caused it. Logging usage per request is the only fix.
What should I log?
Input tokens and output tokens separately, plus model, feature or endpoint name, and a request ID. Separate is important: output costs several times more, so a blended number hides the thing you most need to see.
How do I catch a runaway bill early?
Alert on day-over-day change rather than a fixed threshold. A 3x jump on a Tuesday matters even if the absolute number is still small — that is the shape of a bug, not of growth.
Is the provider dashboard enough?
It gives accurate totals but weak attribution. You will see the bill went up, not that it was the new extraction job on model X. Per-request logging is what turns a total into an answer.
What is the cheapest way to start?
Wrap your client in one function that logs usage, and aggregate into a daily table. That single change covers most of what teams need before they reach for a dedicated observability tool.