201 - Created
HTTP 201 Created means the request succeeded and a new resource was created as a result. The server should return the new resource URI in the Location response header.
Last reviewed: March 7, 2026|Editorial standard: source-backed technical guidance
What Does Created Mean?
201 confirms both transport success and a state change — a new resource now exists. Missing Location header or wrong response body after 201 breaks downstream resource tracking and idempotency guarantees.
Common Causes
- -Client does not receive 201 confirmation due to network timeout and retries the POST, causing the server to create a duplicate resource because the handler is not idempotent.
- -Server returns 201 but omits the Location header, so the client cannot reference the newly created resource without issuing a separate lookup request.
- -Client code treats any non-201 response as failure and does not handle 200 fallback, causing integration breaks when legacy endpoints return 200 for resource creation instead of 201.
How to Fix Created
- 1Check whether the POST handler implements idempotency keys so duplicate requests return the existing resource instead of creating a second one.
- 2Verify the server includes a Location header in the 201 response pointing to the canonical URI of the new resource.
- 3Update client integration logic to accept both 200 and 201 as valid success responses for resource creation endpoints.
Step-by-Step Diagnosis for Created
- 1Confirm the response status is 201 and inspect the Location header for the new resource URI.
- 2Check server logs for duplicate resource creation when the same client request appears more than once within a short window.
- 3Verify the created resource is immediately accessible via GET at the Location URI, accounting for any propagation delay.
- 4Test the endpoint with and without an idempotency key header to confirm duplicate-safe behavior.
Idempotency and Duplicate Creation
- -Inspect whether the POST handler checks for an idempotency key (example:
Idempotency-Keyheader) and returns the existing 201 response on replay rather than creating a new record. - -Correlate creation timestamps in the database with client retry logs to confirm whether duplicates are appearing after network-level timeouts (example: two orders with identical payload 800ms apart).
Location Header and Resource Accessibility
- -Confirm the Location header is present and resolves to the canonical resource URI (example:
Location: /v1/users/456after POST /v1/users). - -Test a GET request to the Location URI immediately after 201 to verify the resource is readable and not blocked by replication lag or cache propagation (example: read replica returns 404 for 200ms after write).
Implementation Examples
curl -i -X POST https://api.example.com/v1/users \
-H 'Content-Type: application/json' \
-d '{"name":"Alice","email":"alice@example.com"}'
# Response:
# HTTP/1.1 201 Created
# Location: /v1/users/456
# {"id":"456","name":"Alice","email":"alice@example.com"}const response = await fetch('https://api.example.com/v1/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' }),
});
if (response.status === 201) {
const location = response.headers.get('Location');
const created = await response.json();
console.log('Created at:', location, created);
}import requests
response = requests.post(
'https://api.example.com/v1/users',
json={'name': 'Alice', 'email': 'alice@example.com'},
)
if response.status_code == 201:
location = response.headers.get('Location')
created = response.json()
print(f'Created at: {location}', created)How to Verify the Fix
- -Re-run the POST request and confirm 201 is returned with a valid Location header pointing to the new resource.
- -Issue a GET to the Location URI and verify the response matches the resource created in the POST body.
- -Replay the same POST with the same idempotency key and confirm the server returns the original 201 without creating a duplicate.
How to Prevent Recurrence
- -Enforce idempotency keys on all non-idempotent POST endpoints and document the expected behavior in API contracts.
- -Add contract tests that assert Location header presence and validity on every 201 response in CI.
- -Standardize client integration libraries to handle both 200 and 201 as creation success so legacy and modern endpoints are supported uniformly.
Pro Tip
- -store the idempotency key alongside the created resource in the database so duplicate detection survives server restarts and horizontal scaling without relying on in-memory caches.
Decision Support
Compare Guide
403 Forbidden vs 404 Not Found: When to Hide Resources
Use 403 for explicit access denial, or 404 to conceal resource existence when security policy requires reducing endpoint and object enumeration risk.
Compare Guide
404 Not Found vs 410 Gone: Missing vs Permanent Removal
Learn when to return 404 (missing or temporary absence) versus 410 (intentional permanent removal), including redirect and cache implications.
Playbook
Resource State Playbook (404 / 410 / ResourceNotFound)
Use this playbook to separate temporary missing-resource lookups from permanent removals, then fix scope, lifecycle, and identifier drift safely.
Official References
Provider Context
This guidance is specific to HTTP services. Always validate implementation details against official provider documentation before deploying to production.