Bounded Context Logo

About the author

Karthik Vijay is a rare all-rounder with 20+ years of experience, specializing in Architecture, Engineering, Leadership, and Productivity.

View LinkedIn Profile

When to use HTTP PUT vs POST?

HTTP PUT vs POST

TL;DR

Use PUT when you’re creating or updating a resource at a known, stable URI and want idempotency.

Use POST when the server generates the identifier, performs an action, or when idempotency doesn’t apply. POST can be used to create or update resources, but it’s most common for creation when the server assigns the identifier. For updates, PUT or PATCH are usually a better fit.

What is idempotency?

Idempotency means running the same request many times has the same effect as running it once. In APIs, this lets you safely retry without messing up data or creating duplicates.

Idempotent Verbs

  1. GET Retrieves data; repeated requests return the same result without changing server state.
  2. PUT Updates or creates a resource at a known URI; repeating the request leaves the resource in the same state.
  3. DELETE Removes a resource; deleting it multiple times has the same effect as deleting it once (resource no longer exists).
  4. HEAD, OPTIONS, TRACE Also considered idempotent since they don’t change server state.

Non Idempotent Verbs

  1. POST Typically creates resources or triggers actions with side effects; repeating may create duplicates or multiple effects unless an idempotency key is used.
  2. PATCH Generally used for partial updates; can be idempotent if designed carefully, but some implementations may have side effects, so treat it as potentially non-idempotent.

PUT

Example 1 - Change home loan repayment

Changing the repayment on a home loan means you’re updating an existing resource (the loan record already exists, and you’re modifying one of its attributes — e.g. repayment amount, schedule, or frequency).

That maps best to:

  1. PUT if you’re replacing the repayment details with a full new representation.
  2. PATCH if you’re only partially updating (e.g. just the repayment amount, without touching other fields).

# Update the full repayment object
PUT /loans/12345/repayment
Content-Type: application/json
{
  "amount": "1500.00",
  "frequency": "monthly",
  "nextDate": "2025-10-01"
}

You would not normally use POST, since you’re not creating a new loan or triggering an action, just modifying an existing one.

👉 So the answer: Use PUT (or PATCH) to change your repayment details.

PUT is always idempotent by design. This means that sending the same PUT request multiple times has the same effect as sending it once. Whether you’re creating a resource at a known URI or updating an existing one, repeating the request will not create duplicates or unintended changes — the resource simply ends up in the same state.

PATCH is conditionally idempotent and is used for partial updates to a resource. Its idempotency depends on how the server implements it:


# Update only the amount
PATCH /loans/12345/repayment
Content-Type: application/json
{
 "amount": "1500.00"
}
  1. If applying the same patch multiple times always results in the same resource state, then the PATCH request behaves idempotently.
  2. However, PATCH is not guaranteed to be idempotent by the HTTP spec, because some partial updates may depend on the current state or trigger side effects.

Example 2 - Create or update a subscription


PUT /users/98765/subscription
Content-Type: application/json
{
  "plan": "premium",
  "autoRenew": true,
  "startDate": "2025-10-01"
}
  1. Subscription exists (update): If user 98765 already has a subscription, this request updates the plan, auto-renew setting, or start date.
  2. Subscription does not exist (create): If no subscription exists for this user, the request creates one at the specified URI.

POST

POST is used to create a new resource or trigger an action on the server when the client does not know the resource URI in advance. It’s suitable for operations that produce side effects, such as creating a user, submitting a form, or initiating a money transfer. POST is not idempotent by default — sending the same request multiple times can create duplicates or repeat actions — but using an idempotency key can make retries safe.

Example 1 - Transfer money between accounts


POST /accounts/transfer
Content-Type: application/json
{
  "fromAccountId": "12345",
  "toAccountId": "67890",
  "amount": "5000.00",
  "currency": "NZD"
}
  1. Server-generated result: Each transfer usually gets a unique transaction ID, assigned by the server.
  2. Action-oriented: This request triggers a business action (moving money), rather than updating a single resource.
  3. Not idempotent by default: Repeating the same POST request could create multiple transfers, so clients often use an idempotency key to prevent accidental duplicates as below.

# Optional idempotency key:
# With the Idempotency-Key, sending the request multiple times will only create one transfer.
POST /accounts/transfer
Content-Type: application/json
Idempotency-Key: 01H9K4G7X8Z5A1B2C3D4E5F6G7
{
  "fromAccountId": "12345",
  "toAccountId": "67890",
  "amount": 500,
  "currency": "NZD"
}

Example 2 - Create a support ticket


POST /support/tickets
Content-Type: application/json
Idempotency-Key: 01H9K4G7X8Z5A1B2C3D4E5F6G8
{
  "userId": "98765",
  "subject": "Unable to access account",
  "description": "I am getting an error when logging in with my credentials.",
  "priority": "high"
}
  1. Server-generated result: Each ticket gets a unique ticket ID assigned by the server.
  2. Action-oriented: Submitting a ticket triggers a new resource creation and potentially other workflows (notifications, assignments).
  3. Not idempotent by default: Repeating the same request without an Idempotency-Key could create multiple tickets, but using the key makes it safe to retry.