Claude API tutorial: from first call to tools in Python and TypeScript

Claude API tutorial: from first call to tools in Python and TypeScript

To use the Claude API, create a key in the Claude Console, install the official Python or TypeScript SDK, and send a request to the Messages API with a model, a token limit and your messages. This tutorial goes from that first call to conversations, streaming, tool use, structured output and keeping costs under control, with code for both languages.

In shortTL;DR
  • Every Claude API feature goes through one endpoint, POST /v1/messages; the SDKs read your key from ANTHROPIC_API_KEY.
  • The API is stateless, so you send the whole conversation each time and control behavior with a system prompt.
  • Use streaming for long outputs, tools to let Claude call your functions, and messages.parse for validated JSON.
  • As of October 2026, Claude Opus 5.5 costs $4 per million input tokens and $20 per million output tokens; Haiku 5.5 is the cheapest current model.
  • Prompt caching, the 50% Batch API discount and a lower effort setting are the main levers for cutting cost.

What do you need to start this Claude API tutorial?

You need a Claude Console account, an API key, and either Python 3 or Node.js with the official SDK installed. Everything else in this Claude API tutorial builds on one endpoint, POST /v1/messages.

  1. Create an account at the Claude Console and add credits under billing. API usage is billed per token, separately from Claude.ai subscriptions.

  2. Create an API key in the Console and export it. Both SDKs read it automatically:

    terminal
    export ANTHROPIC_API_KEY="your-api-key-here"
  3. Install the SDK for your language, as shown in the official get started guide:

    Python
    python3 -m venv .venv && source .venv/bin/activatepip install anthropic
    TypeScript
    npm init -ynpm pkg set type=modulenpm install @anthropic-ai/sdk

Claude API vs Claude.ai vs Claude Code

The Claude API is for developers who want Claude inside their own software. If you only want to chat with Claude or have it write code for you, a different product fits better, and the billing differs.

ProductWhat it isWho pays how
Claude APIProgrammatic access to Claude models from your codePer token, prepaid credits in the Console
Claude.aiChat app on web, desktop and mobileMonthly subscription or free tier
Claude CodeCoding agent in your terminal, IDE or browserA Claude subscription or an API key
Claude Agent SDKClaude Code packaged as a library for your own agentsAPI usage

Pick the API when you need Claude to answer customers, process documents, classify data or power a feature, and you want control over prompts, models and cost per request.

Warning

Never put your API key in frontend code or commit it to a repository. Call the API from your server and keep the key in an environment variable or secrets manager.

How do you make your first Claude API call?

Your first call creates a client, sends one user message with a model name and a max_tokens limit, and prints the text blocks in the response. The examples use claude-opus-5-5, the current Opus model.

quickstart.py
import anthropicclient = anthropic.Anthropic()message = client.messages.create(    model="claude-opus-5-5",    max_tokens=1000,    messages=[{"role": "user", "content": "Explain what an API rate limit is in two sentences."}],)for block in message.content:    if block.type == "text":        print(block.text)
quickstart.ts
import Anthropic from "@anthropic-ai/sdk";const client = new Anthropic();const message = await client.messages.create({  model: "claude-opus-5-5",  max_tokens: 1000,  messages: [{ role: "user", content: "Explain what an API rate limit is in two sentences." }],});for (const block of message.content) {  if (block.type === "text") console.log(block.text);}

Run them with python quickstart.py or npx tsx quickstart.ts. If you get an authentication error, check that ANTHROPIC_API_KEY is exported in the same terminal session, and that your Console account has credits.

Three parameters are required on every request: model, max_tokens and messages. max_tokens is a ceiling on the reply length, not a target; if Claude hits it, the response stops mid-sentence with stop_reason set to max_tokens. Set it generously for open-ended tasks and tightly for short ones such as classification.

The response is a message object. The parts you will use most:

FieldWhat it holds
contentA list of blocks: text, and also thinking or tool_use when relevant
stop_reasonWhy generation stopped: end_turn, max_tokens, tool_use, pause_turn, refusal
usageinput_tokens and output_tokens for this call, which is what you pay for
modelThe model that answered

