200 OK
Success
The request succeeded and the server returned the requested representation in the response body. The exact meaning of success depends on the HTTP method. For GET it means the resource is included, for HEAD it means the headers describing the resource are included, and for POST/PUT it means the action was performed and the response describes the outcome. A 200 is not a guarantee that the response body is useful: an API can return 200 with an error object in the payload, which is a common source of monitoring blind spots.
When does this happen?
200 is the default success response for every method that produces a body. GET, HEAD, OPTIONS, PATCH, and most successful POSTs land here unless the server has a specific reason to use 201, 202, or 204. The response normally carries a Content-Type and either a Content-Length or Transfer-Encoding: chunked header. For GET requests the body is the resource; for POST it is whatever the action returned, which may not be the same shape as the GET. Caching behavior is dictated by Cache-Control, ETag, and Last-Modified headers. Without those, intermediaries default to heuristic caching that can surprise you. Browsers do not log anything special in DevTools for a 200, so you must rely on the response body and headers to confirm the request behaved as expected. Watch for endpoints that return 200 with an embedded error object. Those bypass most uptime monitors.
Common causes
- Successful GET. The resource was found and its representation is in the body, served either fresh or from a revalidated cache.
- Successful POST that does not create a new resource. For example an RPC-style action like /search or /login where the result is returned inline.
- Successful PUT or PATCH where the server chose to return the updated resource instead of using 204.
- Conditional GET that revalidates with If-None-Match or If-Modified-Since and the server decides to send the body anyway rather than 304.
- Health check endpoint responding normally with a small body like {"status":"ok"}.
- API call that succeeded at the HTTP layer but returned a domain-level error in the JSON payload. Common in GraphQL and older SOAP-style APIs.
- Cached response served by a CDN where the origin's last successful response was a 200.
How to fix it
- No fix needed when this is the expected outcome. Verify the response body matches the schema you expect.
- If you are getting 200 but the body contains an error object, treat the endpoint as broken at the application layer and fix the underlying handler to return a proper 4xx or 5xx.
- Confirm Cache-Control and ETag headers are set correctly. A 200 with no cache headers will be cached unpredictably by proxies and browsers.
- If the same URL sometimes returns 200 and sometimes 3xx, audit your redirect rules. Inconsistent responses confuse search engines and break monitoring.
- When using a CDN, verify the Age header and X-Cache headers (or your CDN's equivalent) to confirm whether the 200 came from origin or edge.
- Validate Content-Type matches the body. A 200 with Content-Type: text/html but a JSON body will break clients that auto-parse.
Real-world examples
- User navigates to a blog post URL like /posts/why-http-matters that exists in the database.
- Server returns 200 with Content-Type: text/html and the rendered HTML in the body. Browser renders the page and the URL bar stays unchanged.
- API client makes GET /v1/users/42 to fetch a user profile that exists.
- Server returns 200 with Content-Type: application/json and the user object in the body. Client parses the JSON and uses the fields directly.
- Browser revalidates a cached image with If-None-Match and the ETag has changed.
- Server returns 200 with a fresh body and a new ETag. Browser replaces the cached entry and renders the new image.
- GraphQL POST to /graphql with a query that the resolver could not satisfy.
- Server returns 200 with a JSON body containing an errors array. The HTTP layer succeeded but the domain operation failed. Most monitors will miss this unless they inspect the body.
- Health check pinger hits /healthz on a Kubernetes pod every five seconds.
- Server returns 200 with a small body like ok. The kubelet marks the pod ready and routes traffic to it.
Debugging
- Run curl -I https://example.com/path to see the status line and headers without downloading the body.
- Run curl -v https://example.com/path to inspect the full request and response, including TLS handshake and header negotiation.
- Open the Network tab in DevTools, click the request, and check the Response and Headers panels. Confirm Content-Type, Content-Length, and Cache-Control are what you expect.
- For CDN-served responses, check Age, X-Cache, and Via headers (or Cf-Cache-Status, X-Served-By, etc. depending on the provider) to determine whether you hit the edge or origin.
- If the body looks wrong, run curl --compressed to confirm content encoding is being decoded correctly. A mismatch between Content-Encoding and the actual body causes silent corruption.
How it differs from related codes
HTTP 201
201 is used when a POST or PUT creates a new resource and the server wants to signal that creation specifically, usually returning a Location header pointing at the new resource. 200 implies the action succeeded but does not promise creation.
HTTP 204
204 means the request succeeded but there is no response body. Use it for DELETE or PUT operations where the client does not need the updated representation back, and switch from 200 when payload size matters.
HTTP 304
304 is the cached counterpart of 200. Same resource, but the server tells the client to reuse its local copy instead of resending the body. A 200 always carries a body, a 304 never does.
Related status codes
See HTTP 200 in your redirect chains?