What Is a REST API? How to Call AI APIs (2026 Beginner's Guide)
Understand what REST APIs are and how HTTP works, then make your first real API call to Claude using curl, Python, and JavaScript. A practical intro for developers new to APIs.
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.
Method + path:POST /v1/messages — you are creating a new message.
Host: which server to talk to.
Headers: metadata about the request. Content-Type tells the server the body is JSON. x-api-key is your authentication.
Body: the actual data you are sending, formatted as JSON.
And here is what a response looks like:
snippet
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.
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:
snippet
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:
bash
ANTHROPIC_API_KEY=sk-ant-api03-your-key-here
Then add .env to your .gitignore file:
bash
echo".env" >> .gitignore
Your code reads the key from the environment at runtime:
Python:
python
import os
api_key = os.environ.get("ANTHROPIC_API_KEY")
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):
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 textprint(message.content[0].text)
print(f"\nTokens used: {message.usage.input_tokens} in, {message.usage.output_tokens} out")
Run it:
bash
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:
python
import anthropic
from dotenv import load_dotenv
load_dotenv()
client = anthropic.Anthropic()
conversation = []
print("Chat with Claude (type 'quit' to exit)\n")
whileTrue:
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:
bash
npm install @anthropic-ai/sdk dotenv
Create a file called hello-claude.js:
javascript
importAnthropicfrom"@anthropic-ai/sdk";
import"dotenv/config";
// Create the client — reads ANTHROPIC_API_KEY from the environmentconst client = newAnthropic();
asyncfunctionmain() {
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 blockconsole.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:
bash
node hello-claude.js
Handling errors properly
Production code should always handle errors. The most common ones are:
javascript
importAnthropicfrom"@anthropic-ai/sdk";
import"dotenv/config";
const client = newAnthropic();
asyncfunctioncallClaude(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 instanceofAnthropic.APIError) {
if (error.status === 429) {
console.error("Rate limited. Wait before retrying.");
// In production: implement exponential backoff here
} elseif (error.status === 401) {
console.error("Invalid API key. Check your ANTHROPIC_API_KEY.");
} elseif (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.
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:
python
# 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