Skip to content
Developer Template5 columns · 8 sample rows· Updated

HTTP Status Codes & API Error Mapping Markdown Table Template

An error mapping table is the page of your API docs that client developers keep open while they write error handling. It answers three questions for every failure: which HTTP status will I get, which machine-readable code tells me exactly what went wrong, and what should my code do next. When that information only lives in prose, every SDK and mobile team ends up reverse-engineering it from logs.

Edit This Template

Edit cells, add rows, or sort — the Markdown updates live
Row
1
200 OK
2
400 Bad Request
INVALID_PAYLOAD
3
401 Unauthorized
AUTH_EXPIRED
4
403 Forbidden
ROLE_INSUFFICIENT
5
404 Not Found
ENTITY_NOT_FOUND
6
429 Too Many Requests
RATE_LIMITED
7
503 Service Unavailable
SERVICE_UNAVAILABLE
8
504 Gateway Timeout
UPSTREAM_TIMEOUT
Output
|               HTTP Status | Error Code            | Retryable | Cause / Meaning                                | Client Action                            |
| ------------------------: | :-------------------- | :-------: | :--------------------------------------------- | :--------------------------------------- |
|                  `200 OK` | —                     |    No     | Request completed successfully                 | Process payload                          |
|         `400 Bad Request` | `INVALID_PAYLOAD`     |    No     | Malformed JSON syntax or missing schema fields | Validate request body                    |
|        `401 Unauthorized` | `AUTH_EXPIRED`        |    No     | Bearer token missing, malformed, or expired    | Refresh access token                     |
|           `403 Forbidden` | `ROLE_INSUFFICIENT`   |    No     | User lacks RBAC permission for resource        | Request admin privilege                  |
|           `404 Not Found` | `ENTITY_NOT_FOUND`    |    No     | Target UUID does not exist in database         | Check resource ID                        |
|   `429 Too Many Requests` | `RATE_LIMITED`        |    Yes    | Exceeded 1,000 requests per minute quota       | Backoff with jitter                      |
| `503 Service Unavailable` | `SERVICE_UNAVAILABLE` |    Yes    | Service overloaded or in maintenance           | Retry with exponential backoff           |
|     `504 Gateway Timeout` | `UPSTREAM_TIMEOUT`    |    Yes    | Upstream service did not respond in time       | Retry with backoff; report if persistent |
8 rows × 5 columns
Rendered Preview
HTTP StatusError CodeRetryableCause / MeaningClient Action
200 OK—NoRequest completed successfullyProcess payload
400 Bad RequestINVALID_PAYLOADNoMalformed JSON syntax or missing schema fieldsValidate request body
401 UnauthorizedAUTH_EXPIREDNoBearer token missing, malformed, or expiredRefresh access token
403 ForbiddenROLE_INSUFFICIENTNoUser lacks RBAC permission for resourceRequest admin privilege
404 Not FoundENTITY_NOT_FOUNDNoTarget UUID does not exist in databaseCheck resource ID
429 Too Many RequestsRATE_LIMITEDYesExceeded 1,000 requests per minute quotaBackoff with jitter
503 Service UnavailableSERVICE_UNAVAILABLEYesService overloaded or in maintenanceRetry with exponential backoff
504 Gateway TimeoutUPSTREAM_TIMEOUTYesUpstream service did not respond in timeRetry with backoff; report if persistent

When to Use This Table

The HTTP status is the coarse category that proxies, caches, and generic HTTP clients understand; the error code is the precise, stable identifier your own clients branch on. Keep both. Two different problems often share one status (a 400 can be a malformed body or a failed business rule), so clients should never have to parse the human-readable message to tell them apart.

The Retryable and Client Action columns are what make this table more than a glossary. They turn it into a decision table: a client can safely retry 429 and 503 with backoff, but retrying a 400 will fail forever. If your API returns RFC 9457 Problem Details bodies, add a column for the type URI so each row links to its own documentation.

What Goes in Each Column

