Insights · Software Development

API design best practices for APIs other teams will enjoy using

API design best practices come down to predictability: consistent names, standard HTTP behavior, clear errors, safe pagination and versioning, and security built into the contract from the first draft. An API that behaves the same way everywhere lets other teams integrate quickly without reading your code or calling your developers.

Cover for the Digihub guide to API design best practices, covering contracts, errors, pagination, versioning and security

Key takeaways

  • Write the API contract in OpenAPI and review it with the consuming team before any code is written.
  • Use plain nouns for resources, standard HTTP methods and status codes, and one consistent error format.
  • Paginate every list endpoint from day one and choose a versioning rule before the first release.
  • Check every endpoint against the OWASP API Security Top 10, starting with object-level authorization.
  • Make writes safe to retry and publish rate limits so clients can behave well under load.

Part of our guide: Build vs buy software: when custom software is worth it

What are API design best practices?

API design best practices are the conventions that make an interface predictable for the people who call it: how resources are named, how HTTP methods and status codes are used, how errors, lists, versions and security work. None of them is clever on its own. Their value comes from being applied the same way across every endpoint.

A useful test of an API is how far a new developer gets with only the documentation. If they can authenticate, fetch a list, create a record and understand a failure without asking anyone, the design is doing its job. If they need a call with your team for each step, the API is costing both sides time on every integration.

This guide focuses on HTTP APIs in the REST style, which most business systems use for integrations. If you are deciding whether to build an integration at all or connect existing tools, start with our build vs buy software guide.

Why design the contract before writing code?

Design the contract first because it is far cheaper to change a document than a deployed API with live clients. In a design-first process, the team writes the endpoints, fields and error responses in the OpenAPI Specification (opens in a new tab), shares it with the people who will consume it, and only then starts building.

An OpenAPI file is machine-readable, so it does more than describe. It can generate interactive documentation, mock servers that client teams code against while the real API is built, request validation and client libraries. The specification is maintained by the OpenAPI Initiative, and version 3.2 is the current release at the time of writing.

Design-first API workflow following API design best practices: draft the OpenAPI contract, review with consumers, publish a mock, build and test against the contract, then release with docs.
The contract stays the single source of truth for docs, mocks and tests.

How should you name resources and use HTTP methods?

Name resources as plural nouns and let HTTP methods carry the verbs: /invoices, /invoices/{id}, /customers/{id}/orders. Avoid action names like /getInvoice or /createOrder, which duplicate what the method already says and drift into inconsistency as the API grows.

Use each method for the meaning defined in HTTP semantics, published by the IETF as RFC 9110. That standard defines which methods are safe (they change nothing) and which are idempotent (repeating them has the same effect as sending them once). Clients, proxies and caches rely on those meanings, so breaking them causes subtle bugs.

Pick one style for field names, such as camelCase or snake_case, and use it everywhere. Send dates and times in ISO 8601 format with a time zone, and money as an amount plus a currency code rather than a bare number.

Standard HTTP methods and how a business API should use them
MethodUse it toSafeIdempotent
GETRead a resource or a listYesYes
POSTCreate a resource or start an actionNoNo
PUTReplace a resource completelyNoYes
PATCHUpdate some fields of a resourceNoNot by default
DELETERemove a resourceNoYes

How should an API report errors?

Report errors with the correct HTTP status code and one consistent, machine-readable body. The IETF standard for that body is RFC 9457, Problem Details for HTTP APIs (opens in a new tab), which replaced RFC 7807. It defines fields such as type, title, status and detail, and lets you add your own, for example a list of invalid fields.

Good error messages tell the caller what to fix. "Validation failed" forces a support ticket. "dueDate must be on or after issueDate" lets the developer fix the request in a minute. Never return internal details such as stack traces or SQL, which help attackers more than they help clients.

  • 400 Bad Request: the request is malformed or fails validation.
  • 401 Unauthorized: no valid credentials were sent.
  • 403 Forbidden: the caller is known but not allowed to do this.
  • 404 Not Found: the resource does not exist, or the caller may not know it exists.
  • 409 Conflict or 412 Precondition Failed: the record changed since the caller last read it.
  • 429 Too Many Requests: the caller hit a rate limit and should wait before retrying.
  • 5xx: something failed on the server; the client may retry later.

How should list endpoints handle pagination and filtering?

Paginate every list endpoint from the first release, even if the list is short today, because adding pagination later breaks clients that expect everything in one response. Return a page of results plus a token for the next page, and let the client choose a page size within a limit you set.

Cursor or token-based pagination is usually safer than page numbers for data that changes, since new records do not shift items between pages. Google's API design guidance, AIP-158 on pagination (opens in a new tab), describes this pattern with a page size and an opaque page token. Filtering and sorting should use clear query parameters, such as status=open or sort=-createdAt, documented with examples.

