lumo

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

  1. Build a Messages API request and say what model, max_tokens, system and messages each control.
  2. Read a response by taking the text from its content blocks, checking stop_reason and recording usage, thinking tokens included.
  3. Work out the cost of one completed summary, and of a day of them, from the formula, with thinking tokens counted.
  4. Explain why every follow-up question resends the whole conversation and pays for it again.

Builds on 2 lessons

Start with lesson 114 min
  1. Introduction to AI engineering14 min
  2. The AI application stack: from model to product11 min

Video 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.

One summary is one HTTPS request from Deskora’s server. The thread goes out as input tokens; thinking and the summary come back as output tokens.

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.

Check yourselfAnswer in your head first, then reveal
The summary Priya reads is about 80 tokens long. Will Deskora pay for about 80 output tokens?Show answerHide answer
Probably for several times more. Claude Haiku 5.5 thinks before it answers by default, and those thinking tokens are billed as output tokens even though Priya never sees them. Not “you pay for the text you see”: the response reports the real count, as the next sections show.

Four fields make a request

Here is Tomás’s request on the wire:

http
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.

json
{
  "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.

Thinking spends the max_tokens budget first. A ceiling sized for the visible summary cuts the summary off.

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:

text
Problem: Yusuf's replacement blender arrived cracked (order 48213).
Tried: Lena offered a refund

The 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.

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.

The three lines Priya reads are the smallest part of the bill. Input is most of it, and hidden thinking costs almost four times the visible text.

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.

Check yourselfAnswer in your head first, then reveal
The new request’s messages hold only Priya’s question. What does the model know about Yusuf’s ticket?Show answerHide answer
Nothing. The API keeps no memory between calls, so the model sees one question with no thread. It may ask which ticket she means, or guess. Not “it remembers the last call”: no conversation is stored on the provider’s side.

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:

json
{
  "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.

Every call resends everything before it, earlier thinking included. The thread is paid for on every turn.
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.

python
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.

bash
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:

json
{"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 thinking block with an empty thinking field, or none if the model skipped thinking.
  • thinking_tokens against output_tokens: the gap is the text you can read.
  • Change max_tokens to 50 and run it again. The status is still 200, but stop_reason is likely max_tokens, and the text block may be cut short or missing.

Where this shows up

“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 is text.
  • Sizing max_tokens for the visible answer. Thinking spends it first. Leave room, and check stop_reason.
  • Trusting the 200 status. A cut-off summary arrives with status 200. Show text only when stop_reason is end_turn.
  • Leaving thinking out of cost estimates. It is billed as output, and earlier turns’ thinking is billed again as input.

Check your understanding

Check yourselfAnswer in your head first, then reveal
Some Deskora summaries show only one and a half lines, and the HTTP status is always 200. What do you check first?Show answerHide answer
The stop_reason. If it is max_tokens, thinking and text together hit the ceiling, so raise max_tokens or reduce thinking, and never show a summary unless stop_reason is end_turn. Not the network: a 200 means the call worked, not that the answer finished.
Check yourselfAnswer in your head first, then reveal
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 answerHide answer
She saw about 80 tokens of summary. Deskora paid for all 520 at the output price: 520 × $0.50 per million = $0.00026. The thinking cost more than five times the visible text.
Check yourselfAnswer in your head first, then reveal
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 answerHide answer
It goes from about $38 to about $1,512, 40 times more, because both Opus prices are 40 times Haiku’s. The split between input, thinking and text stays the same; only the price per token changed.
Check yourselfAnswer in your head first, then reveal
Priya asks five follow-up questions on one ticket. Why does each call cost a little more than the one before?Show answerHide answer
Each call resends the thread, every earlier question and answer, and the earlier thinking, which Haiku 5.5 bills as input. The history only grows. Not because the questions get longer: each one is a few dozen tokens.

Summary

  1. Tomás sends model, max_tokens, system and messages in one stateless HTTPS request, and gets back content blocks, a stop_reason and usage; each summary costs input tokens × input price + output tokens × output price.
  2. Read only the text blocks. The thinking block comes first and is billed as output even when its text is hidden.
  3. Thinking counts toward max_tokens, so leave room for it, and show text only when stop_reason is end_turn.
  4. The API remembers nothing. Each follow-up resends the whole history, earlier thinking included, and pays for it again.
  5. 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.

Report a mistake

Tell us what’s wrong in this lesson and we’ll fix it.