Always loop over content and check each block's type instead of assuming the first block is text.

How do conversations and system prompts work?

The Messages API is stateless: it remembers nothing between calls, so you send the full conversation history every time. You set the assistant's role and rules with a separate system parameter.

conversation.py
history = [    {"role": "user", "content": "My project uses PostgreSQL 16."},    {"role": "assistant", "content": "Got it. What would you like to do with it?"},    {"role": "user", "content": "Write a query that finds duplicate emails in a users table."},]response = client.messages.create(    model="claude-opus-5-5",    max_tokens=2000,    system="You are a senior database engineer. Answer with SQL first, then one short explanation.",    messages=history,)

Rules worth knowing, from Working with the Messages API:

  • To continue a chat, append the assistant's reply and the next user message, then call again.
  • Put stable instructions in system, not in every user message.
  • Current models do not support prefilling the assistant's reply; use the system prompt or structured output to control format.

Because you resend history, long chats grow expensive. Trim old turns, summarize them, or use prompt caching, covered below.

How do you stream responses from the Claude API?

Stream when output is long or when a user is waiting, so text appears as it is generated instead of after the whole response finishes. The SDKs provide a stream helper that also gives you the final message.

stream.py
with client.messages.stream(    model="claude-opus-5-5",    max_tokens=64000,    messages=[{"role": "user", "content": "Write a 500-word guide to code review etiquette."}],) as stream:    for text in stream.text_stream:        print(text, end="", flush=True)    final = stream.get_final_message()print("\nOutput tokens:", final.usage.output_tokens)
stream.ts
const stream = client.messages.stream({  model: "claude-opus-5-5",  max_tokens: 64000,  messages: [{ role: "user", content: "Write a 500-word guide to code review etiquette." }],});for await (const event of stream) {  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {    process.stdout.write(event.delta.text);  }}const final = await stream.finalMessage();console.log("\nOutput tokens:", final.usage.output_tokens);

Streaming also avoids HTTP timeouts. The SDKs expect streaming for very large max_tokens values; current models support up to 128K output tokens.

How does tool use work in the Claude API?

Tool use lets Claude ask your code to run a function: you describe tools with a name, a description and a JSON Schema for inputs, Claude replies with a tool_use block when it wants one, you run the function, and you send the result back. Repeat until Claude stops asking for tools.

tools.py
import anthropicclient = anthropic.Anthropic()tools = [{    "name": "get_order_status",    "description": "Look up the shipping status of an order by its ID.",    "input_schema": {        "type": "object",        "properties": {"order_id": {"type": "string", "description": "Order ID like A-1234"}},        "required": ["order_id"],    },}]def get_order_status(order_id: str) -> str:    return f"Order {order_id} shipped on Oct 18 and arrives Oct 22."  # call your real system heremessages = [{"role": "user", "content": "Where is my order A-1234?"}]while True:    response = client.messages.create(        model="claude-opus-5-5", max_tokens=4000, tools=tools, messages=messages    )    if response.stop_reason != "tool_use":        break    messages.append({"role": "assistant", "content": response.content})    results = []    for block in response.content:        if block.type == "tool_use":            output = get_order_status(**block.input)            results.append({"type": "tool_result", "tool_use_id": block.id, "content": output})    messages.append({"role": "user", "content": results})print(next(b.text for b in response.content if b.type == "text"))

How the loop works: Claude reads the user message and the tool descriptions, decides it needs order data, and returns a tool_use block with the arguments it chose. Your code runs the function and sends the output back as a tool_result. Claude then writes the final answer using that output. Claude never runs your code itself; it only asks, which is why you stay in control of what each tool can do.

The TypeScript version has the same shape: define tools as Anthropic.Tool[], loop while stop_reason === "tool_use", and push tool_result blocks with the matching tool_use_id.

Things that trip people up:

  • Return all results in one user message when Claude calls several tools at once.
  • Report failures with a tool_result that sets is_error: true, instead of dropping it.
  • Write clear tool descriptions. Claude decides when to call a tool based on its description.
  • Do not force a specific tool on the newest models. Claude Opus 5.5 rejects tool_choice values of any or tool; use auto and say in the prompt which tool to use.
  • Treat tool inputs as untrusted. Validate them before touching files, databases or shells.

