Module 01 · Lesson 11 of 13Free
Estimating the cost and latency of a feature
- Level
- Beginner
- Topic
- AI engineering fundamentals
- Reading time
- 15 min
When you finish this page you can
- Count the calls behind one completed task, including refreshes and retries, as labelled assumptions.
- Turn typical and long per-call costs into a daily and monthly budget, with thinking tokens included.
- Build a latency budget from queue wait, time to first token, thinking and output speed.
- Explain why a feature that runs in the background should promise freshness rather than speed.
Builds on 2 lessons
Start with lesson 315 minVideo lesson · coming soon
The launch question has two numbers
Deskora is a help desk app. A shop’s support team uses it to answer customer emails from one shared inbox. Each customer problem becomes a ticket: one customer’s whole conversation with the support team, message by message.
Tomás, a Deskora engineer, has built a short summary at the top of long tickets. Support agents like Priya read it instead of the whole thread.
Launch is in two weeks. Deskora’s product lead asks Tomás: what will summaries cost each month, and how fast will they be?
From his first test in Calling a model API, Tomás knows one summary costs about $0.0006 on Claude Haiku 5.5: about $38 a day for 40,000 summaries. He almost replies “about $1,140 a month.”
That number prices one call, not a feature that runs all day on tickets that keep growing. This lesson answers one question: how do you turn the cost and time of one call into a monthly budget and a latency promise you can keep?
Of Deskora’s 120,000 new tickets a day, 40,000 get a summary. That share and every other number below are estimates or assumptions for this lesson’s scenario.
One summary is many calls
The to estimate is one completed task, not one API call. Here the task is “Priya opens a long ticket and finds a summary that matches it.” Several calls stand behind it.
- The first summary. Deskora makes it in the background when a ticket reaches 8 messages, the threshold the design in the next lesson uses.
- Refreshes. A summary of messages 1–8 says nothing about message 30, so Deskora makes a new one as the ticket grows.
- Retries. Calls that fail with a 429 or a 5xx are sent again; the Python SDK retries them twice by default 5. See Model API errors, rate limits and retries.
Each refresh is a new one-turn call with the whole thread, not a follow-up question. So earlier thinking is not resent, but the thread is, and it is longer every time.
A long ticket gets its first summary at message 8 and grows to 60 messages. If Deskora makes a new summary after every new message, how many calls does that one ticket make, and do they all cost the same?Show answer
Diagram not drawn yet: summary-calls-long-ticket.svg
A horizontal axis of message numbers from 0 to 60 for one long Deskora ticket. Vertical bars mark a summary call at messages 8, 13, 18 and so on up to 58: 11 bars. Each bar’s height is that call’s input tokens, rising from about 2,150 at message 8 to about 14,650 at message 58. A label reads: one call at the end, 15,150 input tokens; 11 refreshes, 92,400 input tokens in total.
How often to refresh is Tomás’s choice, and it moves the bill more than anything else.
The refresh rule sets the bill
When should Deskora make a new summary for a ticket that keeps growing?
After every new message.
Always current. But a 60-message ticket makes 53 calls, and the day costs about $904 on Claude Haiku 5.5: 24 times the per-call estimate.
When an agent opens a ticket that has changed.
No call is wasted on unopened tickets. But Priya waits for the model on every changed ticket she opens, and the call count depends on how often agents open tickets, which Deskora hasn’t measured.
In the background, after every 5 new messages.
A typical ticket makes 3 calls and a long one 11: about $187 a day. The summary can lag by up to 4 messages, the newest ones, which Priya reads anyway.
Why this choice
The summary saves Priya about five minutes of reading old messages. Four new messages take her about a minute. So a summary a few messages behind keeps most of its value, at about a fifth of the every-message cost.
When the choice changes. Chat tickets get messages seconds apart, so a quiet period, such as two minutes without a new message, fits better than a count. If agents open tickets less often than every 5 messages, refreshing on open makes fewer calls, at the price of a wait. The design in the next lesson settles the rule with real data.
Typical and long tickets, priced
Tomás prices two cases, using the shared token numbers from lesson 03. As of October 2026, Claude Haiku 5.5 costs $0.10 per million input tokens and $0.50 per million output tokens, for prompts up to 100,000 tokens 1. Thinking tokens are billed as output tokens 4.
The formula
cost per task = Σ over its calls (input tokens × input price + (thinking + summary tokens) × output price) × (1 + retry rate); cost per day = Σ over cases (tickets × cost per task)
Prices are per million tokens. The calls are the first summary and each refresh.
Typical ticket: 3 calls
input = 3 × 150 + (8 + 13 + 18) × 200 = 8,250 tokens; output = 3 × (300 + 80) = 1,140 tokens; cost = 8,250 × $0.10 ÷ 1,000,000 + 1,140 × $0.50 ÷ 1,000,000 = $0.000825 + $0.00057 = $0.001395
About 20 messages of about 200 tokens each, plus the 150-token system prompt on every call. Assumed per call: 300 thinking tokens and an 80-token summary.
Long ticket: 11 calls
input = 11 × 150 + (8 + 13 + … + 58) × 250 = 1,650 + 90,750 = 92,400 tokens; output = 11 × (800 + 100) = 9,900 tokens; cost = $0.00924 + $0.00495 = $0.01419
About 60 messages of about 250 tokens each. Assumed per call: 800 thinking tokens and a 100-token summary; using these on early calls overestimates slightly.
Retries
typical: $0.001395 × 1.02 = $0.0014229; long: $0.01419 × 1.02 = $0.0144738
Assumed: 2% of calls are sent again, each counted as fully billed to be safe.
One day
30,000 × $0.0014229 + 10,000 × $0.0144738 = $42.69 + $144.74 = $187.43, about $187
40,000 summarized tickets a day, one in four of them long (shared scenario estimate).
One month
$187.43 × 30 days = about $5,600
Five times the $1,140 Tomás nearly sent.
The thinking amounts are the weakest assumption. If thinking runs at twice the assumed amount, the month is about $7,700. After launch, usage.output_tokens_details.thinking_tokens reports the real amount on every call 4.
Diagram not drawn yet: summary-cost-by-ticket-case.svg
Two horizontal 100% bars. Top bar, share of summarized tickets: typical 75%, long 25%. Bottom bar, share of daily cost on Claude Haiku 5.5: typical $46, about 24%; long $150, about 76%.
A long ticket is 3 times longer than a typical one but costs about 10 times as much. It gets more calls, and each call sends more, so cost grows with roughly the square of length. One average ticket would sit where little of the money is.
Tomás keeps the estimate as code, so he can rerun it with logged numbers after launch:
from dataclasses import dataclass
# claude-haiku-5-5, US dollars per million tokens, as of October 2026.
# Valid for prompts up to 100,000 tokens; above that Haiku 5.5 charges 5x.
INPUT_PRICE = 0.10
OUTPUT_PRICE = 0.50 # thinking tokens are billed at this price too
SYSTEM_TOKENS = 150
FIRST_AT = 8 # first summary at message 8
REFRESH_EVERY = 5 # new summary after every 5 new messages
RETRY_RATE = 0.02 # share of calls sent again, each billed in full
SUMMARIZED_PER_DAY = 40_000
@dataclass
class TicketCase:
name: str
share: float # fraction of summarized tickets
messages: int # messages when the ticket goes quiet
tokens_per_message: int
thinking_tokens: int # assumed, per call
summary_tokens: int # assumed, per call
def cost_per_ticket(case: TicketCase) -> float:
total = 0.0
for n in range(FIRST_AT, case.messages + 1, REFRESH_EVERY):
input_tokens = SYSTEM_TOKENS + n * case.tokens_per_message
output_tokens = case.thinking_tokens + case.summary_tokens
total += (input_tokens * INPUT_PRICE + output_tokens * OUTPUT_PRICE) / 1_000_000
return total * (1 + RETRY_RATE)
cases = [
TicketCase("typical", 0.75, 20, 200, 300, 80),
TicketCase("long", 0.25, 60, 250, 800, 100),
]
daily = 0.0
for case in cases:
per_ticket = cost_per_ticket(case)
day = per_ticket * case.share * SUMMARIZED_PER_DAY
daily += day
print(f"{case.name}: ${per_ticket:.5f} per ticket, ${day:,.2f} a day")
print(f"total: ${daily:,.2f} a day, about ${daily * 30:,.0f} a month")The budget is ready. The second question is time.
Thinking is most of the wait
A summary’s has four parts. The job waits in Deskora’s queue for a free . The model reads the prompt; time to first token is the time from sending the request to the first output token 3. Then it writes its thinking, and only then the summary.
Writing time is output tokens divided by output speed, in tokens per second. Latency depends on prompt length, output length and thinking effort 2. The provider ranks models by speed but gives no seconds, so every time below is an assumption to measure.
The formula
time to summary = queue wait + time to first token + (thinking tokens + summary tokens) ÷ output speed
Assumed: 2 s of queue wait, 100 output tokens a second, and a time to first token of 0.5 s for the typical prompt and 1 s for the long one.
Typical ticket
2 s + 0.5 s + (300 + 80) ÷ 100 tokens/s = 2 + 0.5 + 3.8 = 6.3 s
Long ticket
2 s + 1 s + (800 + 100) ÷ 100 tokens/s = 2 + 1 + 9 = 12 s
Long ticket with one retry
12 s + 1 s backoff + (1 s + 9 s) = 23 s
The retry repeats the whole call after a short wait. Assumed backoff: 1 s.
On the long ticket, thinking is 8 of the 12 seconds. A shorter prompt barely moves this budget; less thinking moves it most.
If Priya waited for the summary, streaming would help little: thinking comes before any text, so she would see an empty box for about 9 seconds.
Promise freshness, not speed
Deskora doesn’t make her wait. The summary is made in the background, before anyone opens the ticket, so 12 seconds versus 6 never reaches her.
Diagram not drawn yet: summary-wait-vs-freshness.svg
Two panels. Left, summary made on open: Priya opens a 60-message ticket, then a bar shows about 12 seconds of waiting, mostly thinking, before the summary appears. Right, summary made in the background: refreshes ran at messages 50 and 55 while nobody was looking; Priya opens the ticket at message 58 and sees the summary at once. A label shows it covers messages 1 to 55, and messages 56 to 58 sit just below it, unread by the model.
The risk instead is staleness: a summary of a ticket that has moved on. So Tomás promises freshness:
- Agents never wait for a summary.
- It covers every message except at most the newest 4, plus any that arrived in the last 30 seconds.
The 30 seconds is the 23-second worst case plus headroom, and an assumption until measured.
Before launch, Tomás runs the summarizer over 200 old tickets, logging usage and the time of every call. That check costs about $1, and its numbers replace the assumptions.
Levers that come later
The estimate uses list prices. Later lessons lower them:
- Prompt caching: every refresh resends the same system prompt and the same older messages, and a cache read costs a tenth of the input price on Haiku 5.5 1. See Caching for LLM apps.
- Batch processing: work that can wait gets 50% off 1. See Batch and background processing for LLM jobs.
- Model routing: a cheap model by default, a stronger one only for tickets that need it. See Model routing.
- Shorter output: asking the model to think less cuts both cost and the 8 seconds of thinking. See Reasoning effort.
Whether Haiku’s summaries are good enough is a question for Choosing a model.
Try it yourself
Time one small call and read its usage. It costs at most about $0.0005 on Claude Haiku 5.5. If you don’t have an API key, skip this.
curl -s -o reply.json -w "total: %{time_total} s\n" https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2026-10-21" \
-d '{"model": "claude-haiku-5-5", "max_tokens": 1000, "system": "Summarize the support ticket in exactly three lines.", "messages": [{"role": "user", "content": "Ines: My order 7731 arrived without the charger.\nOmar (agent): Sorry. I will send one today.\nInes: It is now a week later and nothing has come. Can you check?"}]}'
python3 -c 'import json; print(json.load(open("reply.json"))["usage"])'The output looks like this; the numbers here are illustrative and yours will differ:
total: 2.4 s
{'input_tokens': 85, 'output_tokens': 170, 'output_tokens_details': {'thinking_tokens': 110}, ...}What to look for: output_tokens ÷ total time is a rough, low estimate of output speed, since the total includes time to first token. Run it five times; the spread between runs is why the budget has a worst case.
Where this shows up
- Design: a ticket summary feature turns this budget and promise into a design: when to refresh, where to store summaries, what to show when one is stale.
- Design: an AI customer support platform runs many calls per ticket, so cost per task decides which features are affordable.
The next lesson designs the feature that has to keep this budget and this promise.
Common mistakes
- Pricing the call, not the task. Count first summaries, refreshes and retries.
- Using one average ticket. Long tickets get more calls and bigger calls.
- Leaving thinking out. It is billed as output and is most of the wait.
- Promising speed for background work. Promise freshness, and measure it.
Check your understanding
Tomás changes the refresh rule from every 5 messages to every 10. Roughly what happens to the cost of a long ticket, and what does Priya notice?Show answer
After launch, logs show long-ticket summaries use 1,600 thinking tokens per call, not 800. Which part of the estimate moves, and does the latency promise still hold?Show answer
Deskora moves summaries from the background to “make one when the agent opens the ticket”. Which latency number now matters most?Show answer
Summary
- Price the completed task, not the call. With refreshes and retries, Deskora’s summaries cost about $5,600 a month on Claude Haiku 5.5 (as of October 2026), five times the per-call estimate.
- The refresh rule sets the bill: about $904 a day for every message, about $187 for every 5.
- Price a typical and a long case: long tickets are a quarter of the volume and three quarters of the cost.
- Latency = queue wait + time to first token + output tokens ÷ output speed. Thinking is most of it; measure every part.
- A background feature promises freshness, not speed: agents never wait, and the summary covers all but the newest few messages.