What Is an API?
A complete guide to what APIs are — covering the definition, how they work, the anatomy of a request and response, API types, real-world examples, and the foundational vocabulary every developer needs before designing or consuming any API.
What Is an API?
An API — Application Programming Interface — is a defined contract that allows one piece of software to talk to another.
That one sentence contains everything. An API is not a URL. It is not a server. It is not a framework. It is a contract — a precise specification of how a caller can request something, what data it must provide, what the receiver will do with that request, and what the caller will get back.
When you open a weather app on your phone, the app does not contain weather data. It sends a request to a weather service's API, which responds with the current conditions for your location. The app and the weather service were built by different teams, run on different servers, possibly in different programming languages — and they communicate perfectly because they both honour the same API contract.
This is the core value of APIs: they decouple systems. The weather service does not need to know how the app renders a forecast. The app does not need to know how the weather service collects atmospheric readings. Each side just needs to respect the contract.
A Concrete Example Before the Theory
Before going further, here is what an API interaction looks like in practice.
Scenario: A banking application needs to look up a customer's account balance.
Without an API: The banking frontend would need direct database access, knowledge of the schema, credentials, query syntax, and the ability to handle raw SQL results. Any change to the database breaks the frontend immediately.
With an API: The backend team exposes a single endpoint:
GET /v1/accounts/{accountId}/balance
Authorization: Bearer <token>
The frontend calls it and receives:
{
"accountId": "acc_7f3a9b2c",
"currency": "USD",
"availableBalance": 4250.00,
"pendingBalance": 4100.00,
"asOf": "2026-07-18T09:15:00Z"
}
The frontend team only needs to know this contract. The database schema, query logic, caching, and data transformation are completely hidden. The backend team can change all of those internals without touching the frontend, as long as the response structure stays the same.
The Three Parts of Every API Contract
Every API — regardless of protocol, style, or technology — is defined by three things:
1. The Interface
The interface specifies what operations are available and how to invoke them:
- What is the operation name or endpoint path?
- What input does the caller need to provide (parameters, headers, body)?
- What format must the input be in?
2. The Behaviour
The behaviour specifies what the API does with the input:
- What business logic is executed?
- What state changes happen?
- What side effects occur (emails sent, records written, payments processed)?
Behaviour is not directly visible to the caller — it is the implementation. The contract specifies the observable result, not the implementation.
3. The Response
The response specifies what the caller receives back:
- What is returned on success?
- What is returned on each category of failure?
- What format is the response in?
- What do status codes or error codes mean?
A contract without a complete failure specification is incomplete. How a caller handles a 404 Not Found vs a 409 Conflict vs a 503 Service Unavailable depends entirely on what the API specifies those codes to mean.
How an API Request Works
When a client calls an HTTP API, the following sequence happens:
sequenceDiagram
participant CLIENT as Client (App / Service)
participant NET as Network
participant GW as API Gateway / Load Balancer
participant SVC as API Server
participant DB as Data Store
CLIENT->>NET: HTTP Request (method, URL, headers, body)
NET->>GW: Route request
GW->>GW: Auth, rate limit, logging
GW->>SVC: Forward request
SVC->>SVC: Parse, validate, execute business logic
SVC->>DB: Read or write data
DB-->>SVC: Query result
SVC->>SVC: Serialize response
SVC-->>GW: HTTP Response (status code, headers, body)
GW-->>CLIENT: Response delivered
Each step in this journey is well-defined:
- The client forms a request according to the API contract — method, path, required headers, body format.
- The network delivers the request — TCP/IP handles routing; TLS encrypts the payload in transit.
- The gateway applies cross-cutting concerns — authentication, rate limiting, logging, routing to the right backend.
- The server processes the request — validates input, executes business logic, interacts with databases or other services.
- The server returns a response — a status code indicating success or failure, headers with metadata, and a body with the result.
Every API interaction is this same pattern, regardless of whether the underlying protocol is HTTP, gRPC, WebSocket, or a message queue.
The Anatomy of an HTTP API Request
The most common API style today is HTTP. Understanding the structure of an HTTP request is foundational:
POST /v1/payments HTTP/1.1
Host: api.bank.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
Idempotency-Key: pay_a1b2c3d4
X-Request-ID: req_7f8a9b0c
X-Correlation-ID: corr_e1f2a3b4
{
"fromAccountId": "acc_7f3a9b2c",
"toAccountId": "acc_3c9b2e5a",
"amount": {
"value": 250.00,
"currency": "USD"
},
"reference": "Invoice INV-2026-1234",
"scheduledAt": null
}
Breaking it down:
| Part | Value in the example | Purpose |
|---|---|---|
| Method | POST |
What action to perform (create a payment) |
| Path | /v1/payments |
Which resource to act on |
| Host | api.bank.com |
Which server to send the request to |
| Content-Type | application/json |
Format of the request body |
| Authorization | Bearer eyJ... |
Proves the caller's identity |
| Idempotency-Key | pay_a1b2c3d4 |
Makes the operation safe to retry |
| X-Request-ID | req_7f8a9b0c |
Unique ID for this specific request (for tracing) |
| Body | JSON object | The data needed to execute the operation |
The Anatomy of an HTTP API Response
The server's response is equally structured:
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.bank.com/v1/payments/pmt_e5f6a7b8
X-Request-ID: req_7f8a9b0c
X-RateLimit-Remaining: 98
Retry-After: (absent — not rate limited)
{
"paymentId": "pmt_e5f6a7b8",
"status": "PENDING",
"fromAccountId": "acc_7f3a9b2c",
"toAccountId": "acc_3c9b2e5a",
"amount": {
"value": 250.00,
"currency": "USD"
},
"reference": "Invoice INV-2026-1234",
"createdAt": "2026-07-18T09:15:00Z",
"estimatedSettlementAt": "2026-07-18T17:00:00Z"
}
Breaking it down:
| Part | Value | Purpose |
|---|---|---|
| Status code | 201 Created |
Outcome: resource was created successfully |
| Content-Type | application/json |
Format of the response body |
| Location | https://.../pmt_e5f6a7b8 |
Where to find the newly created resource |
| X-Request-ID | req_7f8a9b0c |
Echoes the caller's request ID for tracing |
| X-RateLimit-Remaining | 98 |
How many requests remain in this rate limit window |
| Body | JSON object | The created payment record with server-assigned ID |
Why "Interface" Is the Right Word
The word interface in API is deliberate. An interface is a boundary — it separates the caller from the implementation.
Think of a wall socket. You plug in a lamp, a phone charger, or a refrigerator. You don't know what is behind the wall — whether the power comes from a coal plant, a solar farm, or a nuclear reactor. The socket is the interface. The specification says: 120V, 60Hz, two or three prongs. As long as both sides respect that contract, anything can be plugged in.
APIs work the same way. The caller knows the interface contract. The implementation details are hidden. This is called encapsulation, and it is what makes large software systems maintainable.
When a team changes the database schema, caching strategy, or internal service architecture — the API consumers notice nothing, as long as the interface contract is unchanged.
Types of APIs
Not all APIs use the same protocol or style. The right choice depends on the use case.
REST (Representational State Transfer)
REST APIs use HTTP as the transport protocol and model their operations around resources — things that can be named and manipulated.
GET /v1/orders → list orders
POST /v1/orders → create an order
GET /v1/orders/ord_abc123 → get a specific order
PUT /v1/orders/ord_abc123 → replace an order
PATCH /v1/orders/ord_abc123 → partially update an order
DELETE /v1/orders/ord_abc123 → delete an order
REST is the most common style for public and internal web APIs. It is stateless, cacheable, and built on the well-understood semantics of HTTP.
Best for: Public APIs, web and mobile clients, CRUD-heavy services, integrations with third parties.
RPC (Remote Procedure Call)
RPC APIs model their operations as procedure calls — named functions that the caller invokes, passing arguments and receiving a return value. The most common modern RPC protocol is gRPC, which uses Protocol Buffers (protobuf) for serialization.
service OrderService {
rpc GetOrder (GetOrderRequest) returns (Order);
rpc CreateOrder (CreateOrderRequest) returns (Order);
rpc ListOrders (ListOrdersRequest) returns (ListOrdersResponse);
}
gRPC uses HTTP/2 for transport (supporting bidirectional streaming), protobuf for compact binary serialization, and strongly typed contracts defined in .proto files.
Best for: Service-to-service communication where low latency, streaming, and strong typing matter.
GraphQL
GraphQL is a query language for APIs. Instead of fixed endpoints, the client specifies exactly what data it needs in a structured query, and the server returns precisely that — nothing more, nothing less.
query {
order(id: "ord_abc123") {
id
status
customer {
name
email
}
items {
productName
quantity
unitPrice
}
}
}
The client determines the shape of the response. No over-fetching (getting fields you don't need) and no under-fetching (making multiple calls to assemble the data you need).
Best for: Applications with complex, variable data requirements — especially when multiple client types (web, mobile, embedded) need different views of the same data.
Event-Driven APIs / Async APIs
Not all APIs follow the request-response model. Event-driven APIs communicate by publishing and subscribing to events on a message broker (Kafka, RabbitMQ, Amazon SNS/SQS).
Producer: order-service → publishes "order.confirmed" event to Kafka
Consumer: fulfillment-service → subscribes to "order.confirmed" events
Consumer: notification-service → subscribes to "order.confirmed" events
The producer does not call the consumers directly — it publishes an event and any interested service can react. This decouples systems temporally (the consumer processes the event when it is ready) and structurally (producers and consumers don't know about each other).
Best for: Workflows where multiple services need to react to state changes, high-throughput event streams, and scenarios where the producer should not wait for consumers.
SOAP (Simple Object Access Protocol)
SOAP is an XML-based protocol for exchanging structured information. It uses WSDL (Web Services Description Language) to formally define the service contract, supports complex security standards (WS-Security), and is common in enterprise integration — particularly in financial services, insurance, healthcare, and government.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<wsse:Security>...</wsse:Security>
</soap:Header>
<soap:Body>
<tns:GetAccountBalanceRequest>
<tns:AccountId>acc_7f3a9b2c</tns:AccountId>
</tns:GetAccountBalanceRequest>
</soap:Body>
</soap:Envelope>
Best for: Legacy enterprise systems, regulated integrations that require WS-Security, ACID transactions, and formal WSDL contracts.
Public APIs, Private APIs, and Partner APIs
APIs are not just a technical category — they are also a business and access category.
Public APIs (Open APIs)
Public APIs are accessible to any developer, often requiring only an API key to get started. They are products in their own right — businesses like Stripe, Twilio, and Google Maps have built enormous value by exposing their capabilities as public APIs.
Examples:
- Stripe Payments API — any business can accept card payments by integrating Stripe
- Twilio SMS API — any app can send text messages worldwide
- Google Maps API — any app can embed maps and routing
Public APIs must be designed with extraordinary care. They are consumed by thousands of developers across hundreds of different use cases, they cannot be changed without deprecation notices, and they are the company's external face.
Private APIs (Internal APIs)
Private APIs are internal to an organization. They connect microservices, frontend applications to backends, and data platforms to consumer services. Most APIs in the world are private.
Private APIs are consumed by a known set of teams within the same organization. They can evolve more rapidly than public APIs, but they still need contracts, documentation, versioning, and security. A sloppy internal API becomes a maintenance burden as the engineering team grows.
Partner APIs
Partner APIs are shared with specific external partners under agreements — B2B integrations. A logistics company exposes a shipping API to its retail partners. A bank exposes an account verification API to partner fintech applications. A healthcare system exposes a patient data API to approved clinical partners.
Partner APIs sit between public (open to all) and private (internal only). They require authentication, authorization, contract governance, and SLA commitments, but only for a defined set of consumers.
APIs as Products
One of the most important shifts in modern API engineering is treating APIs not as technical plumbing but as products.
A product has users. It has a value proposition. It has documentation, onboarding, versioning, and support. It has metrics — adoption rate, error rate, latency, satisfaction.
When an API is treated as a product:
- Consumers can discover it through a developer portal or catalog
- Documentation is accurate and includes working examples
- Breaking changes are announced with migration guides and deprecation periods
- SLOs (Service Level Objectives) are published — callers know what uptime and latency to expect
- Feedback from consumers is used to improve the API
When an API is treated as plumbing:
- It is only documented in someone's head or in an outdated Confluence page
- Breaking changes are deployed silently
- There is no way for a new team to discover it exists
- Consumers reverse-engineer it by reading the source code
The difference in outcomes is enormous. Teams that treat their APIs as products have fewer integration incidents, less coupling between services, and faster onboarding for new consumers.
The API Contract Is a Promise
An API contract is a promise the provider makes to its consumers. This is not metaphorical — in regulated industries, partner integrations, and public APIs, the contract is literally enforced by legal agreements and SLAs.
The contract includes:
| Element | What It Specifies |
|---|---|
| Endpoints / operations | What you can call and how |
| Input schema | What data you must provide and in what format |
| Output schema | What you will receive back on success |
| Error schema | What you will receive back on failure, and what each error code means |
| Versioning | How breaking changes will be communicated and when old versions retire |
| SLA | Uptime, latency, throughput, and rate limits you can rely on |
| Security model | How the API is authenticated and what permissions are required |
Every field in that table is part of the contract. When a provider changes the response schema without notice, consumers break. When a provider removes an error code from their documentation but their server still returns it, consumer error handling becomes unreliable. When a provider provides no versioning policy, consumers live in constant fear of silent breaking changes.
Good API engineering is the discipline of honouring and evolving this contract responsibly.
What Makes an API Good?
An API is not good just because it works. A good API is:
Predictable
A developer who understands one endpoint should be able to correctly guess how the next endpoint works. Consistent naming, consistent error formats, consistent use of HTTP verbs, consistent pagination — these reduce the cognitive load of integration.
Explicit
Good APIs are self-documenting in their structure. Status codes mean what they are supposed to mean. Error responses explain what went wrong. Field names are unambiguous. A caller should not need to read source code or ask the backend team to understand the API.
Stable
Once published and consumed, an API should not change in breaking ways without notice, deprecation, and migration support. Stability is what makes large ecosystems possible — thousands of Stripe integrations exist because Stripe has maintained remarkable API stability for over a decade.
Complete
An API that returns success responses but does not document its failure modes is incomplete. An API that has no documentation for authentication is incomplete. An API that lacks pagination for list endpoints is incomplete. Completeness means the consumer has everything they need, with no gaps that force guesswork.
Secure
An API that exposes data without authentication, leaks internal details in error messages, or allows callers to access data beyond their authorization is not production-ready. Security is not a layer added on top of the API — it is part of the contract.
Observable
An API that provides no request IDs, no rate limit headers, no structured error codes, and no way to correlate failures is extremely difficult to operate and debug. Observability must be designed into the API from the start.
Common Misconceptions About APIs
"An API is a URL"
A URL is the address of a resource. An API is the entire contract — the collection of endpoints, methods, headers, input schemas, output schemas, error codes, versioning policy, and SLA. A URL is one part of that contract.
"An API is just a backend"
An API is a contract, not an implementation. Two different backends can implement the same API contract. A mock server, a real service, and a stub for testing can all satisfy the same contract. The API is the specification; the backend is one implementation of it.
"Internal APIs don't need documentation"
Internal APIs are consumed by real developers who have real integration questions. Undocumented internal APIs lead to bugs (from incorrect assumptions), tight coupling (because consumers read source code instead of contracts), and outages (because breaking changes were not communicated). Documentation is a form of professionalism regardless of audience.
"REST is just HTTP"
REST is an architectural style with specific constraints: stateless interactions, uniform interface, resource-based addressing, self-descriptive messages, and hypermedia as the engine of application state (HATEOAS). HTTP is a protocol that REST APIs happen to use. An HTTP API that does not follow REST constraints is not a REST API — it is just an HTTP API.
"APIs are for external consumers only"
The majority of API calls in any production system are internal — microservice to microservice, frontend to backend, job scheduler to processing service. Every service boundary in a distributed system is an API contract. Treating internal boundaries with the same discipline as external ones is what makes large systems maintainable.
APIs in Production: What You Don't See
When a developer calls GET /v1/orders/ord_abc123, dozens of things happen invisibly:
- DNS resolution — the domain name is resolved to an IP address
- TLS handshake — client and server negotiate encryption
- TCP connection — possibly reused from a connection pool
- Load balancer — the request is distributed to a healthy backend instance
- API gateway — authentication, authorization, rate limiting, and logging happen here
- Routing — the gateway routes to the order service
- Authentication verification — the JWT or API key is validated
- Authorization check — does this caller have permission to access this order?
- Input validation — is the order ID in the expected format?
- Cache check — is there a cached response for this request?
- Business logic — load the order, check visibility rules, apply transformations
- Database query — fetch the order record
- Response serialization — convert the internal representation to JSON
- Response headers — add cache-control, request ID, rate limit remaining
- Compression — gzip the response body if the client accepts it
- Response delivery — send over the existing TLS connection
The developer sees a 200 OK and a JSON body. The API contract abstracts all of this into a single, clean interaction.
The Vocabulary of API Engineering
Before going deeper into this learning path, it helps to have a shared vocabulary:
| Term | Definition |
|---|---|
| Endpoint | A specific URL path that accepts requests (e.g., /v1/orders) |
| Resource | A thing that can be addressed and manipulated via an API (e.g., an order, a user, a payment) |
| Method / Verb | HTTP action to perform (GET, POST, PUT, PATCH, DELETE) |
| Request body | Data sent by the client as part of the request (typically JSON) |
| Response body | Data returned by the server (typically JSON) |
| Status code | Three-digit HTTP code indicating the outcome (200, 201, 400, 401, 404, 500...) |
| Header | Key-value metadata sent with a request or response (Content-Type, Authorization, Cache-Control) |
| Query parameter | Key-value pairs appended to the URL (e.g., ?status=pending&page=2) |
| Path parameter | Variable parts of the URL path (e.g., /orders/{orderId}) |
| Payload | The data contained in a request or response body |
| Schema | The structure and type definition of a request or response payload |
| Contract | The complete specification of an API's interface, behaviour, and responses |
| Consumer | A client or service that calls an API |
| Provider | The service that implements and exposes an API |
| Idempotent | An operation that produces the same result regardless of how many times it is called |
| Rate limit | The maximum number of requests a consumer can make in a time window |
| Versioning | The mechanism for evolving an API without breaking existing consumers |
| Deprecation | The formal process of retiring an old API version after giving consumers time to migrate |
| SLO | Service Level Objective — a measurable target for API availability, latency, or error rate |
| SDK | Software Development Kit — a language-specific library that wraps an API |
| OpenAPI | A standard specification format for describing REST APIs |
Summary
An API is a contract between a provider and its consumers. It specifies what operations are available, what input is required, what output will be returned, how errors are expressed, and how the contract will evolve over time.
flowchart LR
A[Client calls API] --> B[Request travels over network]
B --> C[Gateway: auth + rate limit]
C --> D[Server executes business logic]
D --> E[Response returned]
E --> F[Client handles result]
G[API Contract] -.->|defines| A
G -.->|defines| E
Key takeaways:
- APIs are contracts, not implementations — the same contract can be satisfied by multiple implementations
- Every API interaction has two sides — the provider that fulfils the contract and the consumer that depends on it
- There are multiple API styles — REST, RPC/gRPC, GraphQL, event-driven, and SOAP each solve different problems
- APIs exist at every boundary — public APIs, partner APIs, internal APIs between microservices — all require the same discipline
- Good APIs are predictable, explicit, stable, complete, secure, and observable — these properties are not accidents; they are the result of deliberate design
Learning Path
This page is part of the API Engineering Fundamentals Learning Path.
Return to the API Engineering Learning Path to continue with the complete roadmap.