HTTP

Status Code

HTTP 200 OK: Success Response Explained

Learn what HTTP 200 OK means, when servers return it, and how to handle successful responses in your applications.

4 min read beginner Try in Playground

TL;DR: 200 OK means your request succeeded. The server processed it and is returning the requested data.

200 OK is the most common HTTP status code. It means everything worked—the server received your request, understood it, processed it successfully, and is sending back the result.

What is 200 OK?

When a server returns 200 OK, it’s saying “your request succeeded, here’s what you asked for”:

GET /api/users/123 HTTP/1.1
Host: api.example.com
```text

Response:

```http
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 89

{
  "id": 123,
  "name": "Alice Johnson",
  "email": "alice@example.com"
}

When Servers Return 200

GET Request - Resource Retrieved

GET /products/456 HTTP/1.1
Host: shop.example.com

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 456,
  "name": "Wireless Headphones",
  "price": 79.99
}
```text

### POST Request - Action Completed

```http
POST /api/login HTTP/1.1
Content-Type: application/json

{"email": "user@example.com", "password": "..."}

HTTP/1.1 200 OK
Content-Type: application/json

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": {"id": 123, "name": "User"}
}

PUT Request - Resource Updated

PUT /api/users/123 HTTP/1.1
Content-Type: application/json

{"name": "Alice Smith"}

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "name": "Alice Smith",
  "updatedAt": "2026-01-19T10:30:00Z"
}
```text

### DELETE Request - Resource Removed

```http
DELETE /api/posts/789 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json

{
  "message": "Post deleted successfully",
  "deletedId": 789
}

Response Body Content

The response body varies by request type:

HTML Page

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

<!DOCTYPE html>
<html>
<head><title>Welcome</title></head>
<body><h1>Hello, World!</h1></body>
</html>
```text

### JSON Data

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "users": [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"}
  ],
  "total": 2
}

Image File

HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 12345

[binary PNG data]
```text

### Empty Array (Valid 200)

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "results": [],
  "total": 0
}

Common Response Headers

HeaderPurposeExample
Content-TypeBody formatapplication/json
Content-LengthBody size1234
Cache-ControlCaching rulesmax-age=3600
ETagResource version"abc123"
Last-ModifiedLast changeSat, 18 Jan 2026 10:00:00 GMT
Set-CookieSet cookiessession=xyz; HttpOnly

200 OK vs Other Success Codes

CodeNameWhen to Use
200OKGeneral success with response body
201CreatedNew resource created (POST)
202AcceptedRequest queued for processing
204No ContentSuccess but no body to return

Choosing the Right Code

# GET request - use 200
GET /users/123 → 200 OK with user data

# POST creating resource - use 201
POST /users → 201 Created with new user + Location header

# DELETE with no response body - use 204
DELETE /users/123 → 204 No Content

# POST triggering async job - use 202
POST /reports/generate → 202 Accepted
```text

## Best Practices

### Do Return Useful Data

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "data": {
    "id": 123,
    "name": "Alice"
  },
  "meta": {
    "requestId": "req-abc-123",
    "timestamp": "2026-01-19T10:30:00Z"
  }
}

Don’t Return 200 for Errors

# ❌ Bad: 200 with error in body
HTTP/1.1 200 OK
{"error": "User not found"}

# ✅ Good: Proper error status
HTTP/1.1 404 Not Found
{"error": "User not found"}
```http

### Include Appropriate Headers

```http
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=300
ETag: "v1-abc123"
X-Request-ID: req-xyz-789

{"data": "..."}

JavaScript Handling

Fetch API

const response = await fetch('/api/users/123')

if (response.ok) {
  // true for 200-299
  const user = await response.json()
  console.log('User:', user)
} else {
  console.error('Request failed:', response.status)
}
```javascript

### Checking Specifically for 200

```javascript
const response = await fetch('/api/data')

if (response.status === 200) {
  const data = await response.json()
  // Process successful response
}

With Error Handling

async function fetchUser(id) {
  const response = await fetch(`/api/users/${id}`)

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`)
  }

  return response.json()
}

try {
  const user = await fetchUser(123)
  displayUser(user)
} catch (error) {
  showError(error.message)
}
```text

## API Response Patterns

### Standard Success Response

```json
{
  "status": "success",
  "data": {
    "id": 123,
    "name": "Alice"
  }
}

Paginated Response

{
  "data": [
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob" }
  ],
  "pagination": {
    "page": 1,
    "perPage": 20,
    "total": 150,
    "totalPages": 8
  }
}
```text

### Response with Metadata

```json
{
  "data": { "id": 123 },
  "meta": {
    "requestId": "req-abc",
    "processingTime": "45ms",
    "apiVersion": "v1"
  }
}

Try It Yourself

See a 200 OK response in our request builder:

  1. Select GET method
  2. Set path to /posts/1
  3. Click Send and observe the 200 response with post data

In Practice

Express.js
// GET — return resource
app.get('/api/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id)
  if (!user) return res.status(404).json({ error: 'Not found' })
  res.status(200).json(user) // or just res.json(user)
})

// POST — action succeeded, return result
app.post('/api/search', async (req, res) => {
  const results = await search(req.body.query)
  res.json({ results, total: results.length })
  // 200 is default — no need to set explicitly
})
Next.js App Router
// app/api/users/[id]/route.ts
export async function GET(
  _req: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.users.findById(params.id)
  if (!user) return new Response(null, { status: 404 })
  // Response.json() defaults to 200
  return Response.json(user)
}
Django
from django.http import JsonResponse

def user_detail(request, user_id):
    try:
        user = User.objects.get(pk=user_id)
        # JsonResponse defaults to status=200
        return JsonResponse(user.to_dict())
    except User.DoesNotExist:
        return JsonResponse({'error': 'Not found'}, status=404)

Frequently Asked Questions

What does HTTP 200 OK mean?

HTTP 200 OK means the request was successful. The server understood the request, processed it correctly, and is returning the requested data. It is the standard success response for GET, POST, PUT, and other HTTP methods.

When should a server return 200 OK?

Return 200 OK when a request succeeds and you have content to return. For GET requests, return the requested resource. For POST/PUT, return the created or updated resource. Use 201 Created for new resources and 204 No Content when there is nothing to return.

What is the difference between 200 OK and 201 Created?

200 OK is a general success response. 201 Created specifically indicates a new resource was created, typically from a POST request. 201 should include a Location header pointing to the new resource.

Can a 200 response have an empty body?

Yes, but 204 No Content is more appropriate for successful requests with no response body. Use 200 OK when you have content to return, even if it is just a success message or empty array.

Does 200 OK mean there were no errors?

Not always. Some APIs return 200 OK with error details in the body. This is considered bad practice. Proper APIs use appropriate error status codes (4xx, 5xx) for errors and reserve 200 for actual success.

Keep Learning