Claude API Tutorial: First Request in curl, Python and TS
Claude API tutorial for 2026: make your first Anthropic API request in curl, Python and TypeScript, then add streaming, multi-turn chat and tool use.
By Claudekit Team Published 8 min read
Quick answer: The Claude API (also called the Anthropic API) is the HTTP interface to Anthropic’s Claude models. You create an API key in the Claude Console, then send a POST request to https://api.anthropic.com/v1/messages with a model ID such as claude-opus-5-5 and a list of messages. Official SDKs for Python and TypeScript wrap the same endpoint.
This tutorial takes you from zero to a working request in curl, Python and TypeScript, then adds the three things every real app needs: conversation history, streaming and tool use. Every code shape below was checked against Anthropic’s official docs on October 24, 2026.
What you need before you start
| Requirement | Where to get it | Notes |
|---|---|---|
| Claude Console account | platform.claude.com | Separate from a Claude.ai chat subscription |
| API credits | Console, Settings, Billing | Most organizations pay with prepaid credits |
| API key | Console, API keys page | Shown once, starts with sk-ant- |
| Python 3 or Node.js | Your machine | Only for the SDK examples |
If you don’t have a key yet, follow our Claude API key guide. It covers creating, storing and rotating keys, plus the errors you’ll see when something is off.
Set the key once in your shell. Both SDKs read ANTHROPIC_API_KEY automatically, so you never paste it into code:
export ANTHROPIC_API_KEY="sk-ant-..."
Step 1: Your first request with curl
Every Claude API call goes through one endpoint: the Messages API.
curl https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1000,
"messages": [
{"role": "user", "content": "Explain what an API rate limit is in two sentences."}
]
}'
Three headers matter:
x-api-keycarries your key. Anthropic’s authentication docs also acceptAuthorization: Bearerwith the key;x-api-keyis the legacy form and still supported.anthropic-version: 2023-06-01pins the API version.content-type: application/json.
The response is JSON. The text lives in a content array of blocks, and usage tells you how many input and output tokens you were billed for:
{
"id": "msg_...",
"type": "message",
"role": "assistant",
"model": "claude-opus-5-5",
"content": [{ "type": "text", "text": "An API rate limit caps..." }],
"stop_reason": "end_turn",
"usage": { "input_tokens": 21, "output_tokens": 48 }
}
To print only the text, pipe the output through jq -r '.content[] | select(.type == "text") | .text'.
Step 2: The same request in Python
Install the official SDK in a virtual environment:
python3 -m venv .venv && source .venv/bin/activate
pip install anthropic
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
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)
Always check block.type before reading .text. Responses can contain other block types, such as thinking or tool_use, and current models think before answering.
Step 3: The same request in TypeScript
npm init -y
npm pkg set type=module
npm install @anthropic-ai/sdk
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // reads ANTHROPIC_API_KEY
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 it with npx tsx quickstart.ts. Anthropic also publishes official SDKs for Go, Java, C#, PHP and Ruby, plus an ant command-line tool.
Choosing a model
The model field decides capability, speed and price. These are the current models listed on Anthropic’s models overview, with standard API prices as of October 24, 2026:
| Model | API ID | Best for | Input / output per 1M tokens |
|---|---|---|---|
| Claude Fable 5.1 | claude-fable-5-1 | Demanding reasoning, long-horizon agents | $10 / $50 |
| Claude Opus 5.5 | claude-opus-5-5 | Recommended starting point for most work | $4 / $20 |
| Claude Sonnet 5.5 | claude-sonnet-5-5 | Balance of speed and intelligence | $2 / $10 |
| Claude Haiku 5.5 | claude-haiku-5-5 | High-volume classification, extraction, routing | From $0.10 / from $0.50 |
All four have a 1M-token context window and up to 128K output tokens. Our Claude models explained guide covers how to pick, and the Claude API pricing guide works through real cost examples, including caching and batch discounts.
One API detail worth knowing: Opus 5.5 always uses adaptive thinking, and you steer depth with the effort parameter (its default is medium). You don’t need to set anything for a first request.
Step 4: System prompts and multi-turn conversations
The API is stateless. Claude does not remember earlier requests, so you send the whole conversation every time. Put stable instructions in system and alternate user and assistant turns in messages:
history = [
{"role": "user", "content": "My name is Ana and I write Go."},
{"role": "assistant", "content": "Nice to meet you, Ana. How can I help with Go?"},
{"role": "user", "content": "Suggest a name for a CLI that renames photos."},
]
reply = client.messages.create(
model="claude-opus-5-5",
max_tokens=1000,
system="You are a concise senior engineer. Answer in at most three bullet points.",
messages=history,
)
To continue, append Claude’s reply as an assistant message, then add the next user message. Two rules save debugging time:
- The last message must be from the user. Current models reject “prefilled” assistant turns with a 400 error.
- Append the full
contentof each reply, not just the text, once you use tools or thinking.
For writing better system prompts, see our Claude prompting best practices.
Step 5: Stream the response
Long answers take time. Streaming sends text as it’s generated over server-sent events, so users see output immediately, and it avoids timeouts on large max_tokens values. Anthropic recommends streaming for long-running requests.
Python:
with client.messages.stream(
model="claude-opus-5-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Write a short story about a lighthouse."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
TypeScript:
const stream = client.messages.stream({
model: "claude-opus-5-5",
max_tokens: 64000,
messages: [{ role: "user", content: "Write a short story about a lighthouse." }],
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}
If you only want the finished message without handling events, call stream.get_final_message() in Python or await stream.finalMessage() in TypeScript. With curl, add "stream": true to the body and you’ll get raw events.
Step 6: Tool use basics
Tool use (function calling) lets Claude ask your code to do something: look up an order, query a database, call another API. The round trip has four parts:
- You describe a tool with a name, description and JSON Schema
input_schema. - Claude replies with
stop_reason: "tool_use"and atool_useblock containing arguments. - Your code runs the function.
- You send the output back in a
tool_resultblock that references thetool_useblock’sid.
import anthropic
client = anthropic.Anthropic()
tools = [{
"name": "get_weather",
"description": "Get the current weather for a given location.",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City and state, e.g. San Francisco, CA"}
},
"required": ["location"],
},
}]
messages = [{"role": "user", "content": "What's the weather in San Francisco?"}]
response = client.messages.create(
model="claude-opus-5-5", max_tokens=1024, tools=tools, messages=messages
)
if response.stop_reason == "tool_use":
tool_use = next(b for b in response.content if b.type == "tool_use")
weather = "15 degrees Celsius, partly cloudy" # call your real weather service here
messages += [
{"role": "assistant", "content": response.content},
{"role": "user", "content": [
{"type": "tool_result", "tool_use_id": tool_use.id, "content": weather}
]},
]
followup = client.messages.create(
model="claude-opus-5-5", max_tokens=1024, tools=tools, messages=messages
)
print(next(b.text for b in followup.content if b.type == "text"))
A few things the docs call out:
- These are client tools: your app runs them. Server tools such as web search, web fetch and code execution run on Anthropic’s infrastructure; you just declare them.
- On Opus 5.5 and Sonnet 5.5, forcing a specific tool with
tool_choiceset toanyortoolreturns a 400. Leave the defaultautoand describe the tool clearly, or addstrict: trueto the tool definition for schema-valid inputs. - To skip writing the loop yourself, the SDKs include a tool runner helper that executes your functions and sends results back automatically.
Want Claude to reach tools that already exist as MCP servers? Read what is MCP, then build an MCP server in TypeScript.
Step 7: Errors, retries and rate limits
The API returns JSON errors with a type, a message and a request_id. The ones you’ll meet first:
| Status | Error type | Usual cause |
|---|---|---|
| 400 | invalid_request_error | Malformed body, unsupported parameter, or a spend limit you set |
| 401 | authentication_error | Missing, malformed, revoked or expired key |
| 402 | billing_error | Payment or billing problem |
| 403 | permission_error | Key lacks access to the resource or workspace |
| 429 | rate_limit_error | Rate limit or monthly spend cap reached |
| 529 | overloaded_error | API temporarily overloaded |
The official SDKs retry connection errors, 429s and 5xx errors twice by default with exponential backoff, honouring the retry-after header. Catch the SDK’s typed exceptions (for example anthropic.RateLimitError) rather than matching error strings.
Rate limits are set per organization by usage tier and measured in requests, input tokens and output tokens per minute. Cached input tokens don’t count toward the input limit on most models, which makes prompt caching a cheap way to raise throughput. Check your tier on the Console’s rate limits page.
Where to go next
| Goal | Feature | Why it matters |
|---|---|---|
| Cut cost on repeated context | Prompt caching | Cache reads cost a fraction of base input price |
| Process thousands of requests | Message Batches API | 50% off, results arrive asynchronously |
| JSON you can parse safely | Structured outputs | Constrains the response to your schema |
| An agent with file and shell tools | Claude Agent SDK | The Claude Code harness as a library |
| A hosted agent | Managed Agents | Anthropic runs the loop and the sandbox |
Our Claude agents guide explains when to move from plain API calls to the Agent SDK or Managed Agents. If you’d rather have Claude write the integration for you, the Claude API skill gives Claude Code up-to-date SDK patterns, and what is Claude Code explains the agent itself.
For the canonical reference, Anthropic’s get started guide and models overview are the sources we checked this page against.
Frequently asked questions
Is the Claude API the same as the Anthropic API?
Yes. Anthropic's docs call it the Claude API and note that its keys are also called Anthropic API keys. Requests go to api.anthropic.com, and the official SDKs are the anthropic package on PyPI and @anthropic-ai/sdk on npm.
Is the Claude API free?
No. The API is billed per token, separately from Claude.ai subscriptions. Most organizations buy prepaid credits in the Claude Console. As of October 24, 2026, Claude Opus 5.5 costs $4 per million input tokens and $20 per million output tokens.
Which model ID should I use?
Anthropic's models overview recommends starting with Claude Opus 5.5 (claude-opus-5-5) for most workloads. Use claude-sonnet-5-5 for a faster, cheaper balance, claude-haiku-5-5 for high-volume simple tasks, and claude-fable-5-1 for the hardest long-horizon work.
Do I need a Claude Pro subscription to use the API?
No. A Claude Pro plan covers the Claude apps and Claude Code, not API calls. The API needs a Claude Console account with credits and an API key, billed per token. Max and Team plans include a monthly allowance of API credits.