ColumnAlignmentWhat to put here
HTTP Statusright ---:The numeric code plus its standard reason phrase, in backticks (429 Too Many Requests). Right-aligned so the three-digit numbers line up. Use the standard reason phrases from RFC 9110 rather than inventing your own.
Error Codeleft :---Your stable, machine-readable identifier in UPPER_SNAKE_CASE. Treat these as part of the API contract: clients branch on them, so never rename one without a deprecation period. One HTTP status can map to several error codes.
Retryablecenter :---:A plain Yes / No, centered. Mark Yes only when repeating the identical request can succeed later without the client changing anything — typically 429, 502, 503, and 504.
Cause / Meaningleft :---One sentence describing what actually went wrong from the client’s point of view. Include concrete limits where they exist (“more than 1,000 requests per minute”) instead of vague wording like “too many requests”.
Client Actionleft :---The concrete next step the client should take: refresh the token, fix a field, back off and retry, or contact support. This column is what developers scan when they are writing a switch statement.

How to Fill It In

  1. 1List every error your API can actually return. The fastest source is your error middleware or exception classes, not memory — undocumented codes are the ones that page someone at 3 a.m.
  2. 2Group them by HTTP status and give each one a stable error code. Reuse a status for several codes when the client needs to react differently to each.
  3. 3Decide retryability per row. If a retry needs a changed request (new token, fixed payload), it is not retryable in this sense — say what to change in Client Action instead.
  4. 4Fill in Cause / Meaning with the real limits and conditions, then check every row against your implementation or integration tests.
  5. 5Keep 2xx rows to a minimum. One success row is useful as a reference point; the value of this table is in the failure rows.

Ready-to-Paste Variations

With RFC 9457 Problem Details type URIs

Use this if your API returns application/problem+json error bodies. The type column links each row to its own documentation page.

| HTTP Status | Problem `type` | Title | Retryable |
| ---: | :--- | :--- | :---: |
| `400` | `https://api.example.com/problems/invalid-payload` | Invalid request body | No |
| `401` | `https://api.example.com/problems/token-expired` | Access token expired | No |
| `409` | `https://api.example.com/problems/version-conflict` | Resource was modified | No |
| `429` | `https://api.example.com/problems/rate-limited` | Rate limit exceeded | Yes |
| `503` | `https://api.example.com/problems/maintenance` | Service temporarily unavailable | Yes |

Compact README version

For a README or changelog where a full mapping is overkill: status, code, and what to do, nothing else.

| Status | Code | What to do |
| ---: | :--- | :--- |
| `401` | `AUTH_EXPIRED` | Refresh the token and retry once |
| `404` | `ENTITY_NOT_FOUND` | Check the resource ID |
| `429` | `RATE_LIMITED` | Wait for `Retry-After`, then retry |
| `503` | `SERVICE_UNAVAILABLE` | Retry with exponential backoff |

Common Mistakes

  • Returning 200 OK with an error object in the body.

    Use a real 4xx/5xx status. Monitoring, caches, and generic HTTP clients all decide success by the status code, so a 200 error is invisible to them.

  • Mixing up 401 and 403.

    401 Unauthorized means “we don’t know who you are” (missing or invalid credentials); 403 Forbidden means “we know who you are, and you can’t do this”. Re-authenticating fixes a 401 but never a 403.

  • Using 503 for a gateway timeout.

    503 Service Unavailable is for overload or maintenance; 504 Gateway Timeout is for an upstream that didn’t answer in time. Both are retryable, but they point operators at different problems.

  • Telling clients to retry everything.

    Retrying a 400 or 422 just repeats the failure. Limit automatic retries to rows marked Yes, and always use exponential backoff with jitter so clients don’t retry in lockstep.

Browse all 50 templates
FAQ

HTTP Status Codes & API Error Mapping: Frequently Asked Questions

Should I document every HTTP status code?

No. Document the statuses your API actually returns, plus the error codes behind each one. A table of all 60-odd registered status codes tells your users nothing about your API.

What is the difference between 400 and 422?

400 Bad Request is the general “this request is malformed” response, such as invalid JSON. 422 Unprocessable Content means the syntax was fine but the content failed validation, such as an end date before the start date. Many APIs use only 400; if you use both, document which validation failures return which.

How should clients handle 429 Too Many Requests?

Read the Retry-After response header if you send one, wait that long, then retry. Without the header, use exponential backoff with random jitter. Document your actual rate limits in the Cause / Meaning column so clients can stay under them.

Is a 401 retryable?

Not as-is. The same request with the same expired token will fail again. The client should refresh or re-acquire the token first, which is why the template marks it No and puts “Refresh access token” in Client Action.