HTTP fundamentals for testers
API status codes explained for testing
An HTTP status code is the first summary of what happened to an API request. Good testing checks not only the happy-path code, but also whether failures return the correct category, useful details, and a consistent response body.
The four status groups API testers use most
The first digit places a response in a broad category. That category helps you decide whether to inspect the returned resource, follow a redirect, correct the request, or investigate the server.
The server accepted and completed the request.
The client must take another step or use a different resource location.
The request cannot be fulfilled because of input, authentication, permission, or resource state.
The server failed while handling an otherwise valid request.
2xx: successful requests
A 2xx response means the request was accepted, but the exact code still matters. Test whether the code matches the operation and whether the body follows the documented contract.
200 OKA general successful response, commonly used for reads and updates that return a body.
201 CreatedA new resource was created. Test for a resource identifier and, when documented, a Location header.
202 AcceptedProcessing has started but is not complete. Test how clients can check the eventual result.
204 No ContentThe request succeeded without a response body. Confirm the body is actually empty.
A common migration regression is returning 200 for every successful action. That can hide meaningful distinctions such as creation, asynchronous acceptance, and an intentionally empty response.
3xx: redirects and cached responses
Redirects are less common in JSON APIs than in websites, but they can appear after endpoint moves, authentication flows, or infrastructure changes. Check the Location header and whether the client is expected to follow the redirect automatically.
Pay special attention to 301 and 308 permanent redirects versus 302 and 307 temporary redirects. Some redirect types preserve the original method and body while others may be interpreted differently by clients. Test the actual client behavior rather than assuming every redirect is equivalent.
4xx: problems the client can address
A 4xx response says the server cannot fulfill the request as submitted. Good APIs distinguish between invalid input, missing authentication, insufficient permission, absent resources, state conflicts, and rate limits.
400 Bad RequestThe request is malformed or fails general validation. Test missing fields, invalid JSON, and unsupported values.
401 UnauthorizedAuthentication is missing or invalid. Despite the name, this normally means “not authenticated.”
403 ForbiddenThe identity is known but lacks permission. Test users with different roles and scopes.
404 Not FoundThe resource or route does not exist. Check that the error does not reveal sensitive information.
409 ConflictThe request conflicts with current state, such as a duplicate record or version mismatch.
422 Unprocessable ContentThe syntax is understood, but validation prevents processing. Confirm field-level errors are useful and consistent.
429 Too Many RequestsA rate limit was exceeded. Check retry guidance and any documented limit headers.
5xx: failures owned by the server
A 5xx code should represent a server or upstream failure, not ordinary invalid input. Test whether errors are logged internally, return a safe request identifier, and avoid exposing stack traces or confidential details.
500 Internal Server ErrorAn unexpected failure occurred. The public response should be safe while internal logs preserve diagnostic context.
502 Bad GatewayA gateway or proxy received an invalid upstream response. Test dependency failures and proxy configuration.
503 Service UnavailableThe service is temporarily unable to handle the request. Check whether retry guidance is provided.
504 Gateway TimeoutAn upstream dependency did not respond in time. Compare application and gateway timeout settings.
Compare the error body as well as the code
Two APIs can return the same status while giving clients very different information. A stable error contract often includes a machine-readable code, a human-readable message, field-level details when appropriate, and a request or trace identifier.
{
"error": {
"code": "INVALID_EMAIL",
"message": "Enter a valid email address.",
"field": "email",
"requestId": "req_7f31"
}
}Do not assert only that an error occurred. Assert the expected HTTP status, error schema, stable machine code, and absence of private implementation details.
A practical status-code test matrix
- Valid request with an existing resource
- Valid request for a missing resource
- Missing, expired, and malformed credentials
- Authenticated user without permission
- Malformed JSON and missing required fields
- Duplicate creation or conflicting update
- Rate-limit exhaustion and retry behavior
- Dependency failure and timeout behavior
What to flag during a migration
Flag a change when the candidate returns a different status for the same logical outcome, turns a specific error into a generic one, changes the error-body schema, removes retry information, or exposes more internal detail. Document intentional changes so client teams can update safely.
Test status and body together
Run the same request against your baseline and candidate APIs, then review the status, error contract, and timing as one result.
Compare API responses