An API is one of those terms developers say constantly, yet almost nobody explains clearly to beginners. You have almost certainly used dozens of APIs today without knowing it β every time your weather app loads a forecast, a payments page charges a card, or a login button says "Continue with Google", an API is involved.
This guide explains what an API actually is, how HTTP requests work, and how to call a real API right now with just a few lines of code.
What an API is β and what it is not
API stands for Application Programming Interface. That sounds technical, so let's break it down: it is a defined set of rules for how two programs can talk to each other.
An API is not:
- A website (websites return HTML for browsers; APIs return data for code)
- A database (a database stores data; an API is a layer that exposes data or actions)
- A specific technology (there are many ways to build APIs β REST, GraphQL, gRPC, WebSocket)
The most common type you'll encounter is an HTTP API β one that works over the same protocol as websites, using URLs and HTTP requests.
The restaurant analogy
The classic analogy is a restaurant, but let's make it concrete.
You (the client) sit at a table. The kitchen (the server) has ingredients and can make food. You cannot walk into the kitchen β the restaurant controls what you can order and how.
The waiter is the API. You look at the menu (the API documentation), choose what you want, and give your order (the request) to the waiter. The waiter carries it to the kitchen, and brings back your food (the response).
The menu matters: if the kitchen makes pizza and pasta but the menu only lists pizza, you can only order pizza through the API β even if the capability technically exists. APIs are deliberate contracts about what is exposed.
HTTP methods: what you're asking the server to do
Every HTTP API request has a method that describes your intent. The five you'll encounter most:
| Method | Meaning | Example |
|---|---|---|
GET | Read data | GET /users β get all users |
POST | Create something new | POST /users β create a new user |
PUT | Replace something entirely | PUT /users/1 β replace user #1 with new data |
PATCH | Update part of something | PATCH /users/1 β update just the name of user #1 |
DELETE | Remove something | DELETE /users/1 β delete user #1 |
A well-designed API uses these methods consistently. GET requests should never change data. DELETE requests should not require a body. This consistency is what makes REST APIs predictable to work with.
Anatomy of a request and response
An HTTP request has four parts:
- URL β the address of the resource:
https://api.example.com/users/1 - Method β what to do with it:
GET - Headers β metadata about the request:
Content-Type: application/json,Authorization: Bearer abc123 - Body β data you're sending (only on
POST,PUT,PATCH):{"name": "Alice"}
The server sends back a response with:
- Status code β a number saying what happened
- Headers β metadata about the response
- Body β the data (usually JSON)
Status codes: what they actually mean
Status codes are three-digit numbers. The first digit tells you the category:
- 2xx β success
- 4xx β you (the client) did something wrong
- 5xx β the server did something wrong
The ones you'll see most:
| Code | Name | Meaning |
|---|---|---|
| 200 | OK | Request worked as expected |
| 201 | Created | Your POST created a new resource |
| 400 | Bad Request | You sent invalid data β check your JSON or parameters |
| 401 | Unauthorized | No valid authentication β include your API key |
| 403 | Forbidden | Authenticated, but not allowed to do this |
| 404 | Not Found | That resource doesn't exist |
| 429 | Too Many Requests | You hit the rate limit β slow down |
| 500 | Internal Server Error | The server crashed β not your fault |
When debugging an API call, the first thing to check is the status code. A 401 means you forgot the API key. A 400 means your request body has a typo. A 500 means the API itself has a bug.
JSON: the language of APIs
Almost every modern API sends and receives data as JSON (JavaScript Object Notation). It's a text format for representing structured data that every programming language can read.
A typical API response looks like this:
{
"id": 1,
"login": "octocat",
"name": "The Octocat",
"public_repos": 8,
"followers": 9850,
"created_at": "2011-01-25T18:44:36Z"
}
JSON supports strings, numbers, booleans (true/false), arrays ([...]), and objects ({...}). You can nest them: an array of objects, an object with an array property, etc.
When an API returns a list of items, it's usually an array:
[
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
API keys: what they are and how to use them safely
An API key is a secret token that identifies your application to the API provider. It controls access, tracks usage, and enforces rate limits per key.
Where to pass it: in the Authorization header, like this:
Authorization: Bearer YOUR_API_KEY_HERE
Some older APIs use a query parameter (?api_key=...) or a custom header. Check the documentation.
The rule that matters most: never put an API key in frontend JavaScript that runs in the browser. Browser code is public β anyone can open DevTools and read it. Your API key ends up scraped and your quota gets burned.
Instead, call APIs with secret keys from a backend server, a Next.js API route, or a serverless function. The browser calls your backend; your backend calls the external API.
Calling an API in practice
Let's use the GitHub API as a real example β it returns data about users and repositories, and doesn't require authentication for public data.
With curl in the terminal
curl https://api.github.com/users/octocat
You'll see the JSON response printed directly in your terminal. Add -s to silence the progress output and pipe to jq for pretty-printing if you have it:
curl -s https://api.github.com/users/octocat | jq '.'
With Python
import requests
response = requests.get("https://api.github.com/users/octocat")
data = response.json()
print(data["name"], "β", data["public_repos"], "public repos")
print("Followers:", data["followers"])
The requests library handles JSON parsing for you. Install it with pip install requests if needed. See the Python setup guide if you haven't set up Python yet.
With JavaScript (fetch)
const response = await fetch("https://api.github.com/users/octocat");
const data = await response.json();
console.log(data.name, "β", data.public_repos, "public repos");
console.log("Followers:", data.followers);
In a Next.js app, you'd call this from a Server Component or an API route β never from a client component if API keys are involved.
REST vs GraphQL
REST is the dominant style for HTTP APIs. Each resource type has its own URL, and you combine method + URL to describe what you want:
GET /articlesβ list all articlesGET /articles/5β read article #5POST /articlesβ create an articleDELETE /articles/5β delete article #5
If you need an article plus its author's name, you might need two requests: one for the article, one for the user.
GraphQL takes a different approach. There is one endpoint (/graphql), and you send a query describing exactly what fields you want across any number of related objects:
query {
article(id: 5) {
title
body
author {
name
email
}
}
}
The server returns exactly those fields in one response. GraphQL is useful when your data needs are complex or vary across different clients. REST is simpler to get started with and works well for the vast majority of projects.
Rate limiting: what happens when you call too fast
APIs limit how many requests you can make in a time window β for example, 60 requests per minute. This protects the service from being overwhelmed.
When you exceed the limit, the API returns 429 Too Many Requests. The right response is exponential backoff:
- Get a 429 β wait 1 second, retry
- Get another 429 β wait 2 seconds, retry
- Get another 429 β wait 4 seconds, retry
- Continue doubling until success or you give up
Many APIs include a Retry-After header that tells you exactly how long to wait. Always check for it before implementing your own backoff.
Never retry in a tight loop β that floods the API and can get your key banned permanently.
Tools for testing APIs
Before writing code, test your API calls visually:
- Postman β the most popular API client. Set method, URL, headers, body, and hit Send. Good for saving collections of requests.
- Hoppscotch β open-source Postman alternative, runs in the browser with no install required.
Both let you see the full request and response β headers, status code, body β before you commit anything to code.
A real-world example: the Anthropic API
The Anthropic API is how you call Claude from your own code. You send a POST request to https://api.anthropic.com/v1/messages with your API key in a header and your prompt in the JSON body. The response contains Claude's reply as JSON.
This is the same pattern as every API you'll ever call: authenticate with a key, send a request body, parse the JSON response. Understanding the fundamentals in this guide means you can work with any API β payment processors, AI models, weather services, social platforms β using the same mental model.
Next steps
- Try calling the GitHub API with the Python snippet above β it's free and requires no key for public endpoints.
- When you build a backend and need to respond to events from external services, learn about webhooks β they're APIs in reverse.
- If your app stores the data you get from APIs, you'll need a database.
- Explore AI agents and MCP servers β both rely heavily on APIs to connect AI models to real-world tools.