What Is an API?
How programs talk to each other: what an application programming interface is, the main styles — REST, RPC, GraphQL, gRPC and webhooks — and the contract between client and server.
What an API is
An API (application programming interface) is the part of a piece of software that is meant to be used by other software. A user interface is made for people: buttons, forms, pages. An API is made for programs: it lists the operations you can ask for, the data each operation needs, and what comes back. Everything else — the database, the code, the servers — stays hidden behind it.
Think of the outage map on the customer portal of Kestrel Energy, a fictional energy supplier. The map in the browser does not read the outage database directly. It asks the outage API: "which outages are there right now?" The API checks the request, fetches the data and answers in an agreed format. The same API also feeds the mobile app, the text-message service and the dashboards in the network operations center. Four different programs, one interface.
Two roles appear in every API conversation. The client sends a request; the server (or provider) processes it and sends a response. That is the client-server model applied to programs.
APIs are everywhere, not only on the web
The word is older than the web, and it still covers three quite different things:
-
Library APIs. The functions and classes a library
offers to your code. When a Python script calls
json.loads(), it uses the API of thejsonmodule. The call stays inside one process. - Operating system APIs. The system calls and libraries a program uses to open files, start processes or open a network socket: POSIX on Linux and macOS, the Windows API on Windows.
- Web APIs. Operations offered over the network, almost always over HTTP. The client and server can be on different machines, written in different languages, owned by different companies. This is what most people mean today when they say "the API", and it is what the rest of this topic is about.
The API contract
An API contract is the full, agreed description of how an API behaves — everything a client is allowed to rely on. It has four parts:
| Part | What it fixes | Outage API example |
|---|---|---|
| Inputs | Operations, paths, parameters, required fields, data types, authentication |
GET /v1/outages?region=west with a bearer token
|
| Outputs | The response format and the meaning of each field |
A JSON list; status is one of
investigating, repairing,
restored
|
| Errors | How failures are reported, so a client can react |
401 without a valid token, 404 for
an unknown outage, an error body with a message
|
| Versions | Which version this is and how changes are announced |
/v1/ in the path; fields are only added, never
renamed, within v1
|
Why does this matter? Because the provider and the client usually
change at different times. If the outage team renames
status to state, every client that reads
status breaks — the mobile app, the dashboards, a
script someone wrote two years ago. A contract makes clear which
changes are safe (adding a new optional field) and which are not
(removing or renaming a field, changing a type). How to design,
describe and version contracts — for example with an OpenAPI
document — is the subject of
Designing and Documenting APIs.
API styles at a glance
Web APIs come in a handful of styles. They all send messages over the network; they differ in what a message means and how strictly the contract is written down.
REST: resources and HTTP methods
In a
REST API, every thing the API manages — an outage, a ticket, a user — is a
resource with its own URL, and the standard HTTP methods say what to
do with it: GET to read, POST to create,
PUT or PATCH to change,
DELETE to remove. The data is usually JSON. REST is by
far the most common style for public web APIs;
REST APIs covers it in depth.
GET /v1/outages/101 HTTP/1.1 Host: api.example.com Accept: application/json
RPC: calling a function on another machine
RPC (remote procedure call) is the older
and simpler idea: the client calls a named function on the server as
if it were local, passes arguments and gets a return value. The
focus is on actions (getOutage,
restartService), not on resources. Many APIs that look
like REST are really RPC over HTTP, with URLs like
/api/restartService.
JSON-RPC is a small, widely used RPC format: every
call is a JSON object with the method name, the parameters and an
id that ties the answer to the question. Monitoring
tools such as Zabbix use it for their API.
{
"jsonrpc": "2.0",
"method": "outage.get",
"params": { "id": 101 },
"id": 1
}
The server answers with a result (or an
error object) and the same id. All calls
usually go to one URL with POST, so HTTP methods and
status codes carry little meaning.
SOAP: XML envelopes and WSDL
SOAP (originally Simple Object Access
Protocol) is an RPC-style protocol standardized by the W3C. Each
message is an XML document — an envelope with an optional
header and a body — usually sent with POST. The
contract is written in WSDL (Web Services
Description Language), an XML file that tools read to generate
client code. SOAP brings built-in standards for signing, encryption
and reliable delivery (the WS-* family), at the price of verbose
messages and heavy tooling. New public APIs rarely use it, but you
will still meet it in enterprises: banking, insurance, government,
and older ERP (enterprise resource planning) and HR systems.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<GetOutage xmlns="https://api.example.com/outages">
<Id>101</Id>
</GetOutage>
</soap:Body>
</soap:Envelope>
A SOAP 1.2 request body: the XML namespace of the envelope identifies the SOAP version.
GraphQL and gRPC
GraphQL offers one endpoint and a typed schema; the client writes a query that names exactly the fields it wants, so one request can replace several REST calls and returns no unused data. gRPC is a modern RPC framework from Google: services and messages are defined in Protocol Buffers, messages travel in a compact binary format over HTTP/2, and client code is generated for many languages. GraphQL is popular for front ends with varied data needs; gRPC is common between internal services where speed and strict types matter. Both are covered in GraphQL and gRPC.
Webhooks: the API calls you
In all the styles above, the client asks and the server answers. To
learn that something changed, the client must keep asking — polling
— which wastes requests and still arrives late. A
webhook turns this around: you
register a URL with the provider, and when an event happens the
provider sends an HTTP POST with the event data to that
URL. GitHub calls your webhook when someone pushes code; a payment
provider calls it when a payment succeeds; a monitoring tool calls
it when an alert fires.
POST /hooks/outages HTTP/1.1
Host: portal.example.com
Content-Type: application/json
{"event": "outage.restored", "outage_id": 101}
Because anyone on the internet can send a POST to your
URL, a receiver must verify that the call really comes from the
provider — usually with a signature computed from a shared secret —
and must cope with retries and duplicates. Those details, and
real-time alternatives such as WebSockets, are on
Webhooks and Real-Time APIs. In GitHub, the same events also trigger
GitHub Actions workflows.
The styles compared
| Style | Unit of design | Typical format | Contract | Where you meet it |
|---|---|---|---|---|
| REST | Resources + HTTP methods | JSON | Optional (often OpenAPI) | Most public web APIs, cloud and SaaS APIs |
| JSON-RPC and other RPC over HTTP | Named functions | JSON | Usually prose documentation | Monitoring tools, blockchain nodes, internal tools |
| SOAP | Operations in XML envelopes | XML | Required (WSDL) | Enterprise and government integrations |
| GraphQL | A typed graph, queried by field | JSON | Required (schema) | Front ends with varied data needs |
| gRPC | Service methods, also streaming | Protocol Buffers (binary) | Required (.proto file) |
Service-to-service traffic, microservices |
| Webhooks | Events pushed to your URL | JSON over POST |
Event list in the provider's documentation | Git hosting, payments, alerting, chat tools |
A tiny API you can run
The best way to see that an API is "just" requests and responses is
to run one. The script below starts a small outage API on your own
machine, then acts as a client and calls it. The server answers
GET /outages with a JSON list; any other path gets a
404 with an error body. Nothing leaves your computer:
the server listens on 127.0.0.1, and port
0 lets the operating system pick any free port.
import json
import threading
import urllib.error
import urllib.request
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
OUTAGES = [
{"id": 101, "area": "Riverside", "status": "investigating"},
{"id": 102, "area": "Old Harbor", "status": "restored"},
]
class OutageAPI(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/outages":
self.send_json(200, OUTAGES)
else:
self.send_json(404, {"error": "not found", "path": self.path})
def send_json(self, status, data):
body = json.dumps(data).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, format, *args):
pass # keep the output clean
server = ThreadingHTTPServer(("127.0.0.1", 0), OutageAPI)
threading.Thread(target=server.serve_forever, daemon=True).start()
base = f"http://127.0.0.1:{server.server_port}"
# The client: one request, one response
request = urllib.request.Request(base + "/outages", headers={"Accept": "application/json"})
print("Request: ", request.get_method(), "/outages")
with urllib.request.urlopen(request) as response:
print("Response:", response.status, response.reason)
print("Content-Type:", response.headers["Content-Type"])
raw = response.read()
print(raw.decode("utf-8"))
for outage in json.loads(raw): # text -> Python objects
print(f"#{outage['id']} {outage['area']}: {outage['status']}")
# A path the API does not offer: urllib raises HTTPError for 4xx and 5xx
try:
urllib.request.urlopen(base + "/outage")
except urllib.error.HTTPError as error:
print("Response:", error.code, error.reason)
print(json.load(error))
server.shutdown()
server.server_close()
Request: GET /outages
Response: 200 OK
Content-Type: application/json
[{"id": 101, "area": "Riverside", "status": "investigating"}, {"id": 102, "area": "Old Harbor", "status": "restored"}]
#101 Riverside: investigating
#102 Old Harbor: restored
Response: 404 Not Found
{'error': 'not found', 'path': '/outage'}
Read the output line by line and you see the whole contract in action:
-
The request names a method (
GET) and a path (/outages); theAcceptheader says the client wants JSON. -
The status
200 OKsays it worked; theContent-Typeheader says how to read the body. -
The body is plain text in JSON format. Only
json.loads()turns it into Python lists and dictionaries — see JSON and Other Data Formats. -
The error is part of the contract too: a
404status and a JSON body explaining it.urllibraisesHTTPErrorfor every 4xx and 5xx status, and the error object still holds the response body.
The same call with curl, against a real server, looks
like this (-i includes the response headers; see
curl):
$ curl -i -H "Accept: application/json" https://api.example.com/v1/outages
HTTP/2 200
content-type: application/json
content-length: 118
[{"id": 101, "area": "Riverside", "status": "investigating"}, {"id": 102, "area": "Old Harbor", "status": "restored"}]
SDKs and client libraries
Calling an API by hand means building URLs, adding headers, handling errors and retries, and turning JSON into objects — in every program, again and again. Providers therefore publish an SDK (software development kit): a package for a specific language that wraps the API in ordinary functions and classes, often together with documentation, examples and tools. The AWS SDK for Python (boto3), the Azure SDKs and the Microsoft Graph SDKs are well-known examples. Smaller packages that only wrap the API are usually called client libraries.
An SDK saves work and handles details you might get wrong — authentication, pagination, retries with backoff. The trade-offs:
- It is one more dependency to keep up to date, with its own release cycle and vulnerabilities.
- It hides the HTTP traffic. When something fails, you still need to know which request was sent and what came back — the error message of an SDK often contains the original status code.
- An SDK version may lag behind the API, or support only part of it.
Many SDKs are now generated from the API's machine-readable
contract (an OpenAPI document, a GraphQL schema or a
.proto file), which keeps them in step with the API.
Public, partner and internal APIs
APIs differ in who is allowed to call them, and that changes how carefully they must be designed and protected:
| Kind | Who calls it | Example | What it means in practice |
|---|---|---|---|
| Public (open) | Any registered developer, sometimes anyone | A public outage feed, a weather API | Strong versioning, documentation, rate limits, self-service API keys |
| Partner | Selected organizations under an agreement | Kestrel Energy's meter-data API for grid operators | Contracts, onboarding, per-partner credentials and quotas |
| Internal (private) | The organization's own teams and services | The billing service called by the portal | Faster change, but still a contract between teams |
"Internal" does not mean "safe". Internal APIs that nobody keeps an inventory of, or that trust every caller on the internal network, are a classic source of incidents; see Web and API Security.
Organizations with many APIs usually put an API gateway in front of them: one entry point that authenticates callers, enforces rate limits, routes each request to the right backend, terminates TLS and logs every call. Examples are Kong, AWS API Gateway and Azure API Management. The gateway handles these shared concerns once, so each API does not have to.
How to read API documentation
Whether you need to automate a task or troubleshoot an integration, you will often start with an API you have never seen. Good documentation answers the same questions in roughly the same order; look for these:
-
Base URL and version — for example
https://api.example.com/v1. Check whether there are separate URLs for test (sandbox) and production. - Authentication — an API key in a header, a bearer token from OAuth 2.0, a client certificate? This is where most "401 Unauthorized" problems start; see API Authentication.
- Endpoints — each operation with its method and path, path and query parameters, request body and a sample response.
- Errors — which status codes the API uses and what an error body looks like.
-
Limits — rate limits, page sizes, maximum request
size. Exceeding them gives
429 Too Many Requests,413 Content Too Largeor truncated results. - Changelog and deprecations — what changed recently and what will be removed.
Many APIs also publish an OpenAPI document: a YAML or JSON file that describes every endpoint in machine-readable form. Tools turn it into interactive documentation ("try it out" pages), client code or tests. If you can download it, import it into an API client such as Postman or Bruno and start experimenting; see Testing and Debugging APIs.
APIs you will meet in IT
As soon as you automate anything, you meet APIs. A few examples of what people in operations and service management use them for:
- Monitoring — querying metrics from Prometheus over its HTTP API, creating maintenance windows in Zabbix through its JSON-RPC API, or receiving alerts from a monitoring tool through a webhook.
- Ticketing — creating an incident automatically when an alert fires, or exporting tickets for a report, through the REST API of ServiceNow, Jira or a similar tool.
- Cloud — every click in the AWS, Azure or Google Cloud console is an API call behind the scenes. The command-line tools, SDKs and infrastructure-as-code tools all call the same APIs.
-
Identity — creating users, reading group
memberships or checking sign-in logs in Microsoft Entra ID through
Microsoft Graph, a REST API at
https://graph.microsoft.com. - Network devices — controllers and modern switches and firewalls offer REST APIs for configuration and status; see network automation.
Every one of these needs credentials, and those credentials are often more powerful than a person's account. Store them in a secrets manager, give them only the permissions the task needs, and rotate them — see Identity for Applications and Machines.