Most API failures begin as contract decisions that seemed harmless: an endpoint whose response shape changes without warning, a collection that grows until requests time out, or a retry that creates the same order twice. The five mistakes below are practical failure patterns for HTTP and REST-style APIs (some also apply to RPC systems, including gRPC). They are not a measured ranking of frequency. For each one, you will find a safer design, implementation details, and tests you can automate.
1. Leaving the API contract unclear or inconsistent
An API is a contract between independently changing software. Clients need predictable resource names, HTTP methods, status codes, representations, and error behavior. Inconsistency forces every consumer to write exceptions, and undocumented behavior becomes an accidental dependency.
Use standard HTTP semantics deliberately
- Use nouns for resources (for example,
/customersand/customers/123), not verb-heavy paths such as/createCustomer. - Use methods consistently:
GETreads,POSTcreates or starts a non-idempotent action,PUTreplaces a known resource,PATCHapplies a partial update, andDELETEremoves or deactivates a resource. - Document success and failure status codes. A validation failure should not sometimes be
400and sometimes422without a stated rule. - Publish the exact request and response fields, types, required values, pagination behavior, authentication requirements, and error schema.
Microsoft’s Web API Design Best Practices and API Design guidance both emphasize consistency and an explicit contract. An OpenAPI document can make that contract reviewable and generate client and server checks, but it does not replace examples and behavioral tests.
Make errors useful without leaking internals
Return a stable machine-readable shape, such as an error code, a human message, and field-level details. Include a request or correlation ID so support teams can find the server-side event. Do not return stack traces, SQL fragments, access tokens, or internal hostnames.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
- API Design Patterns
- ABIS BOOK
- Manning Publications
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"error": {
"code": "invalid_field",
"message": "email must be a valid address",
"field": "email",
"request_id": "req_7f31"
}
}
Contract tests should assert both the documented shape and the status code for representative success, validation, authentication, authorization, not-found, conflict, and rate-limit cases.
2. Returning unbounded collections
An endpoint such as GET /events may work with 200 rows and fail after a year of production data. Unbounded responses consume memory, bandwidth, database time, and client parsing capacity. They also make latency unpredictable.
Bound every list request
Require pagination and document a server maximum. A client-requested limit=10,000 should either be capped to the documented maximum or rejected with a clear validation error; never let the database decide implicitly.
GET /v1/events?status=open&limit=50&cursor=eyJpZCI6IjEwMDAifQ
Cursor pagination is usually safer for changing datasets because it avoids large offsets and reduces duplicates or skips while rows are inserted. Offset pagination (page=4&page_size=50) can be easier for numbered pages and reports. Whichever model you choose, define ordering, cursor expiry, and whether records created during traversal appear in later pages.
| Design choice | Client behavior | Trade-off to document |
|---|---|---|
| Cursor | Send the returned cursor until it is absent | Stable traversal; cursors may expire and are not human-readable |
| Offset/page | Request a page number and size | Simple navigation; deep pages can become slow or shift as data changes |
| Maximum page size | Request up to the stated limit | Protects resources; clients must handle a smaller returned page |
Add filtering and field selection
Filtering by status, time range, or owner prevents clients from downloading data they will discard. A sparse field option (for example, fields=id,name) can reduce payloads, but document defaults and authorization implications. Index the filters and sort keys you support, and reject unsupported combinations rather than silently ignoring them.
Rank #2
Test the empty collection, exactly-one-page, multiple-page, maximum-size, invalid-cursor, and concurrent-write cases. Monitor response size and query duration so a new field or join does not quietly make a bounded endpoint expensive.
3. Breaking consumers during API evolution
Removing a response field, changing a field’s type, tightening accepted values, or changing the meaning of a status can break clients that you do not control. Adding a response field is commonly compatible when clients ignore unknown fields, but verify that your client ecosystem actually does so.
Classify changes before shipping
- Usually additive: a new optional response field, a new endpoint, or a new optional request field (provided old validation and defaults remain unchanged).
- Potentially breaking: renaming or removing fields, changing types or enum meanings, altering default sorting, making an optional field required, or changing authentication scopes.
- Operationally breaking: lower rate limits, smaller maximum pages, changed timeout behavior, or a new requirement for a header.
For a breaking contract, introduce a new version and keep the previous version available while clients migrate. Microsoft discusses URI, query-string, header, and media-type versioning in its design guidance. There is no universal winner:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errors| Versioning style | Strength | Cost or caveat |
|---|---|---|
URI, such as /v2/ |
Obvious in logs, documentation, and links | Creates distinct URLs and can complicate link or cache management |
| Query parameter | Easy to add to an existing route | Clients can omit it accidentally; cache keys must include it |
| Custom header | Keeps resource URLs stable | Less visible when copying links; tooling and caches must vary on the header |
| Media type | Expresses representation version in content negotiation | Harder to discover and configure in simple clients |
Give migration a real path
Publish a change log, deprecation date, side-by-side examples, and a mapping from old fields to new ones. Emit a deprecation signal where appropriate, measure traffic by version, and contact owners of active clients. Keep old and new contract tests running until the retirement date. Never assume that a version label alone solves semantic changes; explain what clients must alter.
4. Assuming a retry cannot repeat work
A network timeout tells a client only that it did not receive a response. The server may have completed the operation. Retrying a non-idempotent POST can therefore create two payments, jobs, or shipments.
Rank #3
Define idempotency explicitly
Microsoft’s Web API Implementation guidance recommends idempotent behavior for GET, PUT, DELETE, HEAD, and PATCH: repeating the same request should leave the resource in the same state, even if a later response status differs. That does not mean every retry is safe; authorization, validation, side effects, and time-dependent operations still need defined semantics.
For a create operation, accept an idempotency key:
POST /v1/payments
Idempotency-Key: 4b1d9c2e-6f5b-4f0d-a7c1-91c0b1d5a2e8
Content-Type: application/json
{"amount": 2500, "currency": "USD"}
Store the key with the operation result (and a request fingerprint). A repeat with the same key and identical parameters returns the original result; a reuse with different parameters is rejected. Microsoft also describes tracking processed message IDs to handle duplicates. Define retention, key scope, and what happens after an internal failure.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Retry only the failures you understand
- Retry connection resets, selected 5xx responses, and
429responses when the service documents them as transient. - Honor
Retry-Afterand use exponential backoff with jitter. - Do not blindly retry authentication failures, validation errors, or a non-idempotent request without a key.
- Set a deadline and surface an uncertain outcome for reconciliation instead of issuing unlimited attempts.
Test a timeout after the server commits, a client retry with the same key, a retry with changed parameters, and a delayed duplicate arriving after the key’s retention window.
5. Treating security as only authentication
Authentication answers “who is calling?” Authorization answers “may this caller perform this action on this specific object?” A valid token must not let one customer read another customer’s invoice simply because the URL ID was changed.
Authorize every object and action
Perform an object-level permission check after loading the resource and before returning or mutating it. Check tenant boundaries, ownership, roles, scopes, and the requested operation. Avoid predictable identifiers as the only protection; opaque IDs help reduce guessing but never replace authorization.
Validate input and limit resource use
- Validate type, length, encoding, ranges, and allowed values at the boundary.
- Use parameterized queries and context-appropriate output encoding.
- Limit request body size, upload dimensions, query complexity, pagination size, and execution time.
- Rate-limit expensive or sensitive operations and return
429 Too Many Requestswhen a request is rejected for rate limiting, as described in the OWASP REST Security Cheat Sheet. - Log security-relevant events without logging secrets or personal data unnecessarily.
The OWASP API Security Project identifies broken authentication, broken object-level authorization, security misconfiguration, and inadequate resource limits among major API risks. Return actionable client errors, but keep implementation details in protected logs.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →How to test these protections in a delivery pipeline
- Review the OpenAPI contract with API consumers before implementation.
- Run schema and contract tests against every endpoint and version.
- Generate pagination tests at zero, one, maximum, and over-maximum limits.
- Inject timeouts and duplicate deliveries to verify idempotency and reconciliation.
- Run authorization tests using two users and two tenants, including guessed and altered object IDs.
- Load-test realistic filters and maximum pages; watch database plans, memory, latency, and 429 behavior.
- Scan dependencies and configuration, then verify that production errors omit secrets.
For browser-rendered API documentation, demos, or status pages, you can capture a deterministic visual snapshot as part of a review. ScreenshotNeo is a website screenshot API and MCP server; its clean-shot mode accepts consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture.
Or skip the browser setup
One GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo documentation for all options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
Troubleshooting checklist
Clients report random 400, 404, or 500 responses
Compare the failing request with the published contract, including method, content type, required headers, and path version. Check correlation IDs and server logs; do not ask clients to guess undocumented behavior.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Large lists still time out
Confirm the server enforces a maximum, inspect the database plan for each supported filter and sort, and reduce default fields. A pagination parameter that is accepted but ignored is not pagination.
Best Value
A new release breaks an older app
Classify the change, restore the old behavior or version the endpoint, publish a migration example, and measure remaining traffic before deprecating the old contract.
Retries create duplicates
Reproduce a timeout after commit, add an idempotency key or processed-message store, and return the stored result for an identical repeat. Document key expiry and parameter mismatches.
A user can access another user’s object
Add an explicit object-level authorization test with two identities and tenants. Enforce the check server-side for every read and write; never rely on hidden UI controls.
Legitimate clients receive 429
Inspect which identity, route, and resource the limit measures, return Retry-After when useful, and make the limit and response behavior part of the contract.
Frequently Asked Questions
Do all five mistakes apply to GraphQL or gRPC?
The contract, pagination or resource limits, compatibility, retry, and authorization principles still matter, but the concrete mechanisms differ. HTTP method and status-code advice is specific to HTTP APIs; Google and Microsoft document protocol-specific variations.
Should an API always use URL versioning?
No. URI, query-string, header, and media-type versioning each affect discoverability, compatibility, migration work, links, and caching differently. Choose one deliberately and document it.
Is every POST request unsafe to retry?
A POST is not inherently safe to repeat. Retry it only when the operation defines duplicate protection, such as an idempotency key or processed-message record, and the client can reconcile an uncertain result.
Recommended Free Tools
What should a 429 response contain?
Return a stable error body and, when possible, a Retry-After value or equivalent guidance. Document the limit’s scope and the conditions for retrying.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




