Step 1: Log what every AI call costs
You can't price what you don't measure. Every response from the Claude API already tells you how many tokens it used, so all you have to do is save it.
Add one table:
create table ai_usage (
id bigint generated always as identity primary key,
user_id uuid not null,
feature text not null,
model text not null,
input_tokens int not null default 0,
output_tokens int not null default 0,
cache_read_tokens int not null default 0,
cache_write_tokens int not null default 0,
cost_usd numeric(10,6) not null,
created_at timestamptz not null default now()
);
Then write one row after every call. With the Anthropic TypeScript SDK:
// Prices per million tokens. Check claude.com/pricing and update when they change.
const PRICES = {
"claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
"claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },
};
function costOf(model: keyof typeof PRICES, usage: any) {
const p = PRICES[model];
return (
usage.input_tokens * p.input +
usage.output_tokens * p.output +
(usage.cache_read_input_tokens ?? 0) * p.cacheRead +
(usage.cache_creation_input_tokens ?? 0) * p.cacheWrite
) / 1_000_000;
}
const response = await anthropic.messages.create({ model, max_tokens, messages });
await db.from("ai_usage").insert({
user_id: user.id,
feature: "agent",
model,
input_tokens: response.usage.input_tokens,
output_tokens: response.usage.output_tokens,
cache_read_tokens: response.usage.cache_read_input_tokens ?? 0,
cache_write_tokens: response.usage.cache_creation_input_tokens ?? 0,
cost_usd: costOf(model, response.usage),
});
If you're not the one writing the code, paste this section into Claude Code or your AI coding tool and say: "Add this usage logging to every place my app calls a model."
Done when
A week of real traffic has landed in ai_usage. One week is enough to see the shape.
Step 2: Find the user you're paying to keep
Now compare what each user costs you with what they pay. Run this after a week, then again after a month:
select
user_id,
count(*) as calls,
round(sum(cost_usd), 2) as ai_cost,
round(sum(cost_usd) * 30.0 /
greatest(1, extract(day from now() - min(created_at))), 2) as monthly_run_rate
from ai_usage
where created_at > now() - interval '30 days'
group by user_id
order by ai_cost desc
limit 20;
Then look at the spread, not the average:
select
percentile_cont(0.5) within group (order by c) as p50,
percentile_cont(0.9) within group (order by c) as p90,
max(c) as top_user
from (
select user_id, sum(cost_usd) as c
from ai_usage
where created_at > now() - interval '30 days'
group by user_id
) t;
Take the p90 and the top user and compare them with your plan price. If either one costs more than the plan, you're paying some of your best customers to use you.
Step 3: Run the margin calculator
The fastest way: put your numbers into the free AI Feature Margin Calculator. It prices one task on current Claude, GPT and Gemini models, shows the margin on your typical and heaviest user, and suggests the included usage and overage price.
To run it on your full distribution instead, open Claude, paste this and fill the brackets with the numbers from Step 2:
You are a SaaS pricing analyst. Here is my AI feature's real usage data.
Plan price: $[price] per month
Monthly AI cost per user, last 30 days:
- median (p50): $[p50]
- p90: $[p90]
- top user: $[top]
Number of paying users: [n]
Other cost to serve per user (hosting, email, support): $[other]
1. Calculate gross margin per user at p50, p90 and top, as dollars and percent.
2. Calculate blended gross margin across all users, using the distribution I gave you. State the assumption you make about the shape between p90 and top.
3. Tell me at what monthly usage a user becomes unprofitable, as AI cost and as a number of [unit, e.g. agent runs].
4. Propose included usage per plan so that a user who hits the cap still leaves at least 30% gross margin.
5. Propose an overage price per [unit] with at least 40% margin.
Show every calculation. Don't round until the final answer. If a number I gave you looks inconsistent, say so before calculating.
The rule the prompt enforces is the one that matters: price for the user who maxes out the plan, not the average one. Averages are what got Cursor and Anthropic.
Step 4: Three fixes, in the order to try them
Here's the same agent from the intro, on Claude Sonnet 5 at $2 per million input tokens and $10 per million output. One task is 20 model turns. The agent sends about 40,000 tokens of context each turn and writes about 1,500.
| Cost per task | Heavy user (220 tasks) |
|---|
| As built | $1.90 | $418 / month |
| + prompt caching | about $0.55 | about $121 / month |
| + route simple turns to Haiku 4.5 | about $0.40 | about $88 / month |
| + included usage: 25 tasks, then $0.99 each | capped | pays for itself |
Fix 1: Prompt caching
An agent sends the same system prompt and history again on every turn. With caching, the repeated part is read from cache at a tenth of the input price on Sonnet 5 ($0.20 per million instead of $2). In the example that takes input from $1.60 a task to about $0.25. It's often a one-line change: add cache_control to the request. Ask your coding tool: "Enable automatic prompt caching on every Claude call and show me cache_read_input_tokens in the logs."
Fix 2: Route easy turns to a cheaper model
Not every turn needs your best model. Classifying, extracting, summarizing a tool result: Haiku 4.5 does these at half of Sonnet 5's price. Keep the planning and the final answer on the strong model, and send the rest down. Check with the ai_usage table that quality didn't drop on the turns you moved.
Fix 3: Included usage plus overage
Caching and routing make each task cheaper. They don't stop one user running 1,000 tasks. Only a cap does. The pattern that works:
- Each plan includes a set amount (25 agent runs on $20, 150 on $99).
- A usage meter in the app shows how much is left.
- Past the cap, the user can buy more at a price with margin built in ($0.99 a run when it costs you about $0.40), or wait for next month.
With the numbers above, a $20 user who uses all 25 runs costs you about $10 and still leaves 50% margin. Your heavy user either upgrades, pays overage, or slows down. All three are fine.
Step 5: Add limits without the backlash
Cursor's pricing change was defensible. The way it rolled out wasn't. Users found out from their bills. Do it in this order:
- Show usage first. Put the meter in the app for two to four weeks before any limit exists. People adjust once they can see it.
- Announce by email with dates. State what changes, when, and what the included amount is. Say that 90%+ of users won't notice, if that's what your data shows.
- Protect current customers. Give existing users a grace period or a higher cap for a few months.
- Warn at 80%, never cut off mid-task. Let the running task finish, then stop.
- Talk to your top 10 users yourself. They're your best customers. Offer them a plan that fits them.
Run it today
| When | Do this | Time |
|---|
| Today | Create ai_usage and log every model call | 30 min with a coding tool |
| Day 7 | Run the two queries from Step 2 | 5 min |
| Day 7 | Paste your numbers into the margin calculator | 10 min |
| Week 2 | Turn on prompt caching, then check the cost per task again | 1 hour |
| Week 3 | Move the easy turns to a cheaper model | half a day |
| Week 4 | Ship the usage meter, then announce included usage | a day |
The goal isn't the cheapest possible AI bill. It's knowing, for every plan you sell, what the customer who uses it the most costs you, and making sure that number is lower than the price.