Home › Web Development › Website APIs
WEB DEVELOPMENT / APIs
Learn how website APIs work, from HTTP requests and JSON responses to REST architecture, authentication, security, testing, webhooks and frontend-backend integration.
Beginner-friendly explanations first, then the detail — with copyable examples and no invented statistics.
THE BASICS
An API (application programming interface) is a defined interface that lets software systems talk to each other through agreed rules: what you can ask for, how to ask, and what comes back.
A useful analogy: a restaurant menu. It lists what you can order and how to order it, without explaining the kitchen. You don’t need to know how the food is prepared — you need a defined way to make a request and receive a result. An API is the same contract between programs.
A web API is one reached over web protocols, almost always HTTP or HTTPS. That’s what makes it usable from a browser, a mobile app, a server or anything else that can make an HTTP request.
Two common misconceptions worth clearing up early. An API is not a database — it’s an interface in front of an application, which may or may not use a database, and which decides what any given caller is allowed to see. And APIs aren’t only for websites: they connect web applications, mobile apps, desktop software, backend services, third-party platforms and internal systems to each other.
DISTINCTIONS
A website is built for people: it returns HTML that a browser renders into something readable. An API is built for software: it returns structured data that another program interprets. The same application very often provides both — a Laravel or WordPress site can serve HTML pages at one set of URLs and JSON at another.
A web application is the whole user-facing product. The API is the communication layer inside it. In a typical modern architecture the frontend talks to an API, the API talks to backend logic, and the backend talks to a database. The API is the boundary where those responsibilities meet — and, crucially, where security is enforced.
# The request
GET /api/products?category=shoes&page=2 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer YOUR_TOKEN_HERE
# The response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: max-age=60
{
"data": [
{ "id": 101, "name": "Example Product", "price": 499 },
{ "id": 102, "name": "Another Product", "price": 899 }
],
"meta": {
"page": 2,
"perPage": 20,
"total": 137
}
}REQUESTS & RESPONSES
An API request is made up of a few parts: the HTTP method saying what you want to do, the URL identifying what you’re acting on, headers carrying metadata and credentials, optional query parameters for filtering or paging, path parameters identifying a specific item, and for some methods a body containing data.
An API response contains a status code, headers and usually a body. The status code isn’t decoration — automated clients rely on it, which is why returning 200 with an error message inside the body is such a common and damaging mistake.
An endpoint is a specific URL through which a client interacts with a resource or operation: /api/users, /api/products, /api/orders. Consistent, predictable naming makes an API far easier to work with than clever naming.
On terminology: a URI identifies a resource, and a URL is a URI that also says how and where to reach it. In everyday API work people say URL and endpoint almost interchangeably, and that’s usually fine — just know the terms aren’t strictly identical.
HTTP METHODS
The method expresses intent. Using the right one means clients, caches and proxies can reason about what a request does.
Retrieve data. Should not change anything on the server, though whether an implementation honours that is up to its authors.
Create a resource or submit data for processing. Repeating it usually creates another record.
Replace a resource with the representation you send. Sending it twice should leave the same result.
Partially update a resource, sending only the fields that change.
Remove a resource. What that means in practice depends on the backend and its permissions.
Describes the communication options available, and is what browsers send during a CORS preflight.
Like GET but returns only headers, useful for checking existence or metadata without the body.
# Create a resource
POST /api/products
Content-Type: application/json
{
"name": "Example Product",
"price": 499,
"category": "shoes"
}
# Replace it entirely
PUT /api/products/101
Content-Type: application/json
{
"name": "Updated Product",
"price": 549,
"category": "shoes"
}
# Change only one field
PATCH /api/products/101
Content-Type: application/json
{
"price": 599
}
# Remove it
DELETE /api/products/101STATUS & HEADERS
Status codes fall into ranges: 2xx success, 3xx redirection, 4xx a problem with the request, 5xx a problem on the server.
The pair most often confused is 401 and 403. 401 Unauthorized means authentication is missing or invalid — the server doesn’t know who you are, or your token has expired. 403 Forbidden means the server knows exactly who you are and is refusing anyway, because you lack permission. They are not “wrong password” and “user doesn’t exist”; they’re the authentication question and the authorisation question.
Headers carry metadata and control information. Content-Type describes what you’re sending, Accept what you’d like back, Authorization carries credentials, Cache-Control governs caching, and Origin identifies the calling site in browser cross-origin requests. Never put real credentials in documentation or examples.
OK
The request succeeded and the body contains the result.
Created
A new resource was created; the response often includes it or its location.
No Content
Succeeded with nothing to return — common after a delete.
Bad Request
The request itself was malformed and couldn’t be understood.
Unauthorized
Authentication is missing, invalid or expired. Despite the name, this is about authentication.
Forbidden
The server understood who you are and refuses to authorise this action.
Not Found
No such resource at this URL.
Conflict
The request conflicts with current state, such as a duplicate entry.
Unprocessable Content
Well-formed, but failed validation. The body should say which fields and why.
Too Many Requests
A rate limit has been exceeded.
Internal Server Error
Something failed on the server. Details belong in logs, not the response.
Bad Gateway
An upstream server returned an invalid response.
Service Unavailable
The service is temporarily unable to handle the request.
# Request headers Content-Type: application/json Accept: application/json Authorization: Bearer YOUR_TOKEN_HERE X-Request-Id: 8f14e45f # Response headers Content-Type: application/json; charset=utf-8 Cache-Control: public, max-age=300 ETag: "a1b2c3d4" X-RateLimit-Remaining: 58 # Never put a real token in documentation, # source control or client-side code.
// A JSON request body
{
"name": "Alex",
"email": "alex@example.com",
"age": 30,
"active": true,
"deletedAt": null,
"roles": ["editor", "reviewer"],
"address": {
"city": "Pune",
"country": "IN"
}
}
// A consistent response shape
{
"data": {
"id": 10,
"name": "Alex"
},
"meta": {
"requestId": "8f14e45f"
}
}
// The same API's error shape
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request could not be processed.",
"fields": {
"email": ["Enter a valid email address."]
}
}
}JSON
JSON is the common data format for web APIs. It supports objects in braces, arrays in brackets, strings in double quotes, numbers, booleans and null. Keys must be double-quoted, there are no comments, and no trailing commas — stricter than JavaScript object syntax, which catches people out.
When sending JSON, set Content-Type: application/json so the server parses it correctly. When expecting it, send Accept: application/json.
Consistency in response shape matters more than which shape you pick. If successful responses wrap data under a data key, every successful response should. If errors have a code and a message, every error should. Clients write code against your structure, and inconsistency means every endpoint needs special handling. There’s no universally correct envelope — there’s only documenting yours and sticking to it.
REST
REST is an architectural style, not a format. Its core ideas are resources identified by URLs, HTTP methods expressing what you’re doing to them, stateless requests carrying everything needed to be understood, representations of resources rather than the resources themselves, and a uniform interface that behaves consistently.
Two clarifications matter here. REST is not simply “JSON over HTTP” — the format is incidental. And an API using HTTP and returning JSON is not automatically RESTful; most APIs described as REST follow some of its constraints and not others, which is fine in practice but worth being honest about.
A REST resource typically supports a predictable set of operations: list the collection, fetch one item, create, replace, partially update and delete. Once a client learns that pattern for one resource, it knows what to expect from the others.
SOAP is a protocol with XML messaging and formal standards for security and transactions. It’s still widely used in enterprise and integration contexts, and calling it obsolete would be wrong. GraphQL is a query language and runtime where clients specify the fields they want, usually through one endpoint; it solves real over-fetching problems and brings its own caching, complexity and operational considerations. Neither is better than REST — they suit different situations.
# The conventional operations on one resource GET /api/products # list the collection GET /api/products/101 # fetch one item POST /api/products # create PUT /api/products/101 # replace PATCH /api/products/101 # partially update DELETE /api/products/101 # remove # Collection parameters GET /api/products?page=2&per_page=20 GET /api/products?category=shoes GET /api/products?sort=price&order=asc GET /api/products?search=laptop # Versioning in the URL — one common approach GET /api/v1/products GET /api/v2/products
IDENTITY
Authentication asks who you are. Authorization asks what you may do. They are separate checks and both are needed — being authenticated does not entitle a caller to every record.
API keys identify a calling application. They’re simple and widely used, but a key identifies a client, not usually a user, and by itself carries no permission model — treating one as a complete authorisation system is a common and serious mistake. Keys must stay server-side, travel over HTTPS, and be rotated if exposed.
Bearer tokens are sent as Authorization: Bearer <token>. “Bearer” is literal: whoever holds it can use it, so tokens need HTTPS, sensible expiry and careful storage.
OAuth is an authorization framework for delegated access — letting one application act on a user’s behalf at another without handling their password. It isn’t a login system in itself; identity layers such as OpenID Connect build on top of it for that.
JWT is a token format with a header, payload and signature. The signature proves the token wasn’t altered — it does not encrypt anything. The payload is base64-encoded and readable by anyone holding the token, so never put sensitive data in one unless the design adds encryption.
# API key, typically identifying an application GET /api/products X-API-Key: YOUR_API_KEY_HERE # Bearer token, typically identifying a user session GET /api/orders Authorization: Bearer YOUR_TOKEN_HERE # A JWT has three base64url parts separated by dots: # header.payload.signature # The signature proves integrity. # The payload is ENCODED, not encrypted — readable by anyone. # Authorisation is a separate check, made per action: # Authenticated as user 42 # -> may user 42 delete order 918? # -> no => 403 Forbidden
# The browser sends the origin automatically Origin: https://app.example.com # A preflight for non-simple requests OPTIONS /api/products Origin: https://app.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: Content-Type, Authorization # The server responds with what it permits Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, PATCH, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 600 # Access-Control-Allow-Origin: * # is fine for a genuinely public, unauthenticated API # and inappropriate for anything using credentials.
SECURITY
CORS (Cross-Origin Resource Sharing) controls whether browser JavaScript on one origin may read a response from another. Three things are worth being precise about: it’s enforced by the browser, it’s configured by server headers, and it is not authentication. A CORS error means the browser blocked your script from reading the response — the request often reached the server regardless, and non-browser clients ignore CORS entirely. It protects users, not your API.
For some requests the browser first sends an OPTIONS preflight asking what’s permitted, and only proceeds if the answer allows it. Disabling browser security or using a public proxy is not a fix; configuring the server is.
API security is much broader than authentication. SQL injection is prevented by parameterised queries and ORM abstractions — validation alone does not prevent it. XSS is a risk for whatever renders your data: an API returning stored user content isn’t itself vulnerable, but a frontend inserting that content as HTML is. CSRF depends on the authentication mechanism: cookie-based APIs need protection because browsers send cookies automatically, while header-based tokens are less exposed — though that’s not immunity to every issue.
And a point that bears repeating: a React frontend hiding an admin button is a user-experience choice. The API must enforce the permission, because anyone can call the endpoint directly.
[ ] HTTPS enforced everywhere [ ] Authentication required where appropriate [ ] Authorisation checked on every sensitive action [ ] All input validated server-side [ ] Rate limiting on auth and public endpoints [ ] Secrets kept out of client code and version control [ ] CORS configured intentionally, not with a blanket wildcard [ ] Errors that reveal nothing sensitive [ ] Dependencies kept updated [ ] Logs that exclude secrets and personal data [ ] Webhook signatures verified [ ] API versions managed and deprecations communicated [ ] Database access with least privilege
COLLECTIONS
Rate limiting caps how often a client can call an endpoint, protecting login forms from brute force and public endpoints from abuse. Exceeding it should return 429 Too Many Requests, ideally with headers showing the limit and when it resets.
Pagination should be the default for collections. Page-based pagination is simple and lets clients jump to a page, but can skip or repeat items if data changes between requests. Cursor-based pagination is stable across changes and suits large or fast-moving datasets, at the cost of arbitrary page jumps. Neither is universally better.
Filtering, sorting and search are usually query parameters. One security note that’s easy to miss: never pass an arbitrary sort or filter field straight into a database query. Validate against an allowed list you define, or you’ve handed callers partial control of your queries.
Versioning lets you make breaking changes without breaking existing clients. URL versioning like /api/v1/ is common and visible; header-based and media-type versioning are also valid approaches. What matters more than the mechanism is communicating changes, keeping old versions running for a stated period and documenting migration.
# Pagination with metadata in the response
GET /api/products?page=2&per_page=20
{
"data": [ /* ... */ ],
"meta": { "page": 2, "perPage": 20, "total": 137, "lastPage": 7 }
}
# Cursor-based pagination
GET /api/events?limit=50&after=evt_8f14e45f
# Filtering, sorting and search
GET /api/products?category=shoes&min_price=500
GET /api/products?sort=price&order=desc
GET /api/products?search=laptop
# Rate limit headers, and the response when exceeded
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
Retry-After: 30
HTTP/1.1 429 Too Many Requests# A simple GET
curl -X GET "https://api.example.com/api/products"
# With headers and authentication
curl -X GET "https://api.example.com/api/products?page=2" \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
# POST with a JSON body
curl -X POST "https://api.example.com/api/products" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-d '{"name":"Example Product","price":499}'
# Show response headers and status
curl -i "https://api.example.com/api/products"
# Replace YOUR_TOKEN_HERE with a token from your own
# environment. Never commit real tokens.TESTING
API testing covers more than the happy path. Test successful requests, then invalid input, missing fields, unauthenticated requests, forbidden requests by an authenticated user who lacks permission, missing resources, duplicate data, rate limits, pagination edges and large payloads. The failure cases are where bugs and security holes live, and they’re the ones manual clicking skips.
Postman provides a graphical client for building requests, storing collections, managing environment variables and writing assertions on responses. It’s widely used and useful; it’s one tool among several rather than a requirement.
cURL does the same job from the command line, which makes it easy to share exactly what you ran and to script checks. Both are for exploration and manual verification — automated tests in your backend framework remain the thing that stops regressions.
Whichever tool you use, keep real tokens out of shared collections and version control. Use environment variables and placeholders.
CONSUMING APIS
In the browser, fetch() is the standard way to call an API. Two things catch people out: fetch does not reject on HTTP error statuses — a 404 or 500 resolves normally, so check response.ok yourself — and response.json() is itself asynchronous. The async/await form reads more clearly and lets you use ordinary try/catch. More in our JavaScript guide.
Always handle three states in the interface: loading, success and error. Skipping the error state produces a blank screen when something fails, which is the worst outcome for the person using it.
On the server, PHP can both consume and build APIs. For consuming, a modern HTTP client library handles timeouts, retries and errors far better than the older approach of reading a URL with a stream function — and server-side calls are where third-party credentials belong, since browser code can’t hold a secret. See our PHP guide.
// Promise chain
fetch("/api/products")
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then(data => renderProducts(data))
.catch(error => showError(error));
// The same with async/await
async function loadProducts() {
try {
const response = await fetch("/api/products", {
headers: {
"Accept": "application/json",
"Authorization": `Bearer ${token}`,
},
});
// fetch does NOT reject on 4xx or 5xx
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const { data, meta } = await response.json();
return { products: data, pagination: meta };
} catch (error) {
showError(error);
}
}
// Sending JSON
await fetch("/api/products", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Example Product", price: 499 }),
});INTEGRATION
Laravel is a PHP framework that can build APIs alongside server-rendered pages. API routes, middleware for authentication and rate limiting, form request validation, Eloquent for data and API resources for shaping JSON all come ready. Secure APIs still depend on implementing authorisation and validation properly. See our Laravel guide.
WordPress exposes content through REST endpoints under a /wp-json/ path. Not every resource is public and not every operation is available without authentication — permissions apply per endpoint. Exposing the REST API does not make a site headless; that's an architectural choice. See our CMS guides.
React is a frontend library that consumes APIs; it is not an API framework. A component triggers a request, stores the JSON in state and renders it, handling loading and error states along the way. All validation and authorisation stay on the server. See our React guide.
Android and iOS apps talk to the same kind of API over HTTPS, usually with token authentication. Mobile adds its own considerations: storing tokens in secure platform storage, handling intermittent connectivity, paginating for smaller screens and bandwidth, and versioning carefully since users may not update the app.
<?php
// routes/api.php
use App\Http\Controllers\ProductController;
use Illuminate\Support\Facades\Route;
Route::middleware(['auth:sanctum', 'throttle:60,1'])->group(function () {
Route::get('/products', [ProductController::class, 'index']);
Route::post('/products', [ProductController::class, 'store']);
});
// The controller returns JSON
public function index()
{
$products = Product::with('category')->paginate(20);
return response()->json([
'data' => $products->items(),
'meta' => [
'page' => $products->currentPage(),
'total' => $products->total(),
],
]);
}
# WordPress REST API — an example endpoint pattern
# GET https://example.com/wp-json/wp/v2/posts?per_page=10
# Availability and permissions depend on the endpoint and site configuration.# An incoming webhook request to your endpoint
POST /api/webhooks/payments
Content-Type: application/json
X-Signature: 4f2a...
{
"event": "payment.completed",
"id": "evt_8f14e45f",
"createdAt": "2026-03-08T10:15:00Z",
"data": {
"orderId": 918,
"amount": 149900,
"currency": "INR"
}
}
<?php
// Verify BEFORE trusting anything in the payload
$payload = file_get_contents("php://input");
$signature = $_SERVER["HTTP_X_SIGNATURE"] ?? "";
$expected = hash_hmac("sha256", $payload, WEBHOOK_SECRET);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit;
}
$event = json_decode($payload, true, 512, JSON_THROW_ON_ERROR);
// Idempotency: ignore an event id already processed
if ($this->alreadyProcessed($event["id"])) {
http_response_code(200);
exit;
}
// Acknowledge quickly, process heavier work in a queue
http_response_code(200);WEBHOOKS
A webhook reverses the usual direction. Instead of your application repeatedly asking “has anything happened?”, the other system sends an HTTP request to a URL you provide when an event occurs — a payment completed, an order created, a form submitted.
The difference from an API call is who initiates it. You call an API; a webhook calls you. Most integrations use both: webhooks to learn something happened, API calls to fetch the detail.
Webhook security matters because your endpoint is a public URL anyone can post to. Verify the request before acting on it — typically by computing an HMAC signature over the raw body with a shared secret and comparing with a timing-safe function. Require HTTPS, validate the payload shape, and log what you receive.
Idempotency is the related concept. Senders retry on timeouts and network failures, so the same event can arrive twice. If processing it twice would charge a card twice or create two orders, that’s a real problem. Record processed event ids and ignore repeats. Acknowledge quickly with a 200 and do the slow work in a background queue, or the sender will time out and retry something you’re already handling.
OPERATIONS
Error responses should use the right status code, keep a consistent shape, and say enough for a developer to fix the problem without revealing anything about your infrastructure. Stack traces, database errors, file paths and internal identifiers must never reach a client. Log the detail; return a clean message.
Performance in APIs is usually about database work and payload size rather than the framework. Efficient queries and indexes, avoiding N+1 patterns, paginating collections, returning only the fields clients need, compressing responses, moving slow work to background jobs and reducing the number of round trips all help. What helps varies by API — measure rather than guess, and treat any specific percentage claim with suspicion.
Caching can operate at several levels: HTTP caching via Cache-Control, ETag and Last-Modified, server-side caching of expensive results, and client caching. It isn’t right for every endpoint — personalised or rapidly changing data usually shouldn’t be cached, and stale data can be worse than a slower response. Invalidation is the difficult part, not storage.
Monitoring tracks response time, error rates, availability, request volume, authentication failures and resource usage, with alerts when something moves. Logging should capture enough context to diagnose an issue — endpoint, status, timing, request id — and never passwords, tokens, API keys or unnecessary personal data.
# Validation failure
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request could not be processed.",
"fields": {
"email": ["Enter a valid email address."],
"price": ["Price must be a positive number."]
}
}
}
# Server error — no internal detail exposed
HTTP/1.1 500 Internal Server Error
{
"error": {
"code": "SERVER_ERROR",
"message": "Something went wrong. Please try again.",
"requestId": "8f14e45f"
}
}
# Cache headers on a cacheable response
Cache-Control: public, max-age=300
ETag: "a1b2c3d4"
Last-Modified: Wed, 08 Mar 2026 10:15:00 GMT
# A client can revalidate cheaply
If-None-Match: "a1b2c3d4"
-> HTTP/1.1 304 Not ModifiedAPI TYPES
Available to external developers — usually still behind registration, API keys, rate limits, documented terms and access restrictions. “Public” means externally available, not unrestricted.
Built for a specific application or organisation, not offered to outside developers. Access is controlled, and the contract can change more freely because you know every consumer.
How services within one system talk to each other. Still need authentication and validation — being inside a network is not a security boundary on its own.
External services for payments, maps, email, shipping, analytics, CRM or authentication. Consider credentials handling, rate limits, failure behaviour and what happens if the service is unavailable.
A layer between clients and backend services handling routing, authentication, rate limiting, logging and monitoring in one place. Valuable with several services; unnecessary overhead for a single application.
Independent services communicating through APIs. The architecture buys independent deployment and scaling, and costs distributed complexity, network failures and operational overhead. Most projects do not need it.
DOCUMENTATION
Documentation is what makes an API usable by anyone other than its author. Each endpoint needs its method and URL, a description, authentication requirements, parameters, the request body schema, an example response, the status codes it returns, the error format, rate limits, and version and deprecation notes where they apply. Real examples for both success and failure save more support time than any prose.
OpenAPI is a specification for describing REST APIs in a machine-readable format. Swagger refers to the tooling ecosystem associated with it — the two names are often used interchangeably but aren’t the same thing. A specification file can generate documentation, client libraries and test scaffolding, which is why keeping it accurate is worth the effort.
An API is not finished at launch. It has a lifecycle, and the parts people neglect are the last three: versioning changes so clients don’t break, announcing deprecations with a real timeline and migration guidance, and actually retiring old versions rather than maintaining them forever.
Identify what consumers need and what data exists.
Define resources, endpoints, schemas and errors.
Build with authentication, validation and authorisation from the start.
Success, failure, permission and edge cases.
Make integration possible without guessing.
Ship with monitoring and logging in place.
Watch errors, latency and usage.
Manage breaking changes for existing clients.
Announce, support for a stated period, then retire.
APIS IN CONTEXT
Not directly, and no API design improves rankings by itself. What matters is the final rendered website: whether content is in the HTML or requires JavaScript, whether URLs are crawlable, and whether metadata and internal links exist. An API-driven site can rank perfectly well or badly — the architecture decides. See website SEO.
Slow API responses delay dynamic content, large payloads increase transfer time, and excessive requests multiply the work. Efficient queries, pagination, smaller responses and caching all help, though how much depends entirely on the application. See website speed.
An API has no accessibility properties of its own — it returns data. Everything accessible happens in the frontend rendering it: semantic HTML, keyboard support, labels, announced loading and error states. See website accessibility.
Headless CMS architectures make the API central: a content system manages editing and exposes content through an API, and a separate frontend renders it. WordPress with its REST API feeding a React or other frontend is a common example.
The trade-offs are real and worth stating. You gain flexibility in how and where content is rendered, and the ability to serve several channels from one source. You take on a second system to build, deploy and maintain, plus responsibility for the rendering strategy — which is exactly where SEO problems appear if content ends up client-rendered on pages that need to be found. Headless is one architecture among several, not an upgrade every site needs.
PRACTICE
Predictable naming across every resource.
The right method and the right status code.
Server-side, always, for every field.
Choose a mechanism that fits the client type.
Authentication is not authorisation.
Make integration possible without guessing.
Don't break existing clients without warning.
Never return everything by default.
Actionable for developers, safe for everyone.
Errors, latency and usage, with alerts.
Endpoints reachable by anyone who finds the URL.
Any authenticated user able to reach any record.
Client checks treated as protection.
API keys in frontend code or version control.
Internal columns and unrelated fields in every response.
Whole tables returned in one response.
Every endpoint shaped differently.
200 returned with an error inside the body.
Stack traces and database errors sent to clients.
Login and public endpoints open to abuse.
A wildcard on an API that uses credentials.
Tokens and passwords written into log files.
Integration by trial and error.
Breaking changes shipped without warning.
One query per item in a collection.
Outages discovered by users.
Acting on requests from anyone who finds the URL.
An API key mistaken for a permission system.
CHECKLISTS
Two passes over the same API: one before building, one before shipping. Working lists rather than formal audits.
DESIGN [ ] Define the resources [ ] Define the endpoints [ ] Choose HTTP methods deliberately [ ] Define request body schemas [ ] Define response schemas [ ] Define status codes for each case [ ] Define the authentication mechanism [ ] Define authorisation rules [ ] Define validation rules [ ] Define pagination strategy [ ] Define the error format [ ] Define rate limits [ ] Document everything [ ] Test success and failure paths [ ] Plan monitoring TESTING [ ] Successful requests [ ] Invalid input [ ] Missing required fields [ ] Unauthenticated requests [ ] Forbidden requests by an authenticated user [ ] Missing resources [ ] Duplicate or conflicting data [ ] Rate limit behaviour [ ] Pagination edges [ ] Filtering and sorting parameters [ ] Large payloads [ ] Webhook signature validation [ ] Server error handling
REFERENCE
A categorised quick reference for the methods, codes, headers and patterns covered above. For authoritative definitions of HTTP behaviour, use MDN Web Docs and the HTTP specifications; for security guidance, OWASP.
GETPOSTPUTPATCHDELETEOPTIONSHEAD200 OK201 Created204 No Content304 Not Modified400401403404409422429500502503Content-TypeAcceptAuthorizationOriginCache-ControlETagLast-ModifiedRetry-AfterAccess-Control-Allow-OriginAllow-MethodsAllow-Headers?page=&per_page=&sort=&search=Bearer tokenAPI keyOAuthSession cookie{ }[ ]stringnumbertrue / falsenullcurl -X GETcurl -iPostman collectionsfetch()response.okresponse.json()async / awaitFAQ
Short answers to the questions people ask most about web APIs, REST, authentication and integration.
LEARNING PATH
HTTP fundamentals sit near the start deliberately. Most API confusion — status codes, headers, CORS, caching — is really HTTP confusion, and it clears up quickly once the protocol makes sense.
These are projects to build yourself. Each introduces a specific set of problems, and each raises questions — particularly around authorisation and error handling — that reading alone never does.
Beginner — GET, POST, PUT, DELETE and status codes.
Beginner — validation, JSON bodies and error responses.
Intermediate — users, posts, comments and relationships.
Intermediate — CRUD, filtering, sorting and pagination.
Intermediate — login, tokens and permission checks.
Advanced — carts, orders, idempotency and payment architecture.
Advanced — availability, conflicts and business rules.
Advanced — token auth, pagination and versioning.
Advanced — full frontend and backend integration.
Advanced — signature verification and idempotent processing.
NEXT TOPICS
Learn the markup language used to structure web pages.
Learn how websites and API-powered interfaces are styled.
Learn how browsers consume APIs and update interfaces.
Understand the server-side language commonly used to build APIs.
Learn how frontend applications consume APIs.
Learn how a PHP framework can be used to build APIs.
Explore WordPress and its REST API.
Understand where APIs run and how they are deployed.
Understand how websites, frontend applications, mobile apps and backend systems communicate through APIs using HTTP, JSON, authentication and secure integration patterns.