ScreenshotNeo

BlogGuides

What Is HTTP PUT? Semantics, Idempotence, Status Codes, and Examples

HTTP PUT replaces a resource at a known URL. Learn idempotence, PUT vs PATCH, status codes, retries, headers, and working examples.

By the ScreenshotNeo team1 October 20267 min read

HTTP PUT is the method a client uses to replace all current representations of a target resource with the content in the request. The client normally chooses the resource URL, sends the complete desired representation in the request body, and receives a status describing whether the resource was created or replaced.

RFC 9110 defines PUT as “Replace all current representations of the target resource with the request content.” Read the specification. MDN describes the common create-or-replace behavior: PUT creates a new resource or replaces a representation at the target URL. MDN PUT reference.

PUT in one request

PUT /profiles/42 HTTP/1.1
Host: api.example.test
Content-Type: application/json
Authorization: Bearer TOKEN

{"name":"Ada","timezone":"UTC"}

The body is the representation the client wants at /profiles/42. If the endpoint follows standard PUT semantics, omitting a field can remove it from the stored representation. Check the API contract: some APIs document PUT as a full replacement while others implement a merge-like operation.

What makes PUT different?

Method Typical intent Idempotent? Who chooses the final URI?
GET Retrieve a representation Yes Client requests a known URI
POST Server-side processing, often create under a collection or trigger an action Not guaranteed Usually the server
PUT Replace the representation at a known URI; creation may be possible Yes Client
PATCH Apply partial modification instructions Not guaranteed Client
DELETE Remove current representations Yes Client

Why PUT is idempotent

An operation is idempotent when making the same request once has the same intended effect as making it repeatedly. MDN’s idempotence glossary uses this definition. Sending the same PUT representation to the same URI ten times should leave that resource in the same state as sending it once.

Idempotent does not mean read-only. IANA classifies PUT as safe=no and idempotent=yes. A PUT can change server state; it is simply defined so that repetition has the same intended target-resource effect.

Idempotence does not eliminate every side effect. An implementation might write audit records, send notifications, update search indexes, or charge a separate service on each request. Authentication, authorization, validation, locking, and those application side effects remain API-specific.

PUT versus PATCH

Use PUT for a complete desired representation

Choose PUT when the client knows the resource URI and can send the complete state that should replace the current representation.

PUT /users/42 HTTP/1.1
Content-Type: application/json

{"name":"Ada Lovelace","email":"ada@example.test","timezone":"UTC"}

If the existing object also had a phone property and the API defines PUT as replacement, leaving phone out can remove it.

Use PATCH for partial instructions

Choose PATCH when the request should change selected fields or apply an operation to a substructure. PATCH is not guaranteed to be idempotent; its behavior depends on the patch format and operation.

PATCH /users/42 HTTP/1.1
Content-Type: application/merge-patch+json

{"timezone":"Europe/London"}

Follow the endpoint documentation. Some APIs accept partial JSON in PUT, but that is a contract decision rather than the general HTTP meaning of PUT.

Creation, replacement, and status codes

Situation Common response Meaning
New resource created by PUT 201 Created The target did not have a current representation and now does
Existing resource replaced and representation returned 200 OK The response includes a representation or result
Existing resource replaced with no response body 204 No Content The operation succeeded and there is no body to return
Precondition failed 412 Precondition Failed An If-Match or similar condition was false
Validation failed 400 Bad Request or 422 Unprocessable Content The API rejected the request data
Conflict 409 Conflict The state conflicts with a business or resource constraint

For a newly created resource, the server may include Location or Content-Location. RFC 9110’s method and status definitions describe these outcomes; an individual API can document stricter rules.

Complete runnable examples

cURL

curl -i -X PUT 'https://api.example.test/profiles/42' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  --data '{"name":"Ada","timezone":"UTC"}'

-i prints the response status and headers so you can see whether the server returned 201, 200, or 204.

Python

import requests

payload = {"name": "Ada", "timezone": "UTC"}
response = requests.put(
    "https://api.example.test/profiles/42",
    json=payload,
    headers={"Authorization": "Bearer YOUR_TOKEN"},
    timeout=30,
)
response.raise_for_status()
print(response.status_code)
if response.content:
    print(response.json())

Node.js

const payload = { name: 'Ada', timezone: 'UTC' };
const response = await fetch('https://api.example.test/profiles/42', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(payload)
});

if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
console.log(response.status);
if (response.status !== 204) console.log(await response.json());

Raw HTTP

PUT /profiles/42 HTTP/1.1
Host: api.example.test
Content-Type: application/json
Content-Length: 35

