API guide
How to Design Predictable REST APIs in 2026
Design predictable REST APIs with current HTTP semantics, precise status codes, machine-readable errors, pagination, PATCH formats, and explicit version policies.

How to Design Predictable REST APIs in 2026
A usable REST API makes resources, state changes, failures, and continuation rules predictable. Start from HTTP semantics, document the choices your interface makes, and test the contract from a client's point of view.
TL;DR verdict
Use nouns for resources, standard methods for intent, precise status codes, one documented error contract, and pagination that exposes a reliable continuation mechanism. RFC 9110 defines current HTTP semantics. RFC 9457 defines machine-readable problem details. For partial updates, RFC 7396 and RFC 6902 describe different media types and behaviors; choose deliberately rather than treating PATCH as self-explanatory.
API fit matrix
| Operation | Method | Typical success | Contract question |
|---|---|---|---|
| Read a collection | GET /orders | 200 | How are filtering, ordering, and continuation represented? |
| Read one resource | GET /orders/{id} | 200 | Does absence use 404, or is existence deliberately concealed? |
| Create a resource | POST /orders | 201 | Is Location returned, and can the request be retried safely? |
| Replace a resource | PUT /orders/{id} | 200 or 204 | Which omitted fields are cleared? |
| Partially update | PATCH /orders/{id} | 200 or 204 | Which patch media type and null semantics apply? |
| Remove a resource | DELETE /orders/{id} | 204 | Is deletion reversible, and what happens on a repeated request? |
| Queue work | POST /exports | 202 | Where can the client observe completion or failure? |
HTTP supplies semantics; the API contract still needs to define the resource lifecycle.
Resource and URL design
Use plural resource nouns and shallow relationships:
GET /users
POST /users
GET /users/{user_id}
GET /users/{user_id}/orders
POST /invoices/{invoice_id}/payments
Prefer a sub-resource such as payments to a command-style path such as /pay. Use path parameters to identify resources and query parameters to filter or shape a representation. Keep parameter names consistent across collections.
Auth matrix
| Condition | Status | Response guidance |
|---|---|---|
| Credential missing or invalid | 401 | State the authentication scheme without echoing credentials |
| Actor authenticated but action denied | 403 | Identify the required permission only when safe |
| Resource existence intentionally concealed | 404 | Use the normal not-found shape |
| Credential accepted but provider quota intervenes | Provider contract | Preserve the provider's status, headers, and request ID |
Send bearer credentials in the Authorization header, never in a query string. Keep authentication, authorization, quota, and resource-state errors distinguishable to client code.
Status codes as interface behavior
Choose the narrowest status that matches what happened:
201for a created resource;202when work was accepted but is not complete;400for malformed or otherwise bad request content under the published contract;401for absent or invalid authentication;403for a denied authenticated action;404for an absent or deliberately concealed resource;409for a state conflict;422when the content is syntactically valid but its instructions cannot be processed;429for rate limiting where appropriate; and5xxfor server-side failure conditions.
Do not infer client action from the number alone. A response body, headers, method, and idempotency contract can all change what a safe next step looks like.
SDK quality table
| SDK behavior | What the client needs | Test |
|---|---|---|
| Typed resources | Stable request and response types | Unknown optional fields do not break decoding |
| Typed error | Status, machine code, parameter context, and request ID remain accessible | Validation and quota failures map predictably |
| Pagination | Continuation links or tokens are exposed without manual parsing | Traverse multiple pages and an empty final page |
| Retry control | Provider headers and idempotency options remain visible | Simulate response loss after a mutation |
| Version selection | The active API version is explicit | Contract test sends and verifies the expected version |
Error response design
RFC 9457 provides a standard format for machine-readable problem details. A service may use that format or a documented vendor schema, but clients should not have to parse prose to identify a condition.
{
"type": "https://docs.example.test/problems/invalid-parameter",
"title": "Validation failed",
"status": 422,
"detail": "The email field is not valid.",
"instance": "/requests/req_abc123",
"errors": [
{ "field": "email", "code": "invalid_format" }
]
}
Stripe is a named production example: its documentation describes conventional response classes and conditional fields for a typed error, including parameter context and request_log_url. That is observable behavior, not a requirement that another API copy every field.
A correlation identifier changes the support exchange from "I got an error," to a request that operators can locate. Clear field details also replace the unhelpful "I got this error, what does it mean?" loop with a specific correction.
Rate-limit box
RFC 6585 defines 429. GitHub documents that secondary limits can return 403 or 429. It tells clients to wait when Retry-After is present and otherwise follow its documented backoff guidance.
Treat quotas as provider-specific quotas. A client should:
- inspect the actual status, headers, and body;
- honor a valid delay when supplied;
- replay only a safe or idempotency-protected operation;
- cap attempts and elapsed time; and
- preserve request identifiers in logs.
Pagination choices
GitHub's REST documentation uses the Link response header for pagination and documents official Octokit helpers. Link relations let a client follow available pages without manufacturing URLs.
Offset, cursor, and link-based pagination each fit different data and navigation needs. If a product requirement says "page 3 of 10.", an opaque forward-only cursor may not fit. If records change during traversal, a stable cursor or snapshot can be safer than a deep offset. Publish ordering, limit bounds, termination, and mutation behavior.
Integration risk box
| Risk | Client symptom | Control |
|---|---|---|
| Inconsistent resource names | Callers guess paths | One naming guide and contract tests |
| Ambiguous PATCH behavior | {"bio": null}, does that mean clear or ignore? | Declare the patch media type and examples |
| Prose-only errors | Client cannot branch safely | Stable machine code or problem type |
| Pagination URLs are reconstructed | Clients break when query rules change | Return links or an opaque continuation token |
| Version is implicit | Behavior changes without a visible contract | Make version selection and support policy explicit |
| Unsafe automatic retries | Mutations are duplicated | Document idempotency and retry conditions |
A breaking change includes any contract change that requires a working client to alter its behavior. Additive fields are safe only when clients are required and tested to ignore unknown fields.
PATCH: two interoperable choices
JSON Merge Patch (RFC 7396) uses application/merge-patch+json. An absent member is unchanged; a member with null removes that object member. In plain language, null means "delete/clear the field." That differs from "leave the bio field unchanged (I'm not sending it)".
JSON Patch (RFC 6902) uses application/json-patch+json and an ordered operation sequence such as add, remove, replace, and test. It can express conditional or multi-step changes but requires a different parser and contract.
Choose from the operations your clients need. Document idempotency separately.
Versioning with current identities
RFC 9110 is the current HTTP semantics reference, and RFC 9457 obsoletes the earlier Problem Details specification. RFC 7396 and RFC 6902 remain the referenced JSON patch standards.
GitHub's current REST documentation lists 2026-03-10 and 2022-11-28 as supported versions, with 2022-11-28 scheduled through March 10, 2028. That is GitHub's dated support policy, not a general retention period for every API.
Source-backed evidence
Evidence for standards-based interface behavior
The RFCs support HTTP semantics, 429 behavior, Problem Details, JSON Merge Patch, and JSON Patch.
Named production examples
GitHub supports the pagination, rate-limit, and version examples. Stripe supports the documented error attributes. They are named production examples, not rankings.
Editorial limits
Resource naming, nesting depth, envelope choice, and retry budgets are API design choices. Validate them through client contract tests.
The claim classes used for course popularity are not applicable to API design; they were omitted rather than repurposed.
Methodology
APIScout reviewed the five RFCs and the current GitHub and Stripe documentation listed below on 2026-08-22. Unsupported preference percentages, provider rankings, placeholder evidence links, and generic version-retention rules were removed.
Source-backed FAQ
Should validation use 400 or 422?
Publish one consistent rule. RFC 9110 defines 422 for content whose syntax is understood but whose instructions cannot be processed; an API can still document 400 for its validation cases.
Must PATCH use JSON Merge Patch?
No. JSON Merge Patch and JSON Patch have distinct media types and behaviors. Use the one that fits the required operations, or define and document another contract.
Should clients construct pagination URLs?
Prefer returned links or documented opaque tokens. Reconstructing URLs couples the client to query details the server may need to change.
What does 410 tell a client?
It states that the target resource is no longer available and the condition is likely permanent: "stop requesting this URL." Use it only when the service can make that lifecycle statement.
How should a client distinguish validation failures?
Preserve a stable machine code and field detail. That lets a UI distinguish "my JSON is broken" from "my data is invalid" without parsing a message.
Sources
- RFC 9110: HTTP Semantics — accessed 2026-08-22
- RFC 9457: Problem Details for HTTP APIs — accessed 2026-08-22
- RFC 7396: JSON Merge Patch — accessed 2026-08-22
- RFC 6902: JSON Patch — accessed 2026-08-22
- RFC 6585: Additional HTTP Status Codes — accessed 2026-08-22
- GitHub: Using pagination in the REST API — accessed 2026-08-22
- GitHub: Rate limits for the REST API — accessed 2026-08-22
- GitHub: API Versions — accessed 2026-08-22
- Stripe: Errors — accessed 2026-08-22
Designing APIs? Explore API design tools and patterns on APIScout.
Related guides
{/* Sources: rest-github-pagination, rest-github-rate-limits, rest-github-versions, rest-rfc6585, rest-rfc6902, rest-rfc7396, rest-rfc9110, rest-rfc9457, rest-stripe-errors. Claims: apiscout:how-to-design-rest-api-developers-love-2026:plan_or_rate_limits, apiscout:how-to-design-rest-api-developers-love-2026:ratings_reviews_enrollment, apiscout:how-to-design-rest-api-developers-love-2026:release_version_status, apiscout:how-to-design-rest-api-developers-love-2026:compatibility_integrations, apiscout:how-to-design-rest-api-developers-love-2026:product_capabilities, apiscout:how-to-design-rest-api-developers-love-2026:ranking_popularity_superlative. */}
The API Integration Checklist (Free PDF)
Step-by-step checklist: auth setup, rate limit handling, error codes, SDK evaluation, and pricing comparison for 50+ APIs. Used by 200+ developers.
Join 200+ developers. Unsubscribe in one click.