HTTP

Method

HTTP POST Method: Complete Guide with Examples

Learn how the HTTP POST method works. Understand when to use POST requests, request bodies, form submissions, and API calls with practical examples.

6 min read beginner Try in Playground

TL;DR: POST sends data to create new resources or trigger actions on the server. Use it for form submissions, user registration, file uploads, and API calls that modify data.

POST is the HTTP method for sending data to servers. When you submit a form, upload a file, or create a new account, you’re using POST. Unlike GET which retrieves data, POST sends data to create or process something new.

What is POST?

POST requests include data in the request body, telling the server to process it and typically create a new resource:

POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 64

{
  "name": "Alice Johnson",
  "email": "alice@example.com"
}
```text

The server processes the data and responds:

```http
HTTP/1.1 201 Created
Location: /api/users/456
Content-Type: application/json

{
  "id": 456,
  "name": "Alice Johnson",
  "email": "alice@example.com",
  "createdAt": "2026-01-19T10:30:00Z"
}

Key Characteristics

Non-Safe

POST requests modify server state. They create, update, or trigger actions:

POST /orders          → Creates a new order
POST /payments        → Processes a payment
POST /emails/send     → Sends an email

Non-Idempotent

Sending the same POST request twice may have different effects:

POST /orders with {product: "Book"}
→ First request: Creates order #1001
→ Second request: Creates order #1002 (duplicate!)

This is why browsers show “Confirm Form Resubmission” warnings.

Not Cached

POST responses are not cached by default. Each request goes to the server:

Cache-Control: no-store
```text

### Data in Body

POST data is sent in the request body, not the URL:

```http
GET  /search?q=secret     ← Visible in URL, logs, history
POST /search with body    ← Hidden from URL
```text

## Content Types

The `Content-Type` header tells the server how to parse the request body.

### JSON (APIs)

Most common for modern APIs:

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

{
  "name": "Alice",
  "email": "alice@example.com",
  "roles": ["user", "admin"]
}

Form URL-Encoded (HTML Forms)

Default for HTML <form> submissions:

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=alice&password=secret123
```text

### Multipart Form Data (File Uploads)

Required for file uploads:

```http
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: image/jpeg

[binary image data]
------WebKitFormBoundary
Content-Disposition: form-data; name="description"

My vacation photo
------WebKitFormBoundary--

Plain Text

Simple text data:

POST /logs HTTP/1.1
Content-Type: text/plain

Error occurred at line 42: undefined variable
```text

## Real-World Examples

### User Registration

```http
POST /api/auth/register HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
  "email": "newuser@example.com",
  "password": "securePassword123",
  "name": "New User"
}

Response:

HTTP/1.1 201 Created
Location: /api/users/789
Set-Cookie: session=abc123; HttpOnly; Secure

{
  "id": 789,
  "email": "newuser@example.com",
  "name": "New User",
  "createdAt": "2026-01-19T10:30:00Z"
}
```text

### Login Form

```http
POST /api/auth/login HTTP/1.1
Host: api.example.com
Content-Type: application/json

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

Response:

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

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expiresIn": 3600,
  "user": {
    "id": 123,
    "email": "user@example.com"
  }
}
```text

### Creating a Blog Post

```http
POST /api/posts HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

{
  "title": "Understanding HTTP POST",
  "content": "POST is used to send data...",
  "tags": ["http", "tutorial"],
  "published": true
}

File Upload

POST /api/files/upload HTTP/1.1
Host: api.example.com
Content-Type: multipart/form-data; boundary=----Boundary
Authorization: Bearer token123

------Boundary
Content-Disposition: form-data; name="file"; filename="document.pdf"
Content-Type: application/pdf

[PDF binary data]
------Boundary--
```text

### Webhook Notification

```http
POST /webhooks/payment HTTP/1.1
Host: yourapp.com
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...

{
  "event": "payment.completed",
  "data": {
    "orderId": "ORD-123",
    "amount": 99.99,
    "currency": "USD"
  }
}

Response Status Codes

CodeMeaningWhen to Use
200 OKSuccessAction completed, returning data
201 CreatedResource createdNew resource created successfully
202 AcceptedAcceptedRequest queued for processing
204 No ContentSuccess, no bodyAction completed, nothing to return
400 Bad RequestInvalid dataMalformed JSON or missing fields
401 UnauthorizedAuth requiredMissing or invalid credentials
403 ForbiddenAccess deniedNot allowed to perform action
409 ConflictConflictResource already exists
422 UnprocessableValidation failedData format correct but invalid
429 Too Many RequestsRate limitedSlow down requests

POST vs GET

AspectPOSTGET
PurposeSend/create dataRetrieve data
Data locationRequest bodyURL query string
Visible in URLNoYes
CachedNoYes
BookmarkableNoYes
SafeNoYes
IdempotentNoYes
Data sizeUnlimited~2,000 chars
Binary dataYesNo
Sensitive dataBetterNever

POST vs PUT

AspectPOSTPUT
PurposeCreate resourceReplace resource
IdempotentNoYes
URLCollection (/users)Specific (/users/123)
Multiple callsCreates duplicatesSame result
Client knows IDNoYes
POST /users          → Server assigns ID (creates user #456)
PUT  /users/456      → Client specifies ID (replaces user #456)
```nginx

## Common Headers

### Request Headers

| Header           | Purpose                  | Example            |
| ---------------- | ------------------------ | ------------------ |
| `Content-Type`   | Body format              | `application/json` |
| `Content-Length` | Body size                | `256`              |
| `Authorization`  | Auth credentials         | `Bearer token123`  |
| `Accept`         | Expected response format | `application/json` |
| `X-Request-ID`   | Request tracking         | `req-abc-123`      |