{"name":"Ada","timezone":"UTC"}

Headers and options that matter

  • Content-Type: identify the representation, such as application/json or text/plain.
  • Accept: tell the server which response representation you can read.
  • Authorization: supply credentials required by the API.
  • Content-Length: clients usually calculate it; do not hand-edit it unless you control the complete HTTP message.
  • If-Match: use an entity tag to prevent overwriting a newer version.
  • If-Unmodified-Since: apply a date-based concurrency condition where supported.
  • Idempotency-Key: some APIs accept this application-level key for request deduplication. It is not required by HTTP PUT itself.

Concurrency control with ETags

A read-modify-write client can accidentally overwrite someone else’s changes. A common pattern is:

  1. GET the resource and save its ETag.
  2. Build the complete replacement representation.
  3. PUT it with If-Match: <etag>.
  4. Handle 412 Precondition Failed by fetching the newer representation, merging intentionally, and retrying only when appropriate.
curl -i -X PUT 'https://api.example.test/profiles/42' \
  -H 'If-Match: "v17"' \
  -H 'Content-Type: application/json' \
  --data '{"name":"Ada","timezone":"UTC"}'

Retries, reliability, and performance

  • Because PUT is idempotent at the target-resource level, a client can usually retry a timed-out request more safely than a non-idempotent POST. Confirm the API contract and authentication behavior first.
  • Use bounded timeouts, exponential backoff, and a maximum retry count. Do not retry permanent 4xx responses such as validation failures.
  • Retry transient network errors and selected 5xx responses only when your request body is replayable and the server documents that behavior.
  • Send the smallest complete representation that satisfies the contract. Large bodies increase upload time and server parsing work.
  • Use conditional headers when concurrent writers are possible; they prevent silent lost updates.
  • Measure latency at the client and inspect response headers and logs. HTTP itself does not promise a particular throughput or uptime.

Common errors and fixes

Symptom Likely cause Fix
405 Method Not Allowed The route does not allow PUT Check the API documentation and the response Allow header; use the documented method.
415 Unsupported Media Type Missing or incorrect Content-Type Send the media type the endpoint accepts.
400 or 422 Malformed JSON or invalid fields Validate syntax, required fields, types, and enum values.
401 or 403 Missing, expired, or insufficient credentials Refresh credentials and verify the required permission.
409 Conflict Business rule or version conflict Read the error body, resolve the conflict, and send a new complete representation.
412 Precondition Failed If-Match or another precondition no longer matches GET the current resource and retry with a fresh condition.
Unexpected fields disappear PUT is being treated as replacement Send the complete representation, or use the API’s documented PATCH/merge operation.
Client hangs or times out Slow server, proxy, or network Set a client timeout, inspect server logs, and retry only under the endpoint’s retry policy.

Testing a PUT endpoint

  1. PUT a representation to an existing URI and verify the returned status and stored state.
  2. Repeat the identical request and verify the target state is unchanged.
  3. PUT to a missing URI and verify whether the API creates it or returns an error.
  4. Omit a field and confirm whether the contract replaces or merges it.
  5. Send invalid JSON, an unsupported media type, and missing credentials.
  6. Exercise concurrent updates with stale and current ETags.
  7. Verify that clients correctly handle both a JSON response body and 204 No Content.

Or skip the browser setup

If your PUT workflow also needs page screenshots for documentation, regression review, or an AI agent, ScreenshotNeo provides a website screenshot API and MCP server. It removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result.

One request returns a PNG, JPEG, WebP, or PDF:

curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for options including full-page and element capture, device presets, custom CSS and JavaScript, waits, blocking, cookies, headers, PDFs, caching, signed links, async jobs, bulk capture, and usage reporting. Its MCP server includes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000.

Create your free ScreenshotNeo account.

Frequently asked questions

Does PUT always create a resource?

No. Creation is possible when no current representation exists, but the endpoint decides whether that URI is creatable.

Can a PUT request have no body?

It can at the HTTP message level, but a replacement endpoint generally needs a representation. Follow the API contract for empty or zero-length resources.

Is PUT safer than POST?

PUT is idempotent, which can make retries easier to reason about. It is still unsafe because it changes server state and still requires authorization and validation.

Should a successful PUT return the updated object?

Either 200 OK with a representation or 204 No Content is common. The API should document which response clients should expect.

Can PUT update only one field?

Only if that API explicitly defines PUT as partial or merge-like. Standard replacement semantics require the desired complete representation; PATCH communicates partial changes more clearly.