Article

The Ultimate Guide to HTTP Status Codes: Designing Robust API Contracts

DKDhaval Kurkutiya
10 min read
The Ultimate Guide to HTTP Status Codes: Designing Robust API Contracts

When designing or integrating APIs, HTTP status codes are your primary communication channel. They aren't just arbitrary numbers; they form a standardized contract between the client and the server. Using them correctly is the difference between a clean, self-documenting REST API and a chaotic, unpredictable integration nightmare.

In this guide, we will dissect all the major HTTP status codes, group them by their class, discuss when to use them in production systems, and highlight senior-level design tips.


The Big Picture: Status Code Classes

HTTP status codes are three-digit integers divided into 5 distinct classes based on the first digit:

  • 1xx — Informational: Request received, continuing process.
  • 2xx — Success: The action was successfully received, understood, and accepted.
  • 3xx — Redirection: Further action must be taken to complete the request.
  • 4xx — Client Error: The request contains bad syntax or cannot be fulfilled.
  • 5xx — Server Error: The server failed to fulfill an apparently valid request.

Let's dive deep into each category.


1xx — Informational Codes

Informational codes are low-level protocol handshake helpers. They are rarely handled directly by web application code, but are critical for web servers and protocols.

100 Continue

The server has received the request headers and the client should proceed to send the request body (e.g., in a large POST request).

  • Production Tip: Useful when uploading large files. The client sends the Expect: 100-continue header. If the server approves the headers (e.g., file type is valid, user is authorized), it returns 100 Continue, saving bandwidth if the request would have been rejected anyway.

101 Switching Protocols

The requester has asked the server to switch protocols and the server has agreed to do so.

  • Real-World Example: Initiating a WebSocket connection. The client sends an HTTP request with Upgrade: websocket, and the server responds with 101 Switching Protocols before upgrading the TCP socket.

102 Processing

An interim response used to inform the client that the server has accepted the complete request, but has not yet completed it.

  • Usage: Used in WebDAV environments or long-running queries to prevent the client from timing out.

2xx — Success Codes

These codes tell the client that the operation was successful. Selecting the right success code makes your API highly expressive.

200 OK

The standard response for successful HTTP requests.

  • Usage: Returning a resource on GET, or performing a successful update on PUT/PATCH where the updated resource is returned.

201 Created

The request has been fulfilled and has resulted in one or more new resources being created.

  • Usage: Successful POST requests.
  • Best Practice: The response should ideally include a Location header containing the URL of the newly created resource, and the response body should contain the created resource payload.
    code
    HTTP/1.1 201 Created
    Location: /api/v1/users/42
    Content-Type: application/json
     
    {
      "id": 42,
      "username": "dhavalkurkutiya",
      "createdAt": "2026-06-01T04:30:00Z"
    }

202 Accepted

The request has been accepted for processing, but the processing has not been completed.

  • Usage: Asynchronous or background tasks (e.g., generating a heavy PDF report, processing a video upload).
  • Best Practice: Return a polling URL or a task ID in the payload so the client can check the progress of the job.

204 No Content

The server successfully processed the request, but is not returning any content.

  • Usage: Successful DELETE requests, or POST/PUT requests where the UI does not need to refresh any local state.
  • Constraint: The response must not contain a body.

206 Partial Content

The server is delivering only part of the resource due to a range header sent by the client.

  • Usage: Multi-part downloads, video/audio streaming players, or resuming paused downloads. The client requests a range (e.g., Range: bytes=0-1023) and the server replies with 206 Partial Content.

3xx — Redirection Codes

Redirections tell the client to look elsewhere for the resource.

The Crucial Redirection Nuance: 301/302 vs 307/308

There is a critical architectural distinction between these two groups of redirection codes:

  • 301 / 302: Originally designed to redirect. However, many browsers historically changed the HTTP method from POST to GET for the redirected request (ignoring the original request body).
  • 307 / 308: Strictly enforce that the HTTP method and request body cannot be changed during redirection.
code
Request: POST /api/v1/old-endpoint (with body)

          HTTP 301 Redirect to /api/v1/new-endpoint

Browser / Client: GET /api/v1/new-endpoint (Body is LOST!)
 
---------------------------------------------------------
 
Request: POST /api/v1/old-endpoint (with body)

          HTTP 308 Redirect to /api/v1/new-endpoint

Browser / Client: POST /api/v1/new-endpoint (Body is PRESERVED!)

301 Moved Permanently

The target resource has been assigned a new permanent URI. Any future references to this resource should use the returned URI.

  • Usage: Domain migrations, or restructuring URL paths (e.g., changing /old-blog to /blog).

302 Found (Temporary Redirect)

The target resource resides temporarily under a different URI.

  • Usage: Short-term campaign redirects, geo-targeting based routing.

304 Not Modified

Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match.

  • Usage: Browser and CDN caching.
  • Benefit: The server does not send a response body, saving massive amounts of outbound bandwidth and network latency.

307 Temporary Redirect

The target resource resides temporarily under a different URI, preserving the HTTP method.

308 Permanent Redirect

The target resource has been permanently moved to a new URI, preserving the HTTP method.


4xx — Client Error Codes

Client errors indicate that there is something wrong with the client's request. Expressive 4xx error handling is a hallmark of premium APIs.

