An API is the official, well-defined way one piece of software lets another talk to it. Think of a restaurant menu: you don't walk into the kitchen or need to know how the food is cooked; you order from the menu and the dish arrives. The menu tells you what you can ask for and in what form, and an API does the same for programs. When a mobile app shows your order history, or an online store asks the payment provider whether a payment went through, an API call is happening behind the scenes.

In day-to-day programming, the most common kind of API today is a REST API: your program sends an HTTP request, just like the one a browser sends to load a page, to a specific URL and usually gets JSON back. Below we look at what these requests are made of, what the responses mean, and how to call an API from PHP and Python.

Short answer: An API (application programming interface) is a contract that defines what data and functionality one piece of software exposes to another, and in what format. A REST API is the most common kind on the web: a program sends an HTTP request with a method such as GET or POST to a specific URL and gets back a status code and, usually, a JSON body.

Where APIs fit in programming

The term API (Application Programming Interface) is broad. The functions a library exposes to you are that library's API, too. But in everyday web work, when someone says "the X API" they almost always mean a web API: a set of URLs on the internet you can send requests to.

A few familiar examples:

  • A store's mobile app and its web dashboard both pull data from the same API, so the core logic is written only once.
  • Your website calls an SMS provider's API to send verification codes.
  • An accounting system reads new invoices from the store's API every night.

The key point is that both sides agree only on the contract: which URL, what input, what output. Either side can change its language, database or architecture behind that contract without the other noticing.

What is a REST API?

REST is a style for designing APIs on top of HTTP. The core idea is simple: everything is a resource, and every resource has its own URL. What you want to do with that resource is expressed by the HTTP method.

text
GET    /v1/orders          list orders
GET    /v1/orders/1042     get one order
POST   /v1/orders          create a new order
PATCH  /v1/orders/1042     update part of an order
DELETE /v1/orders/1042     delete or cancel an order

Notice there are no verbs in the URLs (no /getOrder or /deleteOrder). The method is the verb; the URL only says which resource you're talking about. Another important property of REST is that every request is stateless: the server doesn't need to remember anything from a previous request, and everything it needs, including who is sending it, comes in the request itself.

HTTP methods

Method Used for Has a body? Safe to repeat?
GET Reading No Yes
POST Creating a resource or triggering an action Yes No
PUT Replacing a resource entirely Yes Yes
PATCH Updating part of a resource Yes Depends on implementation
DELETE Deleting Usually not Yes

The last column is what idempotent means: if a PUT or DELETE arrives twice because of a network glitch, the result is the same as if it arrived once. Two POSTs, however, mean two orders. That's why serious APIs accept an idempotency key on sensitive operations such as payments, so they can detect a duplicate request.

Status codes

Every HTTP response carries a three-digit number that tells you what happened before you even read the body. The first digit is the category: 2xx success, 4xx a problem with the request, 5xx a problem on the server.

Code Meaning
200 OK Success; the result is in the body
201 Created A new resource was created
204 No Content Success, with no body (e.g. after a delete)
400 Bad Request The request is malformed
401 Unauthorized You're not authenticated, or the token is invalid
403 Forbidden You're authenticated but not allowed to do this
404 Not Found No such resource
422 Unprocessable Content The data was parsed but isn't valid (e.g. a bad email address)
429 Too Many Requests You've exceeded the rate limit
500 Internal Server Error Something went wrong on the server

A practical rule for code that calls an API: don't retry a 4xx; fix the request first. A 5xx or 429 can be retried after a short pause.

JSON: the common language

Request and response bodies in most REST APIs are JSON: a readable text format that almost every language can parse and produce.

json
{
  "id": 1042,
  "status": "paid",
  "total": 18500,
  "currency": "EUR",
  "items": [
    { "product_id": 7, "title": "Book", "quantity": 2 }
  ],
  "created_at": "2026-10-09T08:30:00Z"
}

A real request with curl

curl is the simplest way to see an API up close. The examples use the placeholder host api.example.com and assume the token is in the SHOP_API_TOKEN environment variable:

bash
curl -i https://api.example.com/v1/orders/1042 \
  -H "Accept: application/json" \
  -H "Authorization: Bearer $SHOP_API_TOKEN"

The -i flag shows the response headers as well:

http
HTTP/2 200
content-type: application/json

{"id":1042,"status":"paid","total":18500,"currency":"EUR"}

Creating a new order with POST:

bash
curl -i -X POST https://api.example.com/v1/orders \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $SHOP_API_TOKEN" \
  -d '{"product_id": 7, "quantity": 2}'

A successful response is usually 201 Created, with the new resource in the body and often a Location header pointing to its URL.

Authentication: how does an API know who you are?

