What an API Provides: A Supported Contract at a Software Boundary
📑 On this page
- A concrete example: account details
- APIs exist inside and across systems
- Capabilities, not database exposure
- Requests define intent
- Responses communicate results
- Semantics matter more than syntax
- Error behavior is part of the API
- Identity and authorization
- Operational rules belong in the contract
- Idempotency protects repeated requests
- APIs support independent evolution
- Documentation is part of the product
- Specifications and generated tooling
- SDKs improve language ergonomics
- Observability and correlation
- Governance without paralysis
- Knowledge check
- The one idea to remember
An API is often described as a way for one program to talk to another. That is true, but incomplete.
An application programming interface defines the supported operations, data, rules, and expectations at a software boundary.
The URL or function name is only the entry point. The contract includes what the operation means, who may call it, how it fails, and how it can change.
A concrete example: account details
A mobile app requests:
GET /accounts/1042The API might return:
{
"id": "1042",
"displayName": "Mira Rao",
"membership": "gold"
}The app does not need to know:
- Which database stores the account
- Whether data came from a cache
- Which internal services were called
- How records are joined
Those details can change while the supported response remains compatible.
APIs exist inside and across systems
An API can be:
- A function or class interface
- An operating-system API
- A library API
- A database interface
- A network service
- A hardware interface
This article focuses mainly on service APIs, but the same design principle applies: callers depend on a published boundary rather than implementation internals.
An API is not necessarily public. Internal interfaces still create dependencies and deserve clear contracts.
Capabilities, not database exposure
A useful API exposes meaningful operations:
- Create order
- Cancel subscription
- List unpaid invoices
- Approve refund
Direct database access exposes:
- Tables
- Storage schema
- Migration timing
- Internal identifiers
- Broad write power
An API can enforce authorization, invariants, audit, and workflow around data.
Returning table rows may be convenient, but the public contract should express domain meaning rather than mirror storage accidentally.
Requests define intent
A request includes:
- Operation
- Resource
- Input data
- Caller identity
- Context
The API should make intent unambiguous.
Compare:
POST /doAction { "code": 17, "flag": true }with:
POST /orders/9001/cancellation
{ "reason": "customer_request" }The second is easier to document, authorize, audit, and evolve.
Generic endpoints often move complexity into undocumented magic values.
Responses communicate results
A response can include:
- Created or requested data
- Status
- Identifiers
- Pagination
- Warnings
- Links to related operations
- Error details
Return enough information for the caller to continue safely.
After creating an order, returning its authoritative identifier and state can prevent the client from guessing what happened.
Do not expose sensitive internal fields merely because they are available.
Response shape is part of the compatibility promise.
Semantics matter more than syntax
Two APIs can use identical JSON but mean different things.
What does status: "complete" mean?
- Payment captured?
- Shipment delivered?
- Background processing finished?
Contracts need semantic definitions:
- Field meaning
- Units
- Time zone
- Null behavior
- State transitions
- Ordering
- Consistency
Schema validation proves shape, not meaning.
Many integration failures come from semantic assumptions that were never written down.
Error behavior is part of the API
Callers need to know whether to:
- Correct input
- Ask the user
- Authenticate again
- Retry later
- Stop permanently
- Contact support
Stable error codes and structured details support decisions.
Do not leak stack traces, SQL, secrets, or internal network names.
Errors should be useful to authorized callers and safe for attackers to see.
Document retryable and nonretryable outcomes.
Identity and authorization
An API must determine:
- Who or what is calling?
- Which action may that identity perform?
- On which resource?
- Under which tenant or context?
Authentication may use sessions, tokens, certificates, or signed requests.
Authorization must occur at the server boundary even if the client hides unavailable actions.
Service identities should receive least privilege, and delegated access should preserve the end user's authority where required.
Operational rules belong in the contract
Callers also depend on:
- Rate limits
- Maximum request size
- Timeout expectations
- Pagination
- Idempotency
- Event-delivery guarantees
- Retention
- Availability targets
An endpoint that accepts an upload but silently rejects files over an undocumented size is incomplete.
Operational behavior affects architecture and user experience as much as field names.
Publish limits and provide machine-readable signals where possible.
Idempotency protects repeated requests
Networks can time out after the server completes an operation.
The client cannot know whether to retry.
For operations such as payment or order creation, an idempotency key lets the server recognize a repeat:
Idempotency-Key: checkout-1042-attempt-7The server returns the original result instead of applying the action twice.
The contract should define key scope, lifetime, and behavior when the same key is reused with different input.
APIs support independent evolution
A database can move from one technology to another if callers depend only on the API contract.
The provider can:
- Add caching
- Split services
- Change queries
- Migrate data
without forcing every client to change.
This independence has limits.
Changes in latency, consistency, ordering, or error behavior can break callers even when JSON remains identical.
Compatibility includes observed semantics.
Documentation is part of the product
Useful API documentation includes:
- Purpose
- Authentication
- Operations
- Examples
- Schemas
- Errors
- Limits
- Pagination
- Versioning
- Changelog
- Support policy
Examples help readers begin, while formal schemas support tooling.
Documentation should be tested against real behavior.
Generated reference docs are valuable but do not replace explanations of workflows, state transitions, and common failure handling.
Specifications and generated tooling
Formats such as OpenAPI or GraphQL schemas can describe interfaces in a machine-readable form.
Tools can generate:
- Client libraries
- Validation
- Interactive documentation
- Mocks
- Contract tests
Generation reduces repetitive work but can produce awkward clients if the underlying API is poorly designed.
The specification should remain authoritative and reviewed with implementation changes.
Do not let generated code hide breaking semantic changes.
SDKs improve language ergonomics
An SDK wraps an API in language-friendly operations:
const order = await orders.create(input);It may handle:
- Authentication headers
- Serialization
- Retries
- Pagination
- Error mapping
- Telemetry
The SDK becomes another compatibility surface.
Avoid hidden retries for nonidempotent operations and expose enough details for diagnosis.
Users may call the raw API from unsupported languages, so the network contract remains fundamental.
Observability and correlation
APIs should provide and preserve request identifiers.
Operators need to trace:
client request -> gateway -> service -> database -> dependencyMonitor:
- Traffic
- Latency
- Errors
- Saturation
- Authentication failures
- Rate-limit responses
- Usage by operation
Logs must avoid sensitive request bodies and credentials.
Operational visibility is part of supporting the contract.
Governance without paralysis
API governance can standardize:
- Naming
- Error format
- Authentication
- Versioning
- Review
- Documentation
Consistency reduces caller learning.
Overly rigid centralized approval can delay useful work and encourage bypasses.
Provide paved paths, reusable tooling, and automated checks.
Allow justified exceptions with recorded reasons.
Knowledge check
- Why is an API more than a URL?
- What is lost when an API exposes raw database tables?
- Why can a schema-valid response still be semantically ambiguous?
- What problem does an idempotency key solve?
- Which behavior can break clients even when response fields do not change?
The one idea to remember
An API is a supported behavioral contract. It exposes meaningful capability while defining data, identity, errors, limits, and compatibility so callers and implementations can evolve without sharing internals.