400 Bad Request

The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax, size too large).

  • Usage: When the client sends invalid JSON syntax. Do not use this for semantic validation errors (use 422 instead).

401 Unauthorized vs 403 Forbidden

One of the most common points of confusion in web security:

  • 401 Unauthorized: "I don't know who you are." The client has not provided authentication credentials, or the credentials are invalid.
  • 403 Forbidden: "I know who you are, but you do not have permission to do this." The client is authenticated but does not possess the required scopes or role (e.g., a regular user trying to access the admin dashboard).

404 Not Found

The requested resource could not be found but may be available in the future.

  • Security Tip: If a resource is restricted, you may want to return 404 Not Found instead of 403 Forbidden to hide its existence from unauthorized scanners.

405 Method Not Allowed

A request method is not supported for the requested resource (e.g., sending a POST request to a read-only endpoint /api/v1/configs).

  • Requirement: The response must include an Allow header listing the supported methods (e.g., Allow: GET, HEAD).

408 Request Timeout

The server timed out waiting for the request.

  • Usage: When the client takes too long to upload its headers or body.

409 Conflict

The request could not be completed due to a conflict with the current state of the target resource.

  • Usage: When a user tries to sign up with an email address that is already registered, or when a git-like concurrent update fails optimistic locking check.

410 Gone

Indicates that the resource is no longer available and will not be available again.

  • Usage: Used when deleting historical API versions, or deactivated user accounts where you explicitly want to tell search crawlers to stop indexing.

413 Payload Too Large

The request entity is larger than limits defined by server.

  • Usage: File uploads that exceed max file size limits.

414 URI Too Long

The URI requested by the client is longer than the server is willing to interpret.

  • Usage: Overly long query strings, sometimes caused by infinite client redirect loops.

415 Unsupported Media Type

The request entity has a media type which the server or resource does not support.

  • Usage: The client sends a POST request with XML payload (Content-Type: application/xml) but the server only supports JSON (Content-Type: application/json).

422 Unprocessable Entity

The request was well-formed but was unable to be followed due to semantic errors.

  • Usage: Form validation errors, missing fields, invalid ranges (e.g., password too short).
  • Best Practice: Return a structured JSON detailing each validation failure.

429 Too Many Requests

The user has sent too many requests in a given amount of time ("rate limiting").

  • Best Practice: Include a Retry-After header telling the client how many seconds they must wait before making another request.

5xx — Server Error Codes

Server errors represent a failure inside your backend or infrastructure. Your API should catch these gracefully and never expose raw database stack traces to the client.

500 Internal Server Error

A generic error message, given when an unexpected condition was encountered and no more specific message is suitable.

  • Production Tip: Log the exact stack trace internally with a unique Correlation ID, but return only the Correlation ID to the client. Never leak internal details.

501 Not Implemented

The server either does not recognize the request method, or it lacks the ability to fulfill the request.

  • Usage: Stubbing endpoints before their actual implementation is deployed.

502 Bad Gateway

The server, while acting as a gateway or proxy, received an invalid response from the inbound server it accessed while attempting to fulfill the request.

  • Usage: Nginx or Cloudflare cannot communicate with your Node.js/Go backend app process.

503 Service Unavailable

The server cannot handle the request (because it is overloaded or down for maintenance). Generally, this is a temporary state.

  • Best Practice: Include a Retry-After header to advise the client when the service will be back up.

504 Gateway Timeout

The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server.

  • Usage: The API Gateway timed out waiting for the database query or microservice to finish processing.

505 HTTP Version Not Supported

The server does not support the HTTP protocol version used in the request.


🛠️ The Production Essentials: Most Used Codes in Modern APIs

While HTTP lists dozens of codes, modern API design centers around a core set of 11 status codes. Mastering these guarantees an intuitive, standardized developer experience.

CodeStatus TextTypical API Scenario
200OKStandard successful GET, PUT, PATCH.
201CreatedSuccessful record creation (POST).
204No ContentSuccessful deletion (DELETE), no body returned.
400Bad RequestSyntax error, malformed JSON.
401UnauthorizedAuthentication missing or failed.
403ForbiddenAuthenticated, but lacks permissions (role conflict).
404Not FoundResource or route does not exist.
422Unprocessable EntityValidation errors (e.g., invalid email address).
429Too Many RequestsRate-limiting active.
500Internal Server ErrorUnhandled backend exception / database failure.
503Service UnavailableBackend server is crashing or in maintenance mode.

Designing a Premium API Error Response (RFC 7807)

For client errors (4xx) and server errors (5xx), do not just return raw status codes or flat strings like {"error": "something went wrong"}. Use the standard RFC 7807 (Problem Details for HTTP APIs) layout.

Here is what a production-ready validation error looks like:

code
{
  "type": "https://api.dhavalkurkutiya.dev/errors/validation-error",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "The email address provided is already registered.",
  "instance": "/api/v1/auth/register",
  "invalidParams": [
    {
      "name": "email",
      "reason": "Email address must be unique."
    }
  ],
  "correlationId": "err_req_9f3c7028fa"
}

By sticking to this unified standard, you build web systems that are predictable, resilient, and incredibly easy for other developers to integrate with!