API Product Design: Choose the Contract the Consumer Can Operate
Design an API as a supported product surface across interaction patterns, authorisation, retries, errors, pagination, webhooks, compatibility, and economics.
On this page14 sections
- 01Start with the consumer’s operating journey
- 02Choose an interaction pattern by need
- 03Review the contract before implementation hardens it
- 04Make authorisation part of the product model
- 05Design repetition before the network repeats it
- 06Give asynchronous work a durable identity
- 07Make collection reads stable enough to finish
- 08Turn errors and limits into recovery contracts
- 09Treat webhooks as an at-least-once integration surface
- 10Plan compatibility and deprecation as customer work
- 11A fictional hybrid API decision
- 12Operate the API as a portfolio, not a launch
- 13Sources
- 14Read next
An API can return valid JSON and still be a poor product.
The consumer may not know which state is authoritative, whether a timed-out write succeeded, how to recover from an error, or when a field will disappear.
Those failures live at the contract boundary. They create customer engineering work, support demand, operational risk, and long-lived compatibility obligations.
Product managers do not need to choose transport details alone. They do need to define the consumer job and the support promise before an implementation becomes somebody else’s dependency.
Start with the consumer’s operating journey
“Expose customer data” is not a usable API brief.
Describe one consumer, one job, and the surrounding operating conditions:
Consumer and authority
Trigger
Information required
Action or decision
Expected state change
Volume and timing shape
Failure consequence
Recovery route
Audit or regulatory need
Support boundary
A payroll partner synchronising employee records has a different job from an analyst exploring workforce data. Both may need the same fields, but not the same contract.
The partner needs repeatable writes, reconciliation, scoped authority, and failure recovery. The analyst may need flexible reads, documented freshness, and query-cost controls.
Do not begin with “REST versus GraphQL”. Begin with the interaction that must remain safe when networks, clients, and people behave imperfectly.
System Design for Product Managers covers authoritative state, failure, recovery, workload, and observability underneath the contract.
Choose an interaction pattern by need
Most durable APIs combine patterns. The question is where each one clarifies or obscures the consumer’s job.
| Interaction need | Useful pattern | Product question |
|---|---|---|
| Read or change a stable entity | HTTP resource | Which representation and method semantics can consumers rely on? |
| Request a domain action | Action or RPC | What command, validation, and resulting state make the action complete? |
| Select connected data flexibly | Query | Who controls cost, field access, and schema evolution? |
| Learn that something changed | Event or webhook | What are delivery, replay, ordering, and recovery semantics? |
HTTP resources work well when clients can reason about identifiable entities and standard method semantics. RFC 9110 defines safe and idempotent methods, status codes, and representation semantics.
It does not require every business operation to look like a resource. An action such as “calculate a quote” may be clearer than pretending a calculation is a conventional update.
GraphQL lets a client select fields through a typed schema. The specification defines validation and execution, including partial data alongside execution errors.
It does not choose authorisation, cost limits, caching, ownership, or a sensible schema for a product. Query flexibility transfers responsibility rather than removing it.
Events suit notification and loose coupling. They are a poor substitute for an authoritative read when a consumer must recover missing state.
Review the contract before implementation hardens it
A contract-first review uses a draft OpenAPI document, GraphQL schema, event catalogue, or equivalent artefact while change remains cheap.
Review one complete journey, including failure:
- resource, action, query, or event names in consumer language;
- state and completion semantics;
- identity and authorisation boundary;
- required and optional inputs;
- idempotency and concurrency behaviour;
- errors and recovery action;
- pagination, filtering, and freshness;
- asynchronous status and cancellation;
- rate or quota policy;
- compatibility and deprecation promise;
- examples, test environment, and support route.
The OpenAPI Specification can describe paths, operations, parameters, schemas, responses, and security schemes for HTTP APIs.
It cannot prove that the implementation follows the document, that a workflow is understandable, or that the provider can support its promise.
Test the draft with a consumer. Ask them to implement or narrate the journey without private architectural knowledge.
Make authorisation part of the product model
Authentication establishes an identity. Authorisation decides what that identity may do to which resource under which conditions.
Define:
- actor types and tenant boundary;
- scopes or permissions requested;
- resource ownership and delegation;
- administrative consent;
- expiry and revocation;
- audit evidence;
- actions requiring stronger assurance.
Avoid one broad scope because it is easy to implement. A customer should not grant write access to payroll records merely to let an integration read employment status.
Also avoid hundreds of opaque scopes that make consent impossible to understand. Group permissions around consumer jobs and material risk.
RFC 9700 is the current OAuth 2.0 security best-current-practice document. It covers threats, token replay prevention, and privilege restriction.
OAuth is only one authorisation mechanism. Following it does not define the product’s tenant model, consent language, or legitimate access policy.
Design repetition before the network repeats it
A client may retry because it did not receive a response. The provider may already have completed the action.
For every write, answer:
- Can an identical request be repeated safely?
- How does the client identify the intended operation?
- How long is replay protection retained?
- What response returns after a duplicate?
- Can concurrent updates overwrite newer state?
- How can the client reconcile the authoritative result?
HTTP defines PUT, DELETE, and safe methods as idempotent in their intended effect. POST is not idempotent by default, but an API can add an operation or idempotency key contract.
Do not describe a request as idempotent when only duplicate billing is prevented while notifications, audit events, or downstream work are repeated.
For competing updates, use a version or validator so the client can detect stale state. Silent last-write-wins behaviour is a product decision, not a neutral default.
Give asynchronous work a durable identity
Long-running work should not hold a client connection open merely to preserve an illusion of immediacy.
Accept the request, create a durable operation, and distinguish:
- accepted;
- queued;
- running;
- completed;
- completed with limitations;
- failed with a retryable cause;
- failed requiring changed input;
- cancelled or expired.
Define whether cancellation stops work or only requests a stop. Define how long results and operation history remain available.
The create response should identify the operation and the resource, if one already exists. A status read and a webhook can serve different needs.
The read is authoritative for recovery. The webhook reduces polling latency.
Make collection reads stable enough to finish
Pagination is not only a response-size concern. It defines what happens while the collection changes.
Specify:
- cursor or page semantics;
- stable ordering and tie-breaker;
- default and maximum size;
- filters and their combinations;
- snapshot or freshness behaviour;
- duplicates and omissions under concurrent change;
- cursor expiry;
- total-count accuracy and cost.
Offset pagination may be adequate for a small, stable list. It can repeat or skip records when inserts and deletions move positions.
A cursor can preserve position more reliably, but only if the ordering and snapshot semantics are defined.
Do not promise an exact total when computing it is slow, stale, or inconsistent with page contents. Label an estimate or omit it.
Turn errors and limits into recovery contracts
An error should let software decide what to do next.
Provide a stable machine-readable type or code, an appropriate protocol status, a safe human explanation, the invalid field where relevant, and a request or occurrence identifier for support.
RFC 9457 defines a standard problem-details format for HTTP APIs. It also warns against exposing implementation or security details.
The standard provides a container, not a domain error taxonomy. The provider still needs stable meanings and recovery guidance.
Separate retryable conditions from requests that must change. Publish backoff behaviour where retry is safe. Use Retry-After where its semantics apply.
Rate limits and quotas also need a product policy:
- unit counted, such as request, record, compute, or event;
- window and burst behaviour;
- tenant, user, token, or endpoint scope;
- response when capacity is exhausted;
- visibility before exhaustion;
- route to higher capacity;
- protection against one consumer harming others.
Limits are part of API economics. They allocate scarce capacity and shape which workflows remain viable.
Treat webhooks as an at-least-once integration surface
Do not imply exactly-once delivery across an external network.
Give every event a stable identifier. Document retry duration, possible duplicates, ordering scope, endpoint disablement, redelivery, and the authoritative read used for reconciliation.
Sign the raw payload and relevant metadata. Let consumers rotate secrets or keys. Include a timestamp and explain the accepted replay window.
The Standard Webhooks specification defines one signature and operational approach, including signed message identifiers, timestamps, duplicate handling, and retries.
It is a community specification, not a universal internet standard. Existing ecosystems use different formats, so compatibility may outweigh uniformity.
Plan compatibility and deprecation as customer work
A breaking change creates work in every consuming organisation. The provider controls the trigger while the customer often carries the migration cost.
Define what counts as breaking for each pattern:
- removing or changing a field’s meaning;
- making optional input required;
- narrowing allowed values;
- changing error or ordering semantics;
- altering event delivery or retry behaviour;
- revoking a permission without a replacement path.
Adding a field can also break clients that reject unknown content, even if the provider considers the change additive.
Maintain usage telemetry by version, field, operation, and customer where lawful. Contact affected consumers through a dependable channel. Provide a migration guide, overlap period, test route, and named exception process.
RFC 9745 defines an HTTP Deprecation response header and links it with the separate Sunset header when a resource is expected to stop responding.
Those fields improve machine discovery. They do not replace customer communication or decide a reasonable migration period.
Product Lifecycle Decisions covers the wider choice to invest, maintain, migrate, or retire.
A fictional hybrid API decision
The following example is hypothetical and claims no implementation result.
A payroll partner needs to synchronise employee records, start payroll calculations, reconcile results, and react when a run completes.
Two pure designs remain plausible: one GraphQL surface for all data and mutations, or an HTTP resource API with action endpoints and webhooks.
The team chooses a hybrid contract:
- employee records are HTTP resources with version validators;
- each write accepts an idempotency key;
- creating a payroll run returns a durable asynchronous operation;
- results are read through cursor pagination against a named snapshot;
- completion emits a signed webhook with an event identifier;
- the webhook points to the authoritative operation read;
- read and write scopes are separate by tenant;
- errors use stable problem types and occurrence identifiers.
GraphQL remains useful for an internal exploratory reporting client. It is not selected for the partner workflow because flexible field selection does not solve write recovery, audit, or payroll-run lifecycle.
The contract review exposes an economic choice. Historical-result exports create heavy compute and support demand, so the default quota covers routine reconciliation while bulk export has a separate asynchronous route.
No pattern is declared universally superior. Each part matches a different interaction and support obligation.
Operate the API as a portfolio, not a launch
Documentation should begin with working journeys, then expose reference detail. Include authentication setup, example data, errors, retries, pagination, webhooks, limits, migration, and a test environment.
SDKs reduce repeated client work, but they create their own version, language, security, release, and support obligations. Publish one only when the provider can maintain it.
Observe consumer outcomes as well as server health:
- time to first successful journey;
- failures by stable error type;
- duplicate and retry behaviour;
- operation completion and age;
- webhook delivery and reconciliation;
- deprecated usage still active;
- support demand by workflow;
- cost to serve by consumer and operation.
Review revenue or strategic value beside infrastructure, documentation, SDK, support, and migration cost. A lightly used endpoint can still be contractual infrastructure for a critical customer.
The API succeeds when a consumer can complete and recover the job without private knowledge, and the provider can afford to keep the contract it has published.
Sources
- RFC 9110: HTTP Semantics defines resource, method, status, safety, and idempotency semantics. It does not choose a product workflow or domain model.
- OpenAPI Specification defines a machine-readable description for HTTP APIs. A valid document does not prove runtime conformance, usability, or supportability.
- GraphQL Specification, September 2025 defines schema, validation, and execution. It does not prescribe authorisation, query economics, caching, or operating ownership.
- RFC 9457: Problem Details for HTTP APIs defines a standard error container. Providers still need domain meanings and safe recovery guidance.
- RFC 9700: OAuth 2.0 Security Best Current Practice updates OAuth threat and security guidance. OAuth does not define the product’s permission policy.
- RFC 9745: The Deprecation HTTP Response Header Field standardises deprecation signalling. It does not replace a migration programme.
- Standard Webhooks specification specifies signing and delivery conventions. It is a community standard and is not universal across providers.
Read next
Related books
Two books to
read next.
If you want to go further on this topic, these are two good places to start.
01
product
Continuous Discovery Habits
by Teresa Torres
A practical guide to discovering products that create customer value and business value, with frameworks for integrating customer research into weekly rhythms.
02
product
The Lean Startup
by Eric Ries
How today's entrepreneurs use continuous innovation to create radically successful businesses, introducing Build-Measure-Learn and validated learning.
Some outbound links are affiliate links and support independent bookstores.