Most APIs aren't public; they need to know who is making the request. Three common approaches, from simplest to most involved:

  • API key: a fixed string you get from the service's dashboard and send with every request, usually in a header. Simple, and well suited to server-to-server communication.
  • Bearer token: a token issued after login or from a dashboard and sent in the Authorization: Bearer ... header. It typically has an expiry and a defined scope.
  • OAuth 2.0: for when a user needs to let your app access another service on their behalf without giving you their password. The "Sign in with..." buttons belong to this family.

A few rules apply whichever method you use:

  • Don't hard-code keys or tokens or commit them to git; keep them in environment variables or a .env file that isn't tracked.
  • HTTPS only. A token sent over plain HTTP is effectively public.
  • Never put a key in browser-side code or a mobile app; anyone can extract it. The app should call your own API, and your server should talk to the third-party service with the key.
  • Issue a separate key per consumer, so if one leaks you revoke only that one.

What makes a good API?

If you're building an API yourself, these are what separate a pleasant API from a painful one:

  • Consistency: the same naming style throughout (all snake_case or all camelCase), plural resource names (/orders), one date format (ISO 8601).
  • Correct status codes: returning errors as 200 with "success": false in the body makes life hard for everyone calling your API.
  • Clear errors: the message should say which field failed and why, not just "error".
  • Versioning: /v1/ in the path, so that when the contract changes, existing consumers don't break.
  • Pagination: never return a whole list in one go; use page or cursor with a maximum page size.
  • Rate limiting, advertised in response headers, with a 429 status when exceeded.
  • Documentation with examples: one working curl example beats pages of prose.

If an endpoint does heavy work (generating a report, bulk sending), it's better to accept the request, hand the job to a queue and immediately return 202 Accepted. That pattern is covered in Laravel queues for slow work.

Calling an API from PHP

Using PHP's built-in cURL extension, with no extra libraries (PHP 8.3+):

php
<?php

$ch = curl_init('https://api.example.com/v1/orders/1042');

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => [
        'Accept: application/json',
        'Authorization: Bearer ' . getenv('SHOP_API_TOKEN'),
    ],
]);

$body = curl_exec($ch);

if ($body === false) {
    throw new RuntimeException('Request failed: ' . curl_error($ch));
}

$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

if ($status !== 200) {
    throw new RuntimeException("Unexpected status {$status}");
}

$order = json_decode($body, true, flags: JSON_THROW_ON_ERROR);

echo $order['status'], PHP_EOL;

In Laravel, the framework's HTTP client makes this shorter. throw() raises an exception on any 4xx or 5xx response:

php
use Illuminate\Support\Facades\Http;

$order = Http::withToken(config('services.shop.token'))
    ->acceptJson()
    ->timeout(10)
    ->get('https://api.example.com/v1/orders/1042')
    ->throw()
    ->json();

Calling an API from Python

The requests library is the usual choice (pip install requests):

python
import os

import requests

headers = {
    "Accept": "application/json",
    "Authorization": f"Bearer {os.environ['SHOP_API_TOKEN']}",
}

# Fetch one order
resp = requests.get(
    "https://api.example.com/v1/orders/1042",
    headers=headers,
    timeout=10,
)
resp.raise_for_status()
order = resp.json()
print(order["status"])

# Create a new order; json= encodes the body and sets Content-Type
resp = requests.post(
    "https://api.example.com/v1/orders",
    headers=headers,
    json={"product_id": 7, "quantity": 2},
    timeout=10,
)
resp.raise_for_status()
print(resp.status_code, resp.json()["id"])

In both languages, don't forget two things: a timeout, because without one a slow service can hang your program indefinitely, and checking the status code before using the response. If you're torn between the two for your backend, see PHP or Python for backend development.

Frequently asked questions

What is the difference between an API and a web service?

A web service is an API that's available over a network, usually via HTTP. API is the broader term and also covers the functions a library exposes to a program, so every web service is an API, but not every API is a web service.

What is the difference between GET and POST in an API?

GET reads data, has no body and is safe to repeat. POST creates a resource or triggers an action, sends its data in the body, and can take effect twice if it arrives twice, for example creating two orders.

What is an API key and where should I store it?

An API key is a fixed string you get from a service's dashboard and send with each request, usually in a header, so the service knows who is calling. Keep it in an environment variable or a .env file outside git, send it only over HTTPS, and never put it in browser-side code or a mobile app.

What is the difference between a 401 and a 403 error?

401 means you aren't authenticated or your token is invalid. 403 means the server knows who you are but you don't have permission to do that.

How do I test an API?

The simplest way is the curl command-line tool: give it the URL, the headers you need such as Authorization, and a JSON body if required, and use the -i flag to see the status code and response headers. Once that works, send the same request from PHP or Python.

Wrap-up

An API is a contract that says what one piece of software exposes to another and in what form. A REST API implements that contract over HTTP: resources have URLs, GET, POST, PATCH and DELETE say what to do, the status code reports the outcome, and the data is usually JSON. To get started, try an API with curl, then call it from PHP or Python, and always set a timeout, check the status code and keep your keys out of your code.