How do you version an API without breaking clients?

Decide your versioning rule before the first release, and make additive changes the norm. Adding a new optional field or a new endpoint should not break anyone, provided clients are told to ignore fields they do not recognize. Removing a field, renaming it or changing its meaning is a breaking change and needs a new major version.

The simplest and most visible approach is a major version in the path, such as /v1/ and /v2/. Whatever you choose, publish a deprecation policy: how long an old version keeps working after a new one launches, and how clients will be warned. Then keep that promise, because trust in an API is mostly trust that it will not change under you.

Versioning matters most when an API sits in front of an older system that is being replaced. In an incremental legacy modernization project, a stable API lets new code replace legacy parts behind it while client integrations stay untouched.

Which security practices belong in the API design?

Security belongs in the contract, not in a review after launch. The OWASP API Security Top 10 (2023 edition) lists the most common API weaknesses, and the first on the list, broken object level authorization, is a design issue: the API returns a record because the caller knows its ID, without checking that the caller may see it.

Design each endpoint with three questions in mind. Who may call it? Which records may they touch? Which fields may they read or change? Write the answers into the contract and test them, because many serious API incidents come from a missing check on one of these, not from broken encryption.

  • Authorize every request at the object level, not just at sign-in.
  • Return only the fields the caller needs; never send whole database rows.
  • Reject unknown or read-only fields on writes, so callers cannot set roles or prices.
  • Limit request sizes, page sizes and call rates to prevent resource exhaustion.
  • Use HTTPS everywhere and short-lived tokens, such as OAuth 2.0 access tokens.
  • Keep an inventory of every API version and environment, and retire old ones.

How do you make an API safe to retry and fair under load?

Make writes safe to retry, and tell clients how much traffic they may send. Networks fail mid-request, so a client that never received a response will often send it again. If that request was "create a payment", a naive API creates two.

The common fix is an idempotency key: the client sends a unique value with each create request, and the server returns the original result if the same key arrives twice. For updates, use ETags with the If-Match header so that two people editing one record cannot silently overwrite each other. For load, return 429 with a Retry-After header when a client exceeds its limit, and document the limits publicly.

These API design best practices are where our API development and third-party integrations work spends much of its testing time, because they decide whether an integration behaves well on a bad network day.

An API design best practices checklist before launch

Run through these API design best practices before any API goes live to a partner or another team. Each item is quick to verify against the OpenAPI contract and a test environment.

  • The OpenAPI contract is complete, reviewed by a consumer and matches the running API.
  • Every endpoint has an example request and response in the documentation.
  • Resource names, field style and date formats are consistent across endpoints.
  • Errors use correct status codes and one Problem Details format.
  • Every list is paginated and has a maximum page size.
  • The versioning and deprecation policy is written and published.
  • Object, field and function level authorization are tested for each role.
  • Create requests accept an idempotency key; updates support conditional requests.
  • Rate limits are enforced, documented and signaled with 429 and Retry-After.
  • Logs record who called what, without storing secrets or personal data unnecessarily.
Sources

Sources and further reading

Official documentation and guidance if you want to read more about this topic.

Keep reading
FAQ

Questions readers ask

Should I use REST or GraphQL for a business API?

Use REST for most business integrations, because it is widely understood, works well with HTTP caching and suits partner APIs with stable resources. GraphQL helps when many different front ends need flexible queries over related data. It needs extra care with authorization and query cost limits. Many systems publish REST for partners and use GraphQL internally.

What is the best way to version an API?

A major version in the URL path, such as /v1/, is the simplest and most visible option, and it works with every client and tool. Make additive changes within a version, reserve new versions for breaking changes, and publish how long old versions stay available. Consistency and a clear deprecation policy matter more than the exact mechanism.

Do I need OpenAPI documentation for an internal API?

Yes, it pays for itself even internally. An OpenAPI file gives new developers working documentation, lets front-end and back-end teams work in parallel against a mock, and enables automated contract tests that catch accidental breaking changes. Internal APIs also tend to become partner APIs later, and having the contract ready makes that step much easier.

What is the most common API security mistake?

The most common serious mistake is broken object level authorization, listed first in the OWASP API Security Top 10. The API checks that the caller is signed in but not that they may access the specific record requested, so changing an ID in the URL exposes another customer's data. Test every endpoint for this with two separate accounts.

How should an API handle dates, times and money?

Send dates and times as ISO 8601 strings with an explicit time zone or in UTC, so clients in the UK, UAE and Pakistan read them the same way. Send money as an amount in the smallest sensible unit or as a decimal string, paired with an ISO 4217 currency code. Never rely on floating-point numbers for money.

Next step

Need an API partners can integrate in days?

Share what the API must expose and who will use it. We will draft the OpenAPI contract with you, review the security model and build it to that contract.