What Is an API?
Start with the simplest possible definition: an API is a way for one program to ask another program to do something.
You have used APIs hundreds of times without knowing it. When you tap "Pay" in a shopping app, the app calls your bank's API. When the weather widget on your phone updates, it is calling a weather API. When you log in with Google, that is an API call.
The restaurant analogy
Imagine you are at a restaurant. You are the customer (the client). The kitchen is the server โ it has all the food and knows how to cook. The menu is the API: it lists exactly what you can order, what information you need to provide (your table number, any allergies), and what you will get back.
You do not need to know how the kitchen works. You just read the menu, place your order, and receive your food.
APIs work the same way. You do not need to understand how Claude generates text. You send a request in the right format, and you get a response.
What Does REST Mean?
REST stands for Representational State Transfer. Do not worry about what that means โ it is an academic term for a set of design principles that most public APIs follow.
The practical meaning of REST is:
Resources โ everything in a REST API is a "resource": a message, a user, a file, an invoice. Each resource has its own URL.
HTTP methods โ you interact with resources using standard HTTP verbs:
| Method | Meaning | Example |
|---|---|---|
| GET | Read a resource | Get a list of messages |
| POST | Create a resource | Send a new message |
| PUT | Replace a resource entirely | Update a user's profile |
| PATCH | Update part of a resource | Change just the email address |
| DELETE | Remove a resource | Delete a message |
Stateless โ each request contains all the information the server needs. The server does not remember your previous request. You have to send your authentication credentials every time.
HTTP Basics
Every API call is an HTTP request. Here is what a request looks like:
POST /v1/messages HTTP/1.1
Host: api.anthropic.com
Content-Type: application/json
x-api-key: sk-ant-api03-...
anthropic-version: 2023-06-01
{
"model": "claude-haiku-4-5-20251001",
"max_tokens": 256,
"messages": [
{"role": "user", "content": "Hello!"}
]
}
Breaking it down:
- Method + path:
POST /v1/messagesโ you are creating a new message. - Host: which server to talk to.
- Headers: metadata about the request.
Content-Typetells the server the body is JSON.x-api-keyis your authentication. - Body: the actual data you are sending, formatted as JSON.
And here is what a response looks like:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"content": [{"type": "text", "text": "Hello! How can I help you today?"}],
"model": "claude-haiku-4-5-20251001",
"stop_reason": "end_turn",
"usage": {"input_tokens": 10, "output_tokens": 12}
}
Status codes
The number at the top of the response tells you whether it worked:
| Code | Meaning | What to do |
|---|---|---|
| 200 | OK | Success. Read the response body. |
| 201 | Created | A new resource was created. |
| 400 | Bad Request | Your request is malformed. Check the error message. |
| 401 | Unauthorized | Your API key is missing or wrong. |
| 403 | Forbidden | Your key is valid but you do not have permission. |
| 404 | Not Found | The URL does not exist. Check for typos. |
| 429 | Too Many Requests | You have hit the rate limit. Wait and retry. |
| 500 | Server Error | Something broke on the API's end. Retry later. |
JSON: The Language of APIs
Almost every modern REST API sends and receives data in JSON (JavaScript Object Notation). It is a text format that is easy for both humans and machines to read.
Here is what JSON looks like:
{
"name": "Yash",
"age": 28,
"is_active": true,
"skills": ["Python", "TypeScript", "MCP"],
"address": {
"city": "Mumbai",
"country": "India"
},
"nickname": null
}
The building blocks are:
- String: text in double quotes โ
"hello" - Number: a number without quotes โ
42,3.14 - Boolean:
trueorfalse - null: the absence of a value
- Array: an ordered list in square brackets โ
["a", "b", "c"] - Object: key-value pairs in curly braces โ
{"key": "value"}
When you call an API, you send JSON in the request body. When the API responds, it sends JSON back. Your code parses that JSON into objects or dictionaries you can work with.
Authentication: API Keys
Most APIs require you to prove who you are before they serve you. The most common mechanism is an API key โ a long random string that identifies your account.
You send the key in a request header. For the Claude API, the header is x-api-key:
x-api-key: sk-ant-api03-abcdef123456...
Never put your API key in code you commit to Git
This is the single most common security mistake beginners make. If you hardcode your key in a Python or JavaScript file and push it to GitHub, bots will find it within minutes and use it to rack up charges on your account.
The right approach is environment variables. Create a file called .env in your project root:
ANTHROPIC_API_KEY=sk-ant-api03-your-key-here
Then add .env to your .gitignore file:
echo ".env" >> .gitignore
Your code reads the key from the environment at runtime:
Python:
import os
api_key = os.environ.get("ANTHROPIC_API_KEY")
Node.js:
const apiKey = process.env.ANTHROPIC_API_KEY;
Getting an Anthropic API Key
- Go to console.anthropic.com.
- Create an account (free).
- Go to API Keys and click Create Key.
- Copy the key and store it in your
.envfile.
You get free trial credits when you sign up. You do not need a credit card to start.
Making Your First API Call with curl
curl is a command-line tool that makes HTTP requests. It is installed by default on macOS and most Linux systems. On Windows, it is included in Git Bash and Windows 10+.
Open your terminal and run this command (replace YOUR_KEY with your actual key):
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: YOUR_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-haiku-4-5-20251001",
"max_tokens": 256,
"messages": [
{"role": "user", "content": "What is 2 + 2? Answer in one sentence."}
]
}'
You should see a JSON response within a second or two. The text Claude generated is inside content[0].text.
Understanding what this command does
-Hadds a header. You are sending three headers: your API key, the API version, and the content type.-dsends data in the request body. The-dflag automatically makes this a POST request.- The URL
https://api.anthropic.com/v1/messagesis the endpoint for sending messages to Claude.
If you see a 401 error, your API key is wrong. If you see a 400 error, there is a syntax problem in your JSON โ check for missing quotes or commas.
Making the Same Call in Python
Install the official Anthropic Python library:
pip install anthropic
Or if you prefer to use a virtual environment (recommended):
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install anthropic python-dotenv
Create a file called hello_claude.py:
import anthropic
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Create the client โ it automatically reads ANTHROPIC_API_KEY from the environment
client = anthropic.Anthropic()
# Send a message
message = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=256,
messages=[
{"role": "user", "content": "What is 2 + 2? Answer in one sentence."}
]
)
# Extract and print the response text
print(message.content[0].text)
print(f"\nTokens used: {message.usage.input_tokens} in, {message.usage.output_tokens} out")
Run it:
python hello_claude.py
Building a simple multi-turn conversation
The Claude API is stateless โ it does not remember previous messages automatically. You maintain the conversation by sending the full history each time:
import anthropic
from dotenv import load_dotenv
load_dotenv()
client = anthropic.Anthropic()
conversation = []
print("Chat with Claude (type 'quit' to exit)\n")
while True:
user_input = input("You: ").strip()
if user_input.lower() == "quit":
break
# Add the user's message to history
conversation.append({"role": "user", "content": user_input})
# Send the full conversation history
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=512,
messages=conversation
)
assistant_text = response.content[0].text
# Add Claude's response to history
conversation.append({"role": "assistant", "content": assistant_text})
print(f"Claude: {assistant_text}\n")
Making the Same Call in JavaScript / Node.js
Install the official Anthropic Node.js library:
npm install @anthropic-ai/sdk dotenv
Create a file called hello-claude.js:
import Anthropic from "@anthropic-ai/sdk";
import "dotenv/config";
// Create the client โ reads ANTHROPIC_API_KEY from the environment
const client = new Anthropic();
async function main() {
const message = await client.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 256,
messages: [
{ role: "user", content: "What is 2 + 2? Answer in one sentence." }
]
});
// Extract the text from the first content block
console.log(message.content[0].text);
console.log(`\nTokens: ${message.usage.input_tokens} in, ${message.usage.output_tokens} out`);
}
main().catch(console.error);
Add "type": "module" to your package.json to use ES module syntax, then run:
node hello-claude.js
Handling errors properly
Production code should always handle errors. The most common ones are:
import Anthropic from "@anthropic-ai/sdk";
import "dotenv/config";
const client = new Anthropic();
async function callClaude(userMessage) {
try {
const response = await client.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 512,
messages: [{ role: "user", content: userMessage }]
});
return response.content[0].text;
} catch (error) {
if (error instanceof Anthropic.APIError) {
if (error.status === 429) {
console.error("Rate limited. Wait before retrying.");
// In production: implement exponential backoff here
} else if (error.status === 401) {
console.error("Invalid API key. Check your ANTHROPIC_API_KEY.");
} else if (error.status >= 500) {
console.error("Anthropic server error. Retry in a moment.");
}
}
throw error;
}
}
callClaude("Explain APIs in one paragraph.").then(console.log);
Rate Limits: What They Are and How to Handle Them
Rate limits cap how many requests you can make per unit of time. The Anthropic API limits vary by tier:
- Free tier: roughly 5 requests per minute.
- Tier 1 (after first payment): significantly higher limits.
- Higher tiers: enterprise-level throughput.
When you exceed the limit, you get a 429 Too Many Requests response. The response includes a Retry-After header with how many seconds to wait.
The right pattern is exponential backoff: wait 1 second, retry. If it fails again, wait 2 seconds. Then 4, then 8, up to a maximum. This prevents your code from hammering the API when it is already overloaded.
import time
import anthropic
client = anthropic.Anthropic()
def call_with_retry(messages, max_retries=5):
wait = 1
for attempt in range(max_retries):
try:
return client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=256,
messages=messages
)
except anthropic.RateLimitError:
if attempt == max_retries - 1:
raise
print(f"Rate limited. Waiting {wait}s...")
time.sleep(wait)
wait *= 2 # Exponential backoff
Common API Mistakes (and How to Avoid Them)
Hardcoding API keys in source code
Already covered โ use environment variables. Check your .gitignore before every commit.
Not handling HTTP errors
Never assume an API call succeeds. Always check the status code or catch exceptions from the SDK. Silent failures lead to bugs that are hard to trace.
Ignoring the usage field
The usage object in the response tells you exactly how many tokens were consumed. Log it during development so you understand your costs and can spot unexpectedly large requests.
Sending the entire conversation context every time
The Claude API is stateless, so you must send history. But sending thousands of tokens of old conversation history on every request gets expensive fast. Implement a sliding window โ keep only the last N turns โ or summarize old turns.
Using the wrong model for the task
Claude Haiku is fast and cheap โ use it for simple tasks like classification, summarization, and short responses. Claude Sonnet handles complex reasoning and longer outputs. Claude Opus is for the hardest tasks where quality trumps cost. Starting with Haiku for development is usually the right call.
Common Request Patterns
Here is a quick reference for the request shapes you will use most often:
# Basic message
client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
messages=[{"role": "user", "content": "Your question here"}]
)
# With a system prompt
client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
system="You are a helpful assistant that only responds in bullet points.",
messages=[{"role": "user", "content": "Explain REST APIs"}]
)
# Multi-turn conversation
client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=1024,
messages=[
{"role": "user", "content": "My name is Yash."},
{"role": "assistant", "content": "Nice to meet you, Yash!"},
{"role": "user", "content": "What is my name?"},
]
)
What to Build Next
Now that you can call the Claude API, here are three things to build with it:
A summarization script โ read a long text file and ask Claude to summarize it in a paragraph. Ten lines of Python.
A question-answering bot โ combine file reading with the API: load a document, put it in the prompt as context, then answer questions about it.
A content classifier โ send text to Claude with a system prompt like "Classify this as positive, negative, or neutral" and parse the single-word response. Use it to process lists of customer reviews.
Each of these teaches you a core pattern: context injection, structured output, and batch processing. Those three patterns cover the majority of real-world API use cases.
Summary
| Concept | What to remember |
|---|---|
| API | A way for programs to talk to each other |
| REST | Uses HTTP, resources have URLs, methods are GET/POST/PUT/DELETE |
| JSON | Text format for data โ objects, arrays, strings, numbers |
| API key | Your credential โ never commit it to Git |
| Status codes | 2xx = success, 4xx = your error, 5xx = their error |
| Rate limits | 429 means slow down โ use exponential backoff |
max_tokens | Controls response length โ set it appropriately |