The SDKs also include a beta tool runner that handles this loop for you. To grow this into a full agent with memory and guardrails, follow build an AI agent in Python.

How do you get structured JSON output from Claude?

Use structured outputs to make Claude return data that matches a schema you define. The SDKs' messages.parse helper takes a Pydantic model (Python) or a Zod schema (TypeScript) and returns a validated object.

extract.py
from pydantic import BaseModelclass Lead(BaseModel):    name: str    email: str    company_size: int    wants_demo: boolresponse = client.messages.parse(    model="claude-opus-5-5",    max_tokens=2000,    messages=[{"role": "user", "content": "Extract: Ana Ruiz (ana@acme.io), 40 people, asked for a demo."}],    output_format=Lead,)lead = response.parsed_outputprint(lead.email, lead.wants_demo)
extract.ts
import { z } from "zod";import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";const Lead = z.object({  name: z.string(),  email: z.string(),  company_size: z.number(),  wants_demo: z.boolean(),});const response = await client.messages.parse({  model: "claude-opus-5-5",  max_tokens: 2000,  messages: [    { role: "user", content: "Extract: Ana Ruiz (ana@acme.io), 40 people, asked for a demo." },  ],  output_config: { format: zodOutputFormat(Lead) },});console.log(response.parsed_output?.email);

Structured output is the right choice whenever another program consumes the answer: filling a CRM record, routing a ticket, or feeding a database. It removes the need to strip markdown fences or retry on malformed JSON. Keep schemas small and specific, and give fields descriptive names, because Claude uses the names as hints about what goes where.

Without a helper, pass a JSON Schema in output_config.format on a normal messages.create call. On messages.create, the older top-level output_format parameter is deprecated in favor of output_config (the Python parse helper still takes output_format as shown above).

Which Claude model should you use, and what does it cost?

Use Claude Opus 5.5 as the default for quality, and test Sonnet 5.5 or Haiku 5.5 when cost or speed matters more. Prices below are from the Claude pricing page at the time of writing (October 2026), in US dollars per million tokens.

ModelModel IDInputOutputCache readGood for
Claude Opus 5.5claude-opus-5-5$4$20$0.20Agents, complex coding, hard reasoning
Claude Sonnet 5.5claude-sonnet-5-5$2$10$0.10Everyday coding and high-volume assistants
Claude Haiku 5.5 (prompts up to 100K tokens)claude-haiku-5-5$0.10$0.50$0.01Classification, extraction, routing
Claude Fable 5.1claude-fable-5-1$10$50$0.25The most demanding long-horizon work

Haiku 5.5 charges more for prompts over 100,000 tokens ($0.50 input, $2.50 output). Current models accept up to 1 million tokens of context; check the models overview for limits and new releases.

On current models, Claude decides how much to think, and you control the depth with effort. Claude Opus 5.5 defaults to medium; use low for simple, high-volume tasks and high or above for hard problems:

effort.py
response = client.messages.create(    model="claude-opus-5-5",    max_tokens=4000,    output_config={"effort": "low"},    messages=[{"role": "user", "content": "Classify this ticket as billing, bug or other: 'I was charged twice.'"}],)

How do you keep Claude API costs down?

Cut Claude API costs by caching repeated context, batching work that can wait, choosing the right model and effort, and sending less text. Measure with the usage field on every response.

  • Prompt caching. Mark a long, stable prefix (system prompt, documents, tool definitions) with cache_control. Per the prompt caching docs, cached reads cost a fraction of normal input; on Opus 5.5 that is $0.20 instead of $4 per million tokens.
  • Batch API. Requests that do not need an immediate answer, such as nightly jobs, get a 50% discount on input and output.
  • Smaller models for simple steps. Route classification and extraction to Haiku 5.5.
  • Lower effort for routine tasks.
  • Trim context. Do not resend whole documents or long histories when a summary or the relevant chunk will do.
  • Count before you send. client.messages.count_tokens(...) tells you the input size before you pay for a request.
