Claude API Intro

Su Suriya Ravichandran Updated 10 Nov 2026
16 min read ·Lesson 2 of 200

What Is the Claude API?

The Claude API is the service your programs talk to when they use Claude. Your program sends a question over the internet, Claude's servers process it, and the answer comes back as data your program can use.

Technically, the Claude API is a RESTful HTTP API hosted at:

https://api.anthropic.com

Each capability is exposed as an endpoint: a URL path combined with an HTTP method. For example, sending a message to Claude is:

POST https://api.anthropic.com/v1/messages
  • POST is the HTTP method. It means "send data to the server and ask it to create something", here a new message from Claude.
  • /v1/ is the URL version prefix.
  • messages is the resource you are working with.

Requests and responses use JSON, a plain-text data format that maps directly to Python dictionaries and lists.

The Anthropic Python SDK from Lesson 1 is a wrapper around this API. Everything the SDK does ends up as an HTTP request to one of these endpoints. Understanding the API itself helps you read error messages, debug problems, and make sense of the SDK's design.


The Claude API vs. the Claude App

The most common beginner confusion is between the Claude app and the Claude API.

Claude app (web, desktop, mobile)Claude API
What it isA finished chat productA programmable service
Who uses itPeople typing in a chat windowPrograms written by developers
InterfaceGraphical chat windowHTTP requests and JSON
AccountClaude app account and planClaude Console account at platform.claude.com
BillingApp subscription plansPay per use, measured in tokens
Conversation memoryThe app keeps your chat historyYou send the conversation history yourself with each request
CustomizationApp settingsFull control of prompts, models, limits, and tools

An app subscription does not include API access, and API usage is not covered by an app plan. They are separate products with separate billing.

Why both exist: the app is for using Claude directly. The API is for building Claude into your own software, such as a support chatbot on your website, a tool that summarizes uploaded documents, or a backend that extracts data from emails.


How a Request Works

Every interaction with the Claude API follows the same request-response cycle:

┌──────────────┐   1. HTTPS request (headers + JSON body)   ┌──────────────┐
│ Your program │ ─────────────────────────────────────────► │  Claude API  │
│              │                                            │              │
│              │ ◄───────────────────────────────────────── │  (runs the   │
└──────────────┘   2. HTTPS response (status + JSON body)   │    model)    │
                                                            └──────────────┘
  1. Your program sends an HTTPS request. Headers carry metadata such as your credentials and the API version. The body contains the JSON describing what you want.
  2. The API authenticates you, validates the request, runs the Claude model, and sends back a response. The status code indicates success (200) or the kind of failure (400, 401, 429, …). The body contains Claude's reply or an error description.

A Complete Request with cURL

curl is a command-line tool for sending HTTP requests. It is installed by default on macOS, most Linux distributions, and current versions of Windows. Showing the request with curl makes every part of it visible:

curl https://api.anthropic.com/v1/messages \
  -H "Authorization: Bearer $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2026-10-21" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "What is an API? Answer in one sentence."}
    ]
  }'

Note: This uses macOS/Linux shell syntax. $ANTHROPIC_API_KEY reads an environment variable that must already contain your key (Lessons 6 and 7 show how). The trailing `` continues the command onto the next line.

Line-by-line explanation:

PartMeaning
curl https://api.anthropic.com/v1/messagesSend a request to the Messages endpoint. curl uses POST automatically because a body (-d) is provided.
-H "Authorization: Bearer $ANTHROPIC_API_KEY"Proves who you are. Bearer means "the token that follows is my credential".
-H "anthropic-version: 2026-10-21"Declares which version of the API's request/response format your code expects.
-H "content-type: application/json"Tells the server the body is JSON.
-d '{...}'The request body.
"model"Which Claude model should answer.
"max_tokens"The maximum length of the output, in tokens, including any thinking the model does.
"messages"The conversation: a list of turns, each with a role and content.

The Response

A successful request returns HTTP status 200 and a JSON body like this (simplified; real responses include a few more fields):