### Response Headers

| Header                  | Purpose          | Example            |
| ----------------------- | ---------------- | ------------------ |
| `Location`              | New resource URL | `/api/users/456`   |
| `Content-Type`          | Response format  | `application/json` |
| `X-RateLimit-Remaining` | Requests left    | `99`               |

## Best Practices

### Do's ✅

```javascript
// Use POST for creating resources
const response = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
})

// Always set Content-Type
headers: { 'Content-Type': 'application/json' }

// Handle the response properly
if (response.status === 201) {
  const newUser = await response.json()
  const location = response.headers.get('Location')
}

// Validate data before sending
if (!email || !password) {
  throw new Error('Email and password required')
}

Don’ts ❌

// Don't use POST for retrieving data
POST /api/users/123  // Wrong! Use GET

// Don't forget Content-Type
fetch('/api/users', {
  method: 'POST',
  body: JSON.stringify(data)  // Server won't know it's JSON!
})

// Don't send sensitive data without HTTPS
http://api.example.com/login  // Insecure!
https://api.example.com/login // Correct!

// Don't ignore error responses
const response = await fetch('/api/users', { method: 'POST', ... })
const data = await response.json()  // Might be an error!
```javascript

## JavaScript Examples

### Basic POST

```javascript
const response = await fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer token123'
  },
  body: JSON.stringify({
    name: 'Alice',
    email: 'alice@example.com'
  })
})

if (response.ok) {
  const newUser = await response.json()
  console.log('Created user:', newUser.id)
}

Form Submission

const form = document.querySelector('form')
const formData = new FormData(form)

const response = await fetch('/api/submit', {
  method: 'POST',
  body: formData // Content-Type set automatically
})
```javascript

### File Upload

```javascript
const fileInput = document.querySelector('input[type="file"]')
const formData = new FormData()
formData.append('file', fileInput.files[0])
formData.append('description', 'My upload')

const response = await fetch('/api/upload', {
  method: 'POST',
  body: formData
})

Error Handling

async function createUser(userData) {
  const response = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(userData)
  })

  if (response.status === 201) {
    return await response.json()
  }

  if (response.status === 400) {
    const error = await response.json()
    throw new Error(`Validation error: ${error.message}`)
  }

  if (response.status === 409) {
    throw new Error('User already exists')
  }

  throw new Error(`Unexpected error: ${response.status}`)
}

Try It Yourself

Create a new resource with our interactive request builder:

  1. Select POST method
  2. Set path to /posts
  3. Add JSON body: {"title": "Test", "body": "Hello"}
  4. Click Send and observe the 201 response
  • GET - Retrieve resources
  • PUT - Replace entire resources
  • PATCH - Partial updates
  • DELETE - Remove resources

In Practice

Express.js
// POST /users — create a new user
app.post('/users', async (req, res) => {
  const { name, email, password } = req.body
  const user = await db.users.create({ name, email, password })
  res.status(201)
    .location(`/users/${user.id}`)
    .json(user)
})

// POST /sessions — login
app.post('/sessions', async (req, res) => {
  const user = await db.users.findByEmail(req.body.email)
  if (!user || !user.verifyPassword(req.body.password)) {
    return res.status(401).json({ error: 'Invalid credentials' })
  }
  const token = generateToken(user)
  res.json({ token })
})
Next.js App Router
// app/api/users/route.ts
export async function POST(request: Request) {
  const body = await request.json()
  const user = await db.users.create(body)
  return Response.json(user, {
    status: 201,
    headers: { Location: `/api/users/${user.id}` }
  })
}

// app/api/sessions/route.ts
export async function POST(request: Request) {
  const { email, password } = await request.json()
  const user = await db.users.findByEmail(email)
  if (!user?.verifyPassword(password)) {
    return Response.json({ error: 'Invalid credentials' }, { status: 401 })
  }
  return Response.json({ token: generateToken(user) })
}
Django
# views.py
import json
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
@require_POST
def create_user(request):
    data = json.loads(request.body)
    user = User.objects.create(
        name=data['name'],
        email=data['email'],
    )
    response = JsonResponse(user.to_dict(), status=201)
    response['Location'] = f'/users/{user.id}'
    return response

Frequently Asked Questions

What is the HTTP POST method?

POST is an HTTP method used to send data to a server to create or update a resource. Unlike GET, POST includes data in the request body rather than the URL, making it suitable for form submissions, file uploads, and API calls that modify data.

When should I use POST instead of GET?

Use POST when creating new resources, submitting forms, uploading files, or sending sensitive data like passwords. POST data is sent in the request body (not visible in URL), is not cached, and can handle large payloads without URL length limits.

Is POST secure?

POST is more secure than GET for sensitive data because the data is not visible in the URL, browser history, or server logs. However, POST data is still sent in plain text unless you use HTTPS. Always use HTTPS for sensitive information.

What Content-Type should I use with POST?

Common Content-Types are application/json for API calls, application/x-www-form-urlencoded for HTML forms, and multipart/form-data for file uploads. The Content-Type header tells the server how to parse the request body.

Is POST idempotent?

No, POST is not idempotent. Sending the same POST request multiple times may create multiple resources or have different effects each time. This is why browsers warn you when refreshing a page after a POST submission.

What status code should a POST request return?

201 Created is ideal when a new resource is created, with a Location header pointing to the new resource. 200 OK is used when the action succeeded but no new resource was created. 204 No Content indicates success with no response body.

Keep Learning