Module 01 · Lesson 3 of 13Free
Calling a model API: request, response and cost
- Level
- Beginner
- Topic
- AI engineering fundamentals
- Reading time
- 15 min
When you finish this page you can
- Build a Messages API request and say what model, max_tokens, system and messages each control.
- Read a response by taking the text from its content blocks, checking stop_reason and recording usage, thinking tokens included.
- Work out the cost of one completed summary, and of a day of them, from the formula, with thinking tokens counted.
- Explain why every follow-up question resends the whole conversation and pays for it again.
Builds on 2 lessons
Start with lesson 114 minVideo lesson · coming soon
Priya has 26 messages to read
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.
Priya is a support agent at a kitchenware shop that uses Deskora. She starts her shift and picks up a ticket she has never seen. It holds 26 messages between a customer, Yusuf, and two other agents. She needs about five minutes to read it before she can reply.
Tomás, an engineer at Deskora, wants a three-line summary at the top of tickets like this one. Today he makes Deskora’s first call to a model: send the thread, get three lines back.
This lesson answers one question: what does Tomás send, what comes back, and what does each summary cost?
Deskora’s 120,000 new tickets a day is a fact used across this course. The thread sizes, thinking amounts and summaries a day below are estimates for this lesson’s scenario.
The call leaves from Deskora’s server
The call is one HTTPS request from Deskora’s app server to the provider’s model API, an HTTP service that runs a model on your input and returns its output. It never runs in Priya’s browser, because it carries Deskora’s . Anyone holding the key can spend Deskora’s money.
Diagram not drawn yet: deskora-summary-call.svg
Four boxes from left to right. 1: Priya’s browser opens a ticket on the Deskora app server. 2: the app server loads the 26-message thread from the ticket database. 3: the app server sends POST /v1/messages to the Claude Messages API with about 4,150 input tokens. 4: a dashed reply returns about 380 output tokens, of which about 300 are thinking and about 80 are the summary. 5: the app server shows the three-line summary above the thread.
Models read and write text as tokens: small pieces of text, often part of a word. Prices are per token. Tokens shows how text becomes tokens; here, “Yusuf’s thread is about 4,000 tokens” is enough.
The summary Priya reads is about 80 tokens long. Will Deskora pay for about 80 output tokens?Show answer
Four fields make a request
Here is Tomás’s request on the wire:
POST /v1/messages HTTP/1.1
Host: api.anthropic.com
x-api-key: <your key>
anthropic-version: 2026-10-21
content-type: application/json
{
"model": "claude-haiku-5-5",
"max_tokens": 2000,
"system": "You summarize a support ticket for the agent who picks it up. Write exactly three lines: the problem, what has been tried, and what the customer is waiting for.",
"messages": [
{"role": "user", "content": "Yusuf (customer, 3 Mar): My replacement blender arrived cracked...\n... 26 messages ..."}
]
}The x-api-key header says who pays. anthropic-version fixes the request and response format, so a later API change can’t break Deskora without warning. Version 2026-10-21 is current as of October 2026 4.
The body has four fields:
| Field | What it controls | Tomás’s value |
|---|---|---|
model |
Which model runs, and so its quality, speed and price per token | claude-haiku-5-5 |
max_tokens |
The most output tokens the call may produce, thinking included. A ceiling, not a target | 2,000 |
system |
The system prompt: instructions that hold for the whole call, such as the role and the format | The three-line rule |
messages |
The conversation so far, as user and assistant turns; the first is user |
One user turn holding the thread |
The system prompt stays the same for every ticket. Only the thread in messages changes. Writing good system prompts is a topic of its own, taught in the prompting module.
The answer comes back in blocks
Here is one example response. The text differs on every run.
{
"id": "msg_01...",
"type": "message",
"role": "assistant",
"model": "claude-haiku-5-5",
"content": [
{"type": "thinking", "thinking": "", "signature": "EosnCkYI..."},
{"type": "text", "text": "Problem: Yusuf's replacement blender arrived cracked (order 48213).\nTried: Lena offered a refund; Yusuf asked for another replacement instead.\nWaiting for: confirmation that the second replacement has shipped."}
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 4163,
"output_tokens": 377,
"output_tokens_details": {"thinking_tokens": 296},
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
}Three fields matter to Tomás’s code.
content is a list of content blocks, each with a type. Thinking is the model working through the task in its own words before it answers. It arrives first, in a thinking block. On Claude Haiku 5.5 its text is hidden by default; the signature carries an encrypted copy 2. The summary is in the text block. On an easy input the model may skip thinking, so code must not assume either block sits at a fixed position.
stop_reason says why the model stopped. The next section is about it.
usage counts what this call was billed for. output_tokens includes the thinking, and output_tokens_details.thinking_tokens says how much of it was thinking 3. Here 296 of 377 output tokens were thinking. Priya sees the other 81. The two cache fields stay at 0 until Deskora uses prompt caching.
A cut-off summary looks finished
These are the stop reasons Deskora handles now:
stop_reason |
Meaning | What Deskora does |
|---|---|---|
end_turn |
The model finished | Show the summary |
max_tokens |
Output reached the max_tokens ceiling; the text may be cut short or missing |
Don’t show it; log it |
refusal |
The model declined | Show the thread without a summary |
Others, such as tool_use, appear with features that later modules teach.
max_tokens is the trap. Thinking counts toward it, and thinking comes first 2. A ceiling sized for three visible lines can be spent before the summary starts.
Diagram not drawn yet: thinking-fills-max-tokens-first.svg
Two panels, each showing one bar for a 100-token or 2,000-token output budget. Left panel, max_tokens 100: the first 60 tokens are thinking, the next 40 are summary text, and the bar ends in the middle of the second line; stop_reason max_tokens. Right panel, max_tokens 2,000: about 300 tokens of thinking, then 80 tokens of summary, then about 1,600 tokens unused; stop_reason end_turn.
Suppose Tomás had set max_tokens to 100, because the summary is about 80 tokens. On one illustrative run, the model thinks for 60 tokens and writes 40 tokens of summary:
Problem: Yusuf's replacement blender arrived cracked (order 48213).
Tried: Lena offered a refundThe status is 200 and nothing looks broken. Priya reads “offered a refund” and sends Yusuf a refund. The missing half of the line said he wanted another replacement. Yusuf writes back angry, and the ticket stays open another day. On a run that thinks for all 100 tokens, content holds only a thinking block, and code that expects text shows an empty summary or crashes.
A 200 status means the call worked, not that the answer is complete. Only stop_reason tells you that.
How high should Tomás set max_tokens for a three-line summary on Claude Haiku 5.5?
Tight: 100 tokens, just above the summary’s length.
Fits the visible summary, but thinking spends the budget first. Some summaries are cut off mid-line and look finished; some have no text at all.
Roomy: 2,000 tokens, plus a check that stop_reason is end_turn.
A normal summary still uses about 380 tokens and costs the same, because you pay for tokens produced, not for the ceiling. A runaway call is capped at 2,000 × $0.50 per million = $0.001 of output.
The model’s maximum: 128,000 tokens.
Nothing is ever cut off. But a prompt bug that makes the model write pages has no real limit: 128,000 output tokens cost $0.064 on Haiku 5.5 and $2.56 on Claude Opus 5.5, and Priya waits minutes.
Why this choice
max_tokens guards against cost and waiting; it does not ask for short answers. The system prompt sets the length. A roomy ceiling costs nothing on normal calls, and the stop_reason check turns the rare cut-off into a visible failure instead of a wrong summary.
When the choice changes. If logs show max_tokens stops at 2,000, the model is thinking more than expected: raise the ceiling, or ask it to think less. Reasoning effort covers that control. A long output, such as a full reply draft, also needs a higher ceiling.
The call now works. What does it cost?
What one summary costs
The unit of cost is the completed task: here, one summary Priya can use. It takes one call. This estimate leaves out retries, checks on the output and follow-up questions; retries come in Model API errors, rate limits and retries.
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 at the output price 3.
The formula
cost = input tokens × input price + (thinking + text tokens) × output price
Per call, summed over the calls in one task. Prices are per million tokens, so divide by 1,000,000.
Typical ticket
4,150 × $0.10 ÷ 1,000,000 + (300 + 80) × $0.50 ÷ 1,000,000 = $0.000415 + $0.00019 = $0.000605
About 20 messages: a 4,000-token thread plus a 150-token system prompt. Assumed: 300 thinking tokens and an 80-token summary.
Long ticket
15,150 × $0.10 ÷ 1,000,000 + (800 + 100) × $0.50 ÷ 1,000,000 = $0.001515 + $0.00045 = $0.001965
About 60 messages: a 15,000-token thread. Assumed: 800 thinking tokens and a 100-token summary.
One day
30,000 × $0.000605 + 10,000 × $0.001965 = $18.15 + $19.65 = about $38
Assumed: 40,000 of the 120,000 daily tickets get a summary, one in four of them long.
The thinking amounts are assumptions. In production, usage.output_tokens_details.thinking_tokens reports the real ones, so log it on every call.
Diagram not drawn yet: deskora-summary-cost-split.svg
One horizontal bar for a typical summary on Claude Haiku 5.5, total $0.000605. The input segment, 4,150 tokens, costs $0.000415, about two-thirds. The thinking segment, 300 tokens, costs $0.00015, about a quarter. The visible summary segment, 80 tokens, costs $0.00004, under a tenth.
A common belief is that you pay for the text you see. Here the visible summary is $0.00004 of $0.000605. Leave thinking out and the estimate is about 25% too low.
The same tokens cost very different amounts on other models. Prices as of October 2026 1:
| Model | Input / output, per million tokens | Typical | Long | 40,000 a day |
|---|---|---|---|---|
Claude Haiku 5.5 (claude-haiku-5-5) |
$0.10 / $0.50 | $0.0006 | $0.0020 | about $38 |
Claude Sonnet 5.5 (claude-sonnet-5-5) |
$2 / $10 | $0.0121 | $0.0393 | about $756 |
Claude Opus 5.5 (claude-opus-5-5) |
$4 / $20 | $0.0242 | $0.0786 | about $1,512 |
This table keeps the same thinking assumption on every model, to compare prices alone. Real thinking differs: Sonnet 5.5 defaults to a higher effort setting than Haiku 5.5 and Opus 5.5 3. On Haiku 5.5, a prompt over 100,000 tokens pays five times these prices.
Opus costs 40 times Haiku for the same summary. Whether Haiku’s summaries are good enough is a quality question for Choosing a model. The arithmetic survives any price change: tokens times price, input and output separately. Prompt caching, batch processing and model routing all cut this bill; Estimating the cost and latency of a feature adds them to the estimate.
Follow-up questions resend everything
Priya reads the summary and asks: “Did Yusuf send a photo of the crack?” Tomás sends that question as a new call.
The new request’s messages hold only Priya’s question. What does the model know about Yusuf’s ticket?Show answer
The Messages API is a : each call stands alone. A conversation exists only because Deskora sends all of it again, every time. The second call looks like this:
{
"model": "claude-haiku-5-5",
"max_tokens": 2000,
"system": "You summarize a support ticket for the agent who picks it up...",
"messages": [
{"role": "user", "content": "Yusuf (customer, 3 Mar): My replacement blender arrived cracked... (all 26 messages)"},
{"role": "assistant", "content": [
{"type": "thinking", "thinking": "", "signature": "EosnCkYI..."},
{"type": "text", "text": "Problem: ...\nTried: ...\nWaiting for: ..."}
]},
{"role": "user", "content": "Did Yusuf send a photo of the crack?"}
]
}The earlier answer goes back as an assistant turn, thinking block included. Claude Haiku 5.5 keeps earlier turns’ thinking in the conversation and bills it as input 2. So the thread is paid for again, and so is the old thinking.
Diagram not drawn yet: deskora-follow-up-history-growth.svg
Three stacked bars, one per call, top to bottom. Call 1: system prompt and thread, 4,150 input tokens. Call 2: the same, plus the first answer’s 300 thinking tokens and 80-token summary, plus a 20-token question: 4,550. Call 3: the same, plus the second answer’s 200 thinking tokens and 40-token answer, plus another 20-token question: 4,810. The thread segment is the same size in every bar and labelled resent.
| Call | Input tokens | Output tokens (assumed) | Cost on Haiku 5.5 |
|---|---|---|---|
| 1: summary | 4,150 | 380 | $0.000605 |
| 2: first question | 4,550 | 240 | $0.000575 |
| 3: second question | 4,810 | 240 | $0.000601 |
| Whole ticket | 13,510 | 860 | $0.00178 |
Two short questions almost triple the ticket’s cost. Sending only the summary and the question would be cheaper, but a summary leaves things out: the photo isn’t in the three lines. Long chats also run into the model’s limit on how much text one call can hold, covered in Context windows.
A first working call in Python
Install the official SDK with pip install anthropic, and put your key in the ANTHROPIC_API_KEY environment variable. The client reads it from there 5.
import anthropic
# claude-haiku-5-5, US dollars per million tokens, as of October 2026
INPUT_PRICE = 0.10 # prompts up to 100,000 tokens
OUTPUT_PRICE = 0.50 # thinking tokens are billed at this price too
SYSTEM = (
"You summarize a support ticket for the agent who picks it up. "
"Write exactly three lines: the problem, what has been tried, "
"and what the customer is waiting for."
)
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from the environment
def summarize(thread: str) -> str:
response = client.messages.create(
model="claude-haiku-5-5",
max_tokens=2000, # room for thinking plus three lines
system=SYSTEM,
messages=[{"role": "user", "content": thread}],
)
usage = response.usage
details = usage.output_tokens_details
thinking = details.thinking_tokens if details else 0
cost = (usage.input_tokens * INPUT_PRICE
+ usage.output_tokens * OUTPUT_PRICE) / 1_000_000
print(f"in={usage.input_tokens} out={usage.output_tokens} "
f"(thinking={thinking}) cost=${cost:.6f}")
if response.stop_reason != "end_turn":
raise RuntimeError(f"No summary: stop_reason={response.stop_reason}")
return "".join(b.text for b in response.content if b.type == "text")
if __name__ == "__main__":
with open("ticket.txt", encoding="utf-8") as f:
print(summarize(f.read()))Put any long email thread in ticket.txt and run it. For a 4,000-token thread, one run costs about $0.0006, and never more than about $0.0014: $0.0004 of input plus at most 2,000 × $0.50 per million of output.
The code checks stop_reason after logging, so cut-off calls still show up in the cost log.
Try it yourself
You can make a small call with curl. It costs about $0.0005 at most, even if the model uses all 1,000 output tokens. If you don’t have an API key, skip this.
curl 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": "Yusuf: My replacement blender arrived cracked. Order 48213.\nLena (agent): Sorry about that. I can refund you today.\nYusuf: I would rather have another replacement. When can you send it?"}]}'One run returned this, shortened; your text and numbers will differ:
{"type":"message","role":"assistant","model":"claude-haiku-5-5","content":[{"type":"thinking","thinking":"","signature":"Ep0C..."},{"type":"text","text":"Problem: ..."}],"stop_reason":"end_turn","usage":{"input_tokens":88,"output_tokens":164,"output_tokens_details":{"thinking_tokens":102},...}}What to look for:
- A
thinkingblock with an emptythinkingfield, or none if the model skipped thinking. thinking_tokensagainstoutput_tokens: the gap is the text you can read.- Change
max_tokensto 50 and run it again. The status is still 200, butstop_reasonis likelymax_tokens, and thetextblock may be cut short or missing.
Where this shows up
- Design: a ticket summary feature turns this call into a full feature: when to summarize, where to store the result, what to show on failure.
- Design: an AI customer support platform runs many such calls per ticket, where cost per task shapes the design.
“About 4,000 tokens” was a guess. The next lesson shows how text becomes tokens, so Tomás can count them before he sends anything.
Common mistakes
- Reading
content[0].text. The first block is often thinking. Keep only the blocks whose type istext. - Sizing
max_tokensfor the visible answer. Thinking spends it first. Leave room, and checkstop_reason. - Trusting the 200 status. A cut-off summary arrives with status 200. Show text only when
stop_reasonisend_turn. - Leaving thinking out of cost estimates. It is billed as output, and earlier turns’ thinking is billed again as input.
Check your understanding
Some Deskora summaries show only one and a half lines, and the HTTP status is always 200. What do you check first?Show answer
A call’s usage shows output_tokens 520 and thinking_tokens 440. How many tokens did Priya see, and what did the output cost on Claude Haiku 5.5?Show answer
Deskora moves the summary from Claude Haiku 5.5 to Claude Opus 5.5, with the same tokens and 40,000 summaries a day. What happens to the daily cost?Show answer
Priya asks five follow-up questions on one ticket. Why does each call cost a little more than the one before?Show answer
Summary
- Tomás sends
model,max_tokens,systemandmessagesin one stateless HTTPS request, and gets back content blocks, astop_reasonandusage; each summary costs input tokens × input price + output tokens × output price. - Read only the
textblocks. Thethinkingblock comes first and is billed as output even when its text is hidden. - Thinking counts toward
max_tokens, so leave room for it, and show text only whenstop_reasonisend_turn. - The API remembers nothing. Each follow-up resends the whole history, earlier thinking included, and pays for it again.
- On Claude Haiku 5.5, as of October 2026, a typical Deskora summary costs about $0.0006 with 300 assumed thinking tokens, and 40,000 a day cost about $38.