Free ASP.NET Core decision tool

What HTTP status code should I return?

Describe the outcome in two quick steps. Get the correct status code, the reasoning behind it, and production-ready ASP.NET Core examples.

STEP 1 OF 2

Start with the outcome

What happened when the client made the request?

Choose the closest category. You can fine-tune the scenario next.

Tip: use Tab and Enter to move through the wizard. No data leaves your browser.

HTTP semantics, made practical

A status code is part of your API contract

HTTP status codes help clients decide whether to retry, authenticate, correct the request, follow a new resource URL, or stop. Choosing them consistently also improves generated SDKs, monitoring, caching, and API documentation.

Want the complete reference and decision tree? Read Choosing the Right HTTP Status Codes for Your API.

2xx

Success

Use the specific success code that describes what happened: returned content, created a resource, accepted async work, or completed without a body.

4xx

Client action required

The caller may need to fix input, authenticate, request permission, resolve a conflict, find another resource, or wait before retrying.

5xx

Server failure

The request may be valid, but the server cannot complete it. Keep error details safe and make transient failure behavior explicit.

Common decisions

HTTP status codes developers often confuse

The right choice depends on what happened, not which code your framework makes easiest to return.

400vs422

Bad Request vs Unprocessable Content

400 means the server cannot correctly parse or understand the request structure. 422 means it understood the request, but the submitted values fail semantic rules. ASP.NET Core often defaults model validation to 400, so consistency and documentation matter.

401vs403

Unauthorized vs Forbidden

401 means valid authentication is missing and should normally trigger a WWW-Authenticate challenge. 403 means the caller is authenticated but lacks permission.

409vs422

Conflict vs Validation failure

409 fits a conflict with current resource state, such as an optimistic concurrency failure or duplicate unique value. 422 fits a validly structured request whose values cannot be processed regardless of a changing resource state.

200vs204

OK vs No Content

Return 200 when the response contains a representation. Return 204 when the operation succeeded and the response has no content. A 204 response must not contain a body.

Consistent error contracts

Use ProblemDetails for API errors

RFC 9457 Problem Details gives clients a predictable error shape with a status, title, type, detail, and instance. ASP.NET Core can generate this format centrally so endpoint code stays focused on application behavior.

  • Keep machine-readable error types stable.
  • Add safe extensions such as trace IDs and validation errors.
  • Never expose stack traces or infrastructure details.
Program.cs
builder.Services.AddProblemDetails();
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

Build APIs that work in production

Status codes are only one part of a great API

Learn authentication, validation, idempotency, versioning, rate limiting, testing, observability, and the architectural decisions behind production-ready ASP.NET Core APIs.

Explore Pragmatic REST APIs

Frequently asked questions

HTTP status code FAQ

Should validation errors return 400 or 422?+

Use 400 when the request cannot be parsed or is structurally invalid. Use 422 when the request is well-formed and understood but fails semantic validation. ASP.NET Core commonly returns 400 for model validation, so either convention can work when it is documented and consistently applied.

What is the difference between 401 and 403?+

401 means the caller is not authenticated and should normally receive a WWW-Authenticate challenge. 403 means the caller is authenticated but does not have permission to perform the operation.

When should an API return 409 Conflict?+

Return 409 when the operation conflicts with the current state of a resource. Common examples include optimistic concurrency failures, duplicate values protected by a uniqueness constraint, and invalid state transitions.

Should a successful POST return 200 or 201?+

Return 201 when the POST creates a resource, and include a Location header for its canonical URI. Return 200 when the operation succeeds but does not create a new resource, or when it performs an action and returns a result.

When should I use 202 Accepted?+

Use 202 when work has been accepted but will complete asynchronously. The response should provide a status-monitor URL so the client can observe completion or failure.

Should a DELETE return 204 or 404 when the resource is already gone?+

Both conventions can be defensible. Return 404 when the client needs to know the resource did not exist. Return 204 when your DELETE contract is idempotent and only promises that the resource is absent after the call. Document the chosen behavior.