Which HTTP Status Code to Use Cheat Sheet for APIs

Which HTTP status code to use cheatsheet helps API developers choose the right codes for success, client errors, redirects, and server errors at a glance.

Jump to section

Jump to section

Jump to section

HTTP status codes aren't just numbers—they're a machine-readable contract that determines how your API integrates with client libraries, AI agents, and automated tooling. When you choose the right status code, SDKs can automatically handle retries, generate typed exceptions, and provide clear error messages, while MCP servers can give LLMs precise signals about tool call outcomes.

This guide covers the essential status codes that shape how developers and AI systems interact with your API, from distinguishing between 400 and 422 validation errors to using 503 for automatic retry logic. You'll learn which codes enable better SDK generation, how status codes influence AI agent behavior, and the common mistakes that break client integrations.

What makes a good API status code strategy

Choosing the right HTTP status code is about creating a clear, machine-readable contract for your API. A consistent strategy tells client applications, SDKs, and AI agents exactly how to interpret a response, which is critical for building reliable integrations. The Stainless SDK generator uses these status codes to automatically build type-safe client libraries. When automated tools know whether to retry a request, invalidate a cache, or throw a specific typed error, it dramatically reduces integration time and future support tickets.

This contract is the foundation for robust tooling. For example, a well-generated SDK can automatically handle retries on a 503 Service Unavailable but will know not to retry on a 400 Bad Request. Similarly, a Model Context Protocol (MCP) server uses status codes to tell an LLM whether a tool call succeeded or failed, directly influencing the agent's next decision. You can generate an MCP server from an OpenAPI spec to expose these status codes as clear signals to AI agents.

Which success code should your API return

When a request succeeds, you have a few options. Choosing the right one gives the client important context about the operation.

  • 200 OK: This is the general-purpose success code. Use it for successful GET requests that return data, or for PUT or PATCH updates that return the modified resource in the response body.

  • 201 Created: Use this specifically after a POST request successfully creates a new resource. A 201 response should also include a Location header pointing to the URL of the newly created resource.

  • 204 No Content: This code signals that the server successfully processed the request but has no content to return. It's the perfect choice for a DELETE request or a PATCH request where you don't need to send the updated resource back.

This precision allows an SDK generator to infer the correct return type for each API method. A method that maps to a 204 response might return void or None, while one that returns 200 or 201 will be typed to the corresponding response body schema.

Which client error tells users what went wrong

Client errors, the 4xx series, are your API's way of telling the user, "The problem is on your end." Being specific here is key to a good developer experience, as it helps users debug their own code faster.

400 vs 422 for validation errors

This is a common point of confusion. Both codes indicate a problem with the user's request, but the distinction is important.

  • 400 Bad Request: Use this for requests that are syntactically incorrect. The server couldn't even parse the request. A common example is malformed JSON.

  • 422 Unprocessable Entity: Use this when the request syntax is perfectly valid, but the data fails semantic validation. For example, a user sends a JSON object where an email field contains a string that isn't a valid email address.

A well-typed SDK can use this distinction to generate different error classes, allowing developers to programmatically handle a 422 APIValidationError differently from a generic 400 APIBadRequestError.

401 vs 403 for auth failures

Authentication and authorization errors are not the same, and your status codes should reflect that.

  • 401 Unauthorized: This means the server doesn't know who the user is. The request lacks valid authentication credentials. The user is unauthenticated.

  • 403 Forbidden: This means the server knows who the user is, but that specific user is not permitted to perform the requested action. The user is authenticated but unauthorized.

This difference is crucial for client-side logic. An SDK receiving a 401 might trigger a flow to refresh an expired token, while a 403 simply informs the user they don't have the necessary permissions.

404 vs 410 for deleted resources

Both codes mean a resource can't be found, but 410 provides a crucial piece of extra information.

  • 404 Not Found: This is the generic "I can't find what you're looking for" response. It doesn't say whether the resource ever existed.

  • 410 Gone: This is a more definitive signal. It tells the client that the resource used to exist at this URL but has been permanently deleted.

Using 410 allows clients to confidently update their own state, for example by removing the resource from a local cache or search index.

When should your API return server errors