{
  "id": "msg_01XFDUDYJgAACzvnptvVoYEL",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-5-5",
  "content": [
    {
      "type": "text",
      "text": "An API is a defined set of rules that lets one program request data or services from another program."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 18,
    "output_tokens": 24
  }
}
FieldWhat it tells you
idUnique identifier of this message
typeThe object type: always "message" for a successful reply
role"assistant": the message was written by Claude
modelThe model that generated the reply
contentA list of content blocks. Here there is one text block. With current models, the list can also start with a thinking block (the model's internal reasoning) before the text, and later lessons cover other block types, such as tool calls.
stop_reasonWhy Claude stopped. end_turn means it finished naturally; max_tokens means it hit your limit.
stop_sequenceThe custom stop text that ended generation, if any (Lesson 48)
usageHow many tokens you sent (input_tokens) and received (output_tokens, which includes any thinking). These numbers determine cost.

Why content is a list, not a string: a single reply can contain several kinds of output, such as reasoning, text, and a request to call a tool. A list of typed blocks can represent all of these consistently. Because a thinking block can come first, code must find the text blocks by their type instead of assuming the first block is text. This is why Lesson 1 looped over message.content.


Request Headers in Detail

Headers are key-value metadata sent with every request. The Claude API uses these:

HeaderValueRequired?
AuthorizationBearer <your API key>Yes, unless x-api-key is sent
x-api-key<your API key>Legacy alternative to Authorization; still supported
anthropic-versionAn API version such as 2026-10-21Yes
content-typeapplication/jsonYes, for requests with a JSON body
anthropic-workspace-idA workspace ID such as wrkspc_01Jw…Only for API keys that are not scoped to a single workspace (Lesson 6)

Authentication: Authorization and x-api-key

Both headers carry the same API key. Authorization: Bearer <key> is the current standard form, and x-api-key: <key> is the older form that the API still accepts. New code should use Authorization.

Note: The Python SDK sends Authorization: Bearer <key> starting with version 2.0.0. Earlier SDK versions sent x-api-key. This only matters if a proxy or gateway in your infrastructure inspects one of these headers (see Lesson 5).

What happens if authentication is missing or wrong: the API returns status 401 with an authentication_error, and no model runs. You are not billed for requests that fail authentication.

API Versioning: anthropic-version

The API evolves over time. When Anthropic makes a change that would break existing code, such as removing a parameter, it publishes a new API version, identified by a date. Your request states which version it was written for, and the API behaves according to that version.

API versionNotes
2023-06-01Long-standing version, sent by SDK releases before Python SDK 2.0.0
2026-10-21Current version, sent by Python SDK 2.0.0 and later

Why the header exists: it lets Anthropic improve the API without breaking applications that were written years ago. Your code changes behavior only when you move to a new version.

What happens if you omit it: the request is rejected with an error. What happens if you change it: the request and response format of that version applies. For example, 2026-10-21 rejects the temperature, top_p, and top_k parameters that 2023-06-01 accepted (Lesson 19).

When you use the SDK, this header is set automatically to match your SDK's major version.


The APIs Available

"The Claude API" is a family of related APIs that share the same base URL, authentication, and conventions:

APIEndpointPurposeLessons
MessagesPOST /v1/messagesSend a conversation and receive Claude's reply11–30
Token CountingPOST /v1/messages/count_tokensCount input tokens before sending a request44–46
Message BatchesPOST /v1/messages/batchesProcess large numbers of requests asynchronously, at a 50 percent cost reduction131–140
ModelsGET /v1/modelsList available models and their details12
FilesPOST /v1/files, GET /v1/filesUpload files once and reference them in many requests115–116

The Messages API is the core of almost everything in this tutorial. Streaming, tool use, vision, structured output, prompt caching, and thinking are all features of the Messages API, controlled through its request parameters.


Statelessness: The API Does Not Remember

A standard Messages API request is stateless: the API does not remember earlier requests. Each request must contain everything Claude needs to answer it.

This surprises developers who are used to the Claude app, where the chat "remembers" what you said. In the API, if you want Claude to know about a previous question and answer, you must send them again:

{
  "model": "claude-opus-5-5",
  "max_tokens": 1024,
  "messages": [
    {"role": "user", "content": "My name is Priya."},
    {"role": "assistant", "content": "Nice to meet you, Priya!"},
    {"role": "user", "content": "What is my name?"}
  ]
}

Claude can answer "Priya" only because the earlier turns are included in this request. If you sent only the last message, Claude would have no way of knowing.

Why the API is designed this way:

  • Control. You decide exactly what context Claude sees. You can edit, shorten, or summarize the history.
  • Simplicity and scale. The server does not need to store a session for every user of every application.
  • Predictability. The same request produces a reply based only on what is in it.

The trade-off: your application stores the history, and longer histories mean more input tokens and therefore higher cost. Lessons 24–28 and 62–64 show how to manage this.


Tokens: How Usage Is Measured

A token is a small piece of text, usually a word or part of a word. Models read and write text as tokens, and the API measures usage in tokens:

  • Input tokens: everything you send, including the system prompt, the conversation history, and any documents or images.
  • Output tokens: everything Claude generates, including thinking that is not shown in the response.

Tokens matter for three practical reasons:

  1. Cost. API pricing is per token, with separate rates for input and output, and rates vary by model. Current prices are listed on Anthropic's pricing page (and in Lesson 12).
  2. Limits. max_tokens caps the length of the output, including thinking. Each model also has a maximum context window, which is the total number of tokens it can consider at once.
  3. Rate limits. Your account can process only a certain number of tokens per minute (described below).

The usage field in each response tells you exactly how many tokens were used. Lessons 13 and 44–47 cover counting and controlling tokens.


Errors

When a request fails, the API returns a non-200 status code and a JSON error body with a consistent structure:

{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "The requested resource could not be found."
  },
  "request_id": "req_011CSHoEeqs5C35K2UUqR7Fy"
}
  • error.type is a machine-readable category you can branch on in code.
  • error.message is a human-readable explanation.
  • request_id identifies this exact request. Include it when you contact Anthropic support.

The exact message text varies; the structure is what your code should rely on.

Common error types:

Statuserror.typeTypical causeRetry?
400invalid_request_errorMalformed request, missing or unsupported parameterNo: fix the request
401authentication_errorMissing, invalid, or expired API keyNo: fix the key
402billing_errorA problem with billing or payment detailsNo: fix billing in the Console
403permission_errorThe key lacks permission for this actionNo
404not_found_errorUnknown resource, such as a misspelled model nameNo
413request_too_largeRequest body exceeds the size limitNo: reduce the size
429rate_limit_errorToo many requests or tokens per minuteYes, after a delay
500api_errorUnexpected error on Anthropic's sideYes
529overloaded_errorThe API is temporarily overloadedYes, after a delay

Why the distinction matters: client errors (4xx, except 429) mean your request is wrong, and sending it again will fail the same way. Rate-limit and server errors are usually temporary, so retrying after a short wait often succeeds. The SDK uses this distinction to decide what to retry automatically (Lesson 1).


Response Headers

Besides the body, every response includes useful headers:

HeaderMeaning
request-idGlobally unique ID of the request, for debugging and support
anthropic-organization-idThe organization the API key belongs to
anthropic-workspace-idThe workspace the request ran in

Rate-limit headers are also included. They report how much of your limit remains, and Lesson 142 uses them.


Limits: Rate Limits, Spend Limits, and Request Size

Rate Limits and Spend Limits

To protect capacity and prevent runaway costs, each organization has limits based on its usage tier. Organizations start on a tier automatically and can move up over time:

  • Rate limits: the maximum requests per minute and tokens per minute.
  • Spend limits: the maximum monthly cost of API usage.

You can see your current limits in the Claude Console under Rate limits, and spend limits on the Billing page. Exceeding a rate limit returns a 429 error.

Request Size Limits

EndpointMaximum request size
Messages, Token Counting128 MB
Message Batches256 MB
Files500 MB

A larger request returns 413 request_too_large. Cloud platforms such as Amazon Bedrock have their own, smaller limits.


Direct API vs. Cloud Platforms

You can reach Claude models in two ways:

Direct Claude APICloud platforms
Whereapi.anthropic.comAmazon Bedrock, Claude Platform on AWS, Google Cloud, Microsoft Foundry
Account and billingClaude Console, billed by AnthropicYour cloud provider account and billing
AuthenticationAPI key (or Workload Identity Federation)The cloud provider's identity system (IAM)
Feature availabilityNewest models and features firstVaries by platform
Best forNew projects, full feature accessOrganizations already committed to a cloud provider

This tutorial uses the direct Claude API. Lessons 161–170 cover the cloud platforms.


The Same Request: Raw HTTP vs. SDK

The raw request in Python, using the requests library:

import os

import requests

response = requests.post(
    "https://api.anthropic.com/v1/messages",
    headers={
        "Authorization": f"Bearer {os.environ['ANTHROPIC_API_KEY']}",
        "anthropic-version": "2026-10-21",
        "content-type": "application/json",
    },
    json={
        "model": "claude-opus-5-5",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": "What is an API? Answer in one sentence."}],
    },
    timeout=60,
)

if response.status_code != 200:
    error = response.json()["error"]
    print(f"Error {response.status_code} ({error['type']}): {error['message']}")
else:
    data = response.json()
    text = "".join(block["text"] for block in data["content"] if block["type"] == "text")
    print(text)
    print("Request ID:", response.headers.get("request-id"))

The same request with the SDK:

import anthropic
from anthropic import Anthropic

client = Anthropic()

try:
    message = client.messages.create(
        model="claude-opus-5-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "What is an API? Answer in one sentence."}],
    )
except anthropic.APIStatusError as error:
    print(f"Error {error.status_code}: {error.message}")
else:
    text = "".join(block.text for block in message.content if block.type == "text")
    print(text)
    print("Request ID:", message._request_id)

How the two map to each other:

Raw API conceptSDK equivalent
URL POST /v1/messagesclient.messages.create()
Authorization headerRead from ANTHROPIC_API_KEY automatically
anthropic-version headerSet automatically by the SDK
JSON body fieldsKeyword arguments (model=, max_tokens=, messages=)
Response JSONA typed Message object
Text blocks: block["type"] == "text" and block["text"]block.type == "text" and block.text
Error body + status codeExceptions such as anthropic.APIStatusError
request-id response headermessage._request_id

Both programs send essentially the same HTTP request. Knowing the raw form lets you understand what the SDK is doing and debug it when something goes wrong.

Note: Both examples collect the text by filtering blocks on their type and joining them, instead of reading content[0]. With current models such as Claude Opus 5.5, the first block can be a thinking block, which has no text field. Position-based access then fails with a KeyError (raw JSON) or AttributeError (SDK). Lesson 16 explains every block type.


Common Mistakes

Expecting the API to Remember Previous Requests

Mistake: sending only the newest user message and expecting Claude to know the earlier conversation.

Why it happens: the Claude app keeps history, so developers assume the API does too.

Result: Claude answers as if the conversation just started. For example, it does not know the user's name mentioned earlier.

Fix: keep the conversation history in your application and send the relevant turns with every request (Lessons 24–26).

Assuming an App Subscription Includes API Access

Mistake: trying to use a Claude app plan for API calls.

Fix: create a Claude Console account at platform.claude.com, set up billing there, and create an API key (Lesson 6).

Retrying Errors That Cannot Succeed

Mistake: automatically retrying every failed request, including 400 and 401 errors.

Result: wasted time and log noise, because the same invalid request fails again every time.

Fix: retry only 429, 5xx, and connection errors. The SDK already does this by default.

Treating content as a String, or Reading content[0]

Mistake: print(data["content"]), string operations on content, or reading content[0] and assuming it is text.

Fix: content is a list of blocks, and the first one may be a thinking block. Read text from the blocks whose type is "text".

Ignoring request_id

Mistake: logging only "request failed".

Fix: always log the request_id (or message._request_id in the SDK). It is the fastest way to investigate a failed or unexpected request with support.


Best Practices

  • Use the SDK for application code. Use raw HTTP for learning, debugging, or languages without an official SDK.
  • Design for statelessness from the start. Decide where conversation history is stored, such as memory, a database, or a cache, and how it is trimmed.
  • Extract text by block type, never by position.
  • Watch usage on every response. Token counts are your cost. Logging them early prevents billing surprises.
  • Branch on error.type and status codes, not on error message text, which can change.
  • Know your limits. Check your rate-limit tier in the Console before load-testing or launching a feature with heavy traffic.
  • Keep the API version deliberate. Upgrade SDK major versions, and therefore API versions, intentionally, with testing (Lesson 5).

Exercise

  1. Using curl or the requests example above, send a request and identify the id, the block types in content, stop_reason, and usage in the response.
  2. Send the request again with "max_tokens": 5. What is the stop_reason now, and what does content contain?
  3. Change the model to "claude-does-not-exist". Which status code and error.type do you get?
  4. Send two separate requests: first "My favorite color is green.", then "What is my favorite color?". Then send one request that contains both turns, with a short assistant reply in between. Explain why the results differ.
Show answers
  1. id starts with msg_. content contains a text block, sometimes preceded by a thinking block. stop_reason is usually end_turn, and usage shows input_tokens and output_tokens.
  2. stop_reason becomes max_tokens, because the 5-token limit was reached before Claude finished. Since thinking also counts toward the limit, content may hold a very short, cut-off text block, or only a thinking block with no text at all.
  3. You receive a 404 status with error.type set to not_found_error, because the model does not exist.
  4. In separate requests, the second request contains no information about your favorite color, because the API is stateless. In the combined request, the earlier turn is part of the input, so Claude can answer "green".

0 Comments

Reviewed before they appear

No comments yet.

Anthropic SDK Using Python
Anthropic SDK Intro Claude API Intro SDK Requirements Install Anthropic SDK Upgrade the SDK Create an API Key Set API Keys Use Environment Variables Import Anthropic Create a Client Send Your First Message Choose a Claude Model Set Max Tokens Read a Response Print Response Text Understand Message Blocks Use System Prompts Send User Messages Set Temperature Handle Stop Reasons Messages API Intro Create Messages Use Message Roles Send Conversation History Continue a Conversation Build a Chat Loop Reset Chat History Use Multiple Turns Inspect Message IDs Read Usage Data Write Clear Prompts Set a System Prompt Add Context to Prompts Use Prompt Templates Add Examples to Prompts Request JSON Output Use XML Tags Control Response Length Improve Prompt Quality Avoid Prompt Injection Read Text Blocks Read Content Blocks Check Stop Reasons Count Input Tokens Count Output Tokens Count Tokens Before Sending Limit Output Tokens Use Stop Sequences Read Request IDs Parse API Responses Streaming Intro Stream Text Output Use Stream Events Use Stream Helpers Get Final Messages Stream Async Responses Handle Stream Errors Build a Live Chat Stream Long Responses Close Streams Safely Build a Chatbot Keep Chat History Manage Chat Sessions Add Chat Memory Build a CLI Chatbot Build a Web Chatbot Use Flask with Claude Use FastAPI with Claude Return JSON from an API Add Chat Error Messages Async SDK Intro Create an Async Client Send Async Messages Use asyncio Run Parallel Requests Stream Async Text Handle Async Errors Set Async Timeouts Close Async Clients Choose Sync or Async Tool Use Intro Define a Tool Create Tool Schemas Send Tools to Claude Read Tool Calls Run Python Tools Return Tool Results Continue After Tool Use Control Tool Choice Handle Tool Errors Use the beta_tool Decorator Create a Tool Runner Add Tool Docstrings Validate Tool Inputs Use Multiple Tools Limit Tool Calls Log Tool Activity Build a Weather Tool Build a Search Tool Build a Calculator Tool Structured Output Intro Request JSON Data Validate JSON Output Use Pydantic Models Handle Invalid JSON Extract Fields from Text Generate Typed Data Use Image URLs Send Base64 Images Read PDFs with Claude Use Output Schemas Build Data Extraction Test Structured Responses Send Image Inputs Upload Files Use File IDs Process Text Files Summarize Documents Extract Table Data Handle File Errors Read Cache Usage Reduce Repeated Input Costs Debug Cache Misses Prompt Caching Intro Enable Prompt Caching Cache System Prompts Cache Long Context Test Cache Performance Use Cache Breakpoints Cache Best Practices Message Batches Intro Create a Message Batch Set Batch IDs Check Batch Status List Message Batches Get Batch Results Process Batch Outputs Handle Failed Batch Items Use Batches for Bulk Tasks Compare Batches and Requests Handle API Errors Handle Rate Limits Retry Failed Requests Set Request Timeouts Handle Network Errors Use Exponential Backoff Build Reliable API Calls Use Extended Thinking Log API Errors Track Request IDs Paginate API Results Set Thinking Budgets Read Thinking Blocks Use Tool Search Use Web Search Tools Use Computer Tools Use Citations Use Token Counting Read Raw Responses Set Custom Headers Use Claude on AWS Bedrock Use Claude on Vertex AI Use Claude on Microsoft Foundry Configure Cloud Credentials Choose a Cloud Provider Compare API Integrations Configure Provider Clients Handle Cloud Errors Use Cloud SDK Extras Deploy Cloud Apps Protect API Keys Use a .env File Ignore Secrets in Git Validate User Input Reduce Prompt Injection Limit Tool Permissions Avoid Unsafe Tool Calls Sanitize Tool Results Set Usage Limits Review Security Logs Test SDK Functions Mock API Responses Test Error Handling Test Streaming Code Measure Token Usage Track API Costs Configure Logging Deploy with Docker Deploy a FastAPI App Monitor Production Apps Build a Claude Chatbot Build a Text Summarizer Build a Code Explainer Build a JSON Extractor Build a PDF Assistant Build a Streaming Chat App Build a Tool-Calling Agent Build a Batch Processor Build a Research Assistant Build a Claude API Dashboard
Ask about this post
AI Ask about this post

Ask questions about Claude API Intro and get answers drawn from it.

Signed-in readers only.