Your API returns a 500 error. The developer integrating with your service doesn't know if it's temporary or permanent, whether to retry, how long to wait, or if they did something wrong. They retry immediately 50 times in a row, DDoS'ing your already-struggling server. Meanwhile, they're cursing your documentation because all it says is "500: Internal Server Error" with no guidance on what to do.
Or your API returns 403 Forbidden when it should return 404 Not Found. The developer spends hours debugging their authentication, convinced their credentials are wrong, when actually they're just requesting a resource that doesn't exist. Your mixing of 403 and 404 codes based on permission visibility created more confusion than clarity.
HTTP status codes are your API's primary communication mechanism for errors and responses. Good documentation doesn't just list codes—it explains what each means in your specific context, when you use it, and critically, what developers should do when they receive it. This guide breaks down how to document HTTP status codes clearly to prevent common integration mistakes.
Why Status Code Documentation Matters
HTTP status codes are standardized, right? Everyone knows what 404 means. Why document them?
Because the standard definitions are incomplete for real-world API design. The RFCs tell you 404 means "Not Found" but they don't tell you:
- Should you return 404 or 403 when a resource exists but user lacks permission?
- When exactly do you return 200 vs. 201 vs. 204?
- What's in the response body for each code?
- Should clients retry on 500 errors? How long should they wait?
- What's the difference between 401 and 403 in your API?
- How do your rate limits work and what happens at 429?
Developers integrating with your API need to know your specific implementation decisions. Without clear documentation, they'll guess—and guess wrong, leading to flaky integrations, poor error handling, and frustrated developers.
The Essential Status Code Reference Table
Start your documentation with a comprehensive table. This gives developers a quick reference without reading paragraphs of explanation.
What to Include in the Table
For each status code you use, include:
- Code: The numeric status code (404)
- Name: Standard name (Not Found)
- When Used: Specific scenarios in your API
- Response Body: What's in the response
- Client Action: What developers should do
Example entry:
404 Not Found
When Used: Resource ID doesn't exist or was deleted
Response Body: Error object with resource type and ID
Client Action: Verify resource ID, check if deleted, don't retry
Group by Category
Organize codes into standard categories:
- 2xx Success: Request succeeded
- 3xx Redirection: Further action needed
- 4xx Client Error: Client did something wrong
- 5xx Server Error: Server failed to fulfill valid request
This grouping helps developers quickly understand fault: 4xx = their problem to fix, 5xx = your problem (but they should retry).
Explaining 2xx Success Codes
Success codes seem straightforward but subtle differences matter.
200 OK vs. 201 Created vs. 204 No Content
These are often confused. Here's when to use each:
200 OK: General success. Use for:
- Successful GET returning data
- Successful PUT/PATCH updating resource
- Successful DELETE that returns confirmation data
Response includes the requested or updated resource.
201 Created: New resource created. Use for:
- Successful POST creating new resource
Response includes:
- The created resource in body
- `Location` header with URL of new resource
- Resource ID
204 No Content: Success with no data. Use for:
- Successful DELETE with no return data
- Successful update with no changed data to return
Response body is empty. Saves bandwidth for operations where response data isn't needed.
Document your choice:
"We return 201 Created for POST requests that create resources, with the new resource in the response body and its URL in the `Location` header. We return 204 No Content for DELETE requests since there's no meaningful data to return after deletion."
202 Accepted for Async Operations
If your API processes requests asynchronously (background jobs), 202 is critical:
"We return 202 Accepted for operations that take longer than 5 seconds. The response includes a job ID and status check URL. Poll the status URL until the job completes."
Example response:
```json
HTTP/1.1 202 Accepted
{
"job_id": "job_abc123",
"status": "processing",
"status_url": "https://api.example.com/jobs/job_abc123",
"estimated_completion": "2024-12-15T10:35:00Z"
}
```
Explain the polling pattern and how often to check ("Poll every 5 seconds, max 100 times before timing out").
The 4xx Client Errors: Blame Assignment
4xx codes mean the client did something wrong. Your documentation must explain what went wrong and how to fix it.
400 Bad Request: Be Specific
"Bad Request" is vague. Your API should return detailed validation errors:
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"message": "Invalid email format",
"received": "not-an-email"
},
{
"field": "age",
"message": "Must be a number between 1 and 120",
"received": "not a number"
}
]
}
}
```
Document your error response format and explain that developers should NOT retry 400 errors without fixing the request.
401 vs. 403: The Authentication vs. Authorization Confusion
Developers constantly confuse these. Make the distinction crystal clear:
401 Unauthorized: "Who are you?"
- No credentials provided
- Invalid API key
- Expired access token
Action: Provide valid authentication credentials.
403 Forbidden: "I know who you are, but you can't do this."
- Authenticated successfully
- Lacks required permission
- Account suspended
- IP blocked
Action: Request permission, use different account, or contact admin.
Document explicitly:
"401 means authentication failed—check your API key or access token. 403 means you're authenticated but lack permission for this operation—you'll need the `users:write` permission to modify users."
404 vs. 403 for Security
Here's a design decision: If a user requests a resource they're not allowed to see, should you return 404 (resource doesn't exist) or 403 (you can't access this)?
403 (honest): Reveals the resource exists, potentially leaking information.
404 (security through obscurity): Hides existence of resource, but might confuse developers.
Most APIs choose 404 for security. Document this:
"We return 404 Not Found for resources that don't exist OR that you don't have permission to view. This prevents information disclosure. If you expected a resource to exist and get 404, verify both the resource ID and your permissions."
422 Unprocessable Entity for Semantic Validation
Use 422 when request is syntactically valid but semantically wrong:
- 400: JSON is malformed, required field missing
- 422: JSON is valid, but email domain is blacklisted, or withdrawal amount exceeds balance
Explain the distinction and when you use each.
Documenting your API's status codes and error handling?
River's AI creates comprehensive HTTP status code reference tables with examples, retry logic guidance, and client handling advice specific to your API.
Generate API DocsThe 5xx Server Errors: Retry Guidance is Critical
5xx errors mean you (the API) messed up, not the client. But clients still need to know what to do.
500 Internal Server Error
This is your catch-all for unexpected errors. Documentation should address:
What it means: "Something unexpected went wrong on our end. It's not your fault."
What to include in response:
- Generic error message (don't expose stack traces)
- Request ID for support/debugging
- Link to status page if applicable
Retry guidance: "500 errors are often transient. Retry with exponential backoff (wait 1s, then 2s, then 4s, etc.). If errors persist after 5 attempts, alert your on-call team."
503 Service Unavailable
Use this for planned maintenance or when deliberately returning errors due to overload.
Always include `Retry-After` header indicating when to retry:
```http
HTTP/1.1 503 Service Unavailable
Retry-After: 300
```
"Retry-After: 300" means wait 300 seconds (5 minutes) before retrying.
Document: "503 means we're temporarily unavailable (maintenance or overload). Check the `Retry-After` header and wait that many seconds before retrying. Don't retry immediately or you'll make overload worse."
502 vs. 504: Gateway Errors
502 Bad Gateway: Upstream service returned invalid response
504 Gateway Timeout: Upstream service didn't respond in time
Both suggest transient issues with dependencies. Retry guidance:
"502 and 504 indicate problems with our upstream services. These are usually temporary. Retry with exponential backoff. If you're seeing consistent 504s, your requests may be too complex or timing out—consider breaking them into smaller requests."
Rate Limiting (429) and Retry-After
Rate limiting is essential but often poorly documented. Developers need to understand:
Your Rate Limit Policy
Be explicit about limits:
"Rate limits per API key:
- Free tier: 100 requests/minute
- Pro tier: 1,000 requests/minute
- Enterprise: Custom limits
Limits are per API key with rolling 60-second windows. Exceeding limits returns 429 Too Many Requests."
Rate Limit Headers
Include rate limit info in every response:
```http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1702650000
```
Explain each header:
- X-RateLimit-Limit: Max requests in current window
- X-RateLimit-Remaining: Requests left in window
- X-RateLimit-Reset: Unix timestamp when limit resets
Handling 429 Errors
Provide clear guidance:
"When you receive 429:
- Read the `Retry-After` header (seconds to wait)
- Wait that many seconds
- Retry your request
- Monitor `X-RateLimit-Remaining` to avoid future rate limits
Don't retry immediately—you'll just get rate limited again. Consider batching requests, caching responses, or upgrading your plan if you regularly hit rate limits."
Idempotency and Safe Retries
Critical concept developers need to understand: which methods are safe to retry?
Idempotent Methods (Safe to Retry)
- GET: Reading data, no side effects
- PUT: Updating to specific state (repeating = same result)
- DELETE: Deleting already-deleted resource = still deleted
"GET, PUT, and DELETE are idempotent. Retrying these methods (even multiple times) is safe and won't cause duplicate effects."
Non-Idempotent Method (POST)
POST is dangerous to retry:
"POST creates new resources or triggers actions. Retrying a POST may create duplicate resources or trigger duplicate actions (double charges, duplicate emails, etc.)."
Idempotency Keys for POST
If you support idempotency keys, document them:
"To safely retry POST requests, include an `Idempotency-Key` header with a unique value (we recommend UUIDs):
```http
POST /api/payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
```
If your request fails or times out, retry with the SAME idempotency key. We'll recognize the duplicate and return the original result instead of creating a duplicate payment.
Idempotency keys expire after 24 hours. Use a new key for genuinely new requests."
Retry Logic Best Practices
Provide developers with concrete retry guidance, ideally with code examples.
When to Retry
Retry these codes:
- 408 Request Timeout
- 429 Too Many Requests (after waiting)
- 500 Internal Server Error
- 502 Bad Gateway
- 503 Service Unavailable
- 504 Gateway Timeout
- Network errors (connection failed, timeout)
Never retry these codes:
- 400 Bad Request
- 401 Unauthorized (fix auth first)
- 403 Forbidden
- 404 Not Found
- 422 Unprocessable Entity
Exponential Backoff
Explain and provide example:
"Use exponential backoff with jitter to avoid thundering herd:
```python
import random
import time
def make_request_with_retry(url, max_attempts=5):
for attempt in range(max_attempts):
response = requests.get(url)
if response.status_code < 500:
return response
if attempt < max_attempts - 1:
wait = (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait)
raise Exception("Max retries exceeded")
```
This waits 1s, 2s, 4s, 8s, 16s (with random jitter) between retries."
Common Mistakes in Status Code Documentation
Only listing status codes without context: "404: Not Found" tells developers nothing about your specific usage.
No retry guidance: Developers don't know whether to retry, how long to wait, or how many times to try.
Inconsistent error response format: Sometimes errors are strings, sometimes objects, sometimes arrays. Pick one format and stick to it.
No client action guidance: Every status code explanation should answer: "What do I do now?"
Missing rate limit documentation: Developers hit rate limits and don't know why or how to fix it.
Confusing 401 and 403: Use them consistently and explain the difference clearly.
No request IDs in errors: When developers contact support about errors, they have no way to reference specific failed requests.
Key Takeaways
HTTP status code documentation must go beyond RFC definitions to explain your specific implementation decisions. Provide comprehensive reference tables showing when each code is used, what's in the response, and what action clients should take.
Distinguish clearly between 401 (authentication failed) and 403 (authorization failed). Explain whether you return 404 or 403 for permission-denied resources and why.
For 4xx errors, provide detailed error response bodies with field-specific validation errors. Make it clear these shouldn't be retried without fixing the request.
For 5xx errors, provide retry guidance with exponential backoff recommendations. Include `Retry-After` headers for 429 and 503 responses. Explain which methods are safe to retry (GET, PUT, DELETE) vs. dangerous (POST without idempotency keys).
Document your rate limiting policy, include rate limit headers in responses, and explain how to handle 429 errors. Provide code examples for retry logic and idempotency key usage.
The status codes that cause fewest integration problems are the ones with clearest documentation about what they mean in your API and what developers should do when they receive them.