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.

Three clients on the left — a browser, a mobile app and a monitoring script — send requests to the API in the middle, which is the contract: endpoints, data formats, authentication and errors. Behind the API, on the right, sit the backend systems: application code, a database and other services. The clients only ever see the API; the backend is hidden. Browser Mobile app Monitoring script Clients API endpoints data formats authentication errors, versions The contract App code Database Other services Backend (hidden) request response
Clients see only the API. What happens behind it can change freely, as long as the contract stays the same.

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 the json module. 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); the Accept header says the client wants JSON.
  • The status 200 OK says it worked; the Content-Type header 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 404 status and a JSON body explaining it. urllib raises HTTPError for 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:

  1. Base URL and version — for example https://api.example.com/v1. Check whether there are separate URLs for test (sandbox) and production.
  2. 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.
  3. Endpoints — each operation with its method and path, path and query parameters, request body and a sample response.
  4. Errors — which status codes the API uses and what an error body looks like.
  5. Limits — rate limits, page sizes, maximum request size. Exceeding them gives 429 Too Many Requests, 413 Content Too Large or truncated results.
  6. 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.