The 5xx series of status codes indicates that something went wrong on your server, and it's not the client's fault.

  • 500 Internal Server Error: This is the catch-all error. It means an unexpected condition was encountered on the server. You should avoid using this for predictable errors and always log these occurrences for debugging.

  • 502 Bad Gateway: This indicates that your server, while acting as a gateway or proxy, received an invalid response from an upstream server.

  • 503 Service Unavailable: This means the server is temporarily unable to handle the request, perhaps due to being overloaded or down for maintenance. This is a key signal for clients to retry the request later.

  • 504 Gateway Timeout: This is similar to 502, but specifically means an upstream server failed to respond in time.

Client libraries often build automatic retry logic around 503 and other transient server errors, making your API more resilient without any extra work from your users.

When do APIs actually need redirects

Redirects are less common in JSON APIs than in traditional web applications, but they have their uses.

  • 301 Moved Permanently: Use this to indicate that a resource or endpoint has permanently moved to a new URL. This is useful when versioning your API via the URL path (e.g., /v1/users is now /v2/users).

  • 307 Temporary Redirect: This tells the client to resubmit the request to a different URL, but that the original URL should be used for future requests.

Most modern HTTP clients, and by extension the SDKs built on them, will automatically follow these redirects, making the process seamless for the end-user.

What status code mistakes break client integrations

A poor status code strategy can actively harm your developer experience and break automated tools. Here are some common anti-patterns to avoid.

  • Always-200: Returning a 200 OK for every request, even for errors, and putting the error details in the response body. This breaks all standard HTTP client error handling.

  • Blanket-500: Using a generic 500 Internal Server Error for client-side validation issues. This misleads the client into thinking the server is broken.

  • HTML for Errors: Returning an HTML error page instead of a structured JSON error object. This is impossible for a machine to parse reliably.

  • Custom Codes: Inventing custom status codes like 451 (before it was standardized) or 600. Stick to the IANA-registered codes for maximum compatibility.

How status codes shape sdk behavior and ai agents

A thoughtful status code strategy directly enables more powerful and resilient client libraries and AI agents. The signals you send are not just for humans; they are instructions for machines.

For example, when an SDK encounters different error codes, it can map them to specific, typed exceptions. This allows a developer to write clean, targeted error-handling logic, and any custom code you add to handle specific error cases will persist through SDK regeneration.

For instance, in a Stainless-generated TypeScript client you might configure 422 to map to MySDK.ValidationError and 401 to MySDK.AuthenticationError. Here’s how you could handle those errors:

// Example error handling with a Stainless-generated TypeScript client
import { MySDK } from 'my-stainless-sdk'; // hypothetical import

try {
  // Suppose "users.create" calls a POST /users endpoint in your API
  await MySDK.users.create({ email: 'invalid-email' });
} catch (error) {
  if (error instanceof MySDK.ValidationError) {
    console.error(`Validation failed: ${error.message}`);
  } else if (error instanceof MySDK.AuthenticationError) {
    console.error('Please check your API key or tokens.');
  } else {
    console.error('An unexpected error occurred.', error);
  }
}

For AI agents using MCP, this is even more critical. If a tool call to your API returns a 429 Too Many Requests, the agent knows it's being rate-limited and can pause before retrying. If it gets a 403 Forbidden, it knows it lacks permission and can ask the user for elevated access instead of retrying fruitlessly. Your status codes become the agent's senses for interacting with your service.

Frequently asked questions about API status codes

Should I invent custom status codes?

No, you should stick to the standard IANA-registered status codes. For custom error details, provide a rich, structured JSON error body instead. When you create OpenAPI specs, these standard codes and error schemas enable tooling to understand your API's behavior.

How many status codes should I support?

You don't need to support every code. Focus on a core set that covers success (200, 201, 204), client errors (400, 401, 403, 404, 422), and server errors (500, 503).

Which code signals rate limiting?

Use 429 Too Many Requests. You should also include a Retry-After header to tell the client how many seconds to wait before trying again. When you integrate SDK snippets with your API docs, developers can see exactly how each SDK handles rate limiting automatically.

How do status codes interact with API versioning?

You can use a 301 Moved Permanently to redirect clients from an old versioned endpoint, though using a custom version header is often a more flexible approach.

Can I change status codes without breaking clients?

Changing the status code for a given outcome is a breaking change. If you must change a code, treat it like any other breaking API change with a new major version and a clear migration path.

Ready to ship APIs with SDKs that just work? Get started for free.