cache.py
response = client.messages.create(    model="claude-opus-5-5",    max_tokens=2000,    system=[{"type": "text", "text": LONG_PRODUCT_MANUAL, "cache_control": {"type": "ephemeral"}}],    messages=[{"role": "user", "content": "How do I reset the device to factory settings?"}],)print(response.usage.cache_read_input_tokens)

The guide on how to reduce LLM API costs goes deeper into routing and measuring cost per task.

How do you handle errors and stop reasons?

Handle errors with the SDK's typed exceptions and always check stop_reason before trusting the output. The SDKs already retry connection errors, 429 rate limits and server errors twice by default with backoff.

errors.py
try:    response = client.messages.create(model="claude-opus-5-5", max_tokens=1000, messages=messages)except anthropic.RateLimitError:    print("Rate limited after retries; slow down or queue the request.")except anthropic.APIStatusError as e:    print(f"API error {e.status_code}: {e.message}")except anthropic.APIConnectionError:    print("Network problem reaching the API.")else:    if response.stop_reason == "max_tokens":        print("Output was cut off; raise max_tokens or stream.")    elif response.stop_reason == "refusal":        print("The request was declined:", response.stop_details)

TypeScript exposes the same classes, such as Anthropic.RateLimitError and Anthropic.APIError, with a status field. For production, log usage and stop_reason on every call; they explain most cost spikes and odd outputs.

Next steps after this Claude API tutorial

  1. Make the first call in your language and print usage.
  2. Add a system prompt and a two-turn conversation.
  3. Switch to streaming for anything user-facing.
  4. Add one tool that calls a real function in your app.
  5. Use messages.parse wherever you need JSON.
  6. Try your task on Sonnet 5.5 and Haiku 5.5, and compare quality and cost.
  7. Add prompt caching for any prefix you send repeatedly.

If you want Claude's built-in file, shell and search tools instead of writing your own, the Claude Agent SDK guide covers the agent loop behind Claude Code. And if your goal is to have an agent write code for you rather than call the API from your app, the Claude Code tutorial is the place to start; Orkio can keep such agents running on an always-on box with your own Claude account.

Frequently asked questions

Is the Claude API free?

No. The API is billed per token, separately from Claude.ai subscriptions, and you buy credits in the Claude Console. Prices depend on the model; at the time of writing Claude Haiku 5.5 costs $0.10 per million input tokens for prompts up to 100,000 tokens, and Claude Opus 5.5 costs $4.

Can I use my Claude Pro or Max subscription for the API?

Claude.ai plans and API usage are billed separately, so a Pro or Max subscription does not include API credits. Some Anthropic tools, such as Claude Code, can run on either a subscription or an API key. For your own applications, create an API key in the Console.

Which Claude model should I use with the API?

Start with Claude Opus 5.5 for quality, then test whether Sonnet 5.5 or Haiku 5.5 holds up on your task at lower cost. Classification and extraction often work well on Haiku; agents and complex coding benefit from Opus. Measure on real examples before switching.

What is the context window of the Claude API?

Current Claude models such as Opus 5.5, Sonnet 5.5 and Haiku 5.5 accept up to 1 million tokens of context. Large prompts cost more and take longer, so send only what the task needs, and use prompt caching for content you send repeatedly.

How do I keep my Claude API key safe?

Store it in an environment variable or a secrets manager, never in source code or frontend JavaScript. Call the API from your server, not from the browser, so users never see the key. Rotate keys you suspect have leaked from the Console.

SOURCES

  1. Claude docs: Get started
  2. Claude docs: Pricing
  3. Claude docs: Models overview
  4. Claude docs: Working with the Messages API
  5. Claude docs: Prompt caching
  • #claude api
  • #anthropic sdk
  • #python
  • #typescript
  • #llm development
Orkio team

The team building Orkio. We write about putting AI to work: coding agents that run overnight, always-on boxes and pull requests ready by morning.

Keep reading

All posts

07:06 · YOU MERGED #128

Go to sleep. Wake up to pull requests.

Start for $19 a month
© 2026 Orkio · Hosted in Europe TürkçeStatus