---
search:
  tags:
    - Orders
    - PUT
seo:
  description: >-
    Setting status to most values requires policies.allowstatus: true in the
    request body. Reference for the PUT /orders/{id} endpoint in the Bolder API
    v2 API.
sidebar:
  badge: PUT
  label: Update an order
title: Update an order
type: openapi-operation
---
Setting `status` to most values requires `_policies.allow_status: true`
in the request body.

## Recommended pattern for retry-safe order creation

`POST /v2/orders` has no idempotency mechanism (see its description).
The recommended way to create an order safely under retry is
**`PUT /v2/orders/{id}` with `_upsert: true` and an `external_id`**
in the body:

- If no order exists yet with that `external_id` (scoped to the
  seller resolved via `shop_id`), one is created (response status
  `201`) using the same request body fields as `POST /v2/orders`
  (`shop_id`, `contact`, `line_items`, etc). The order gets a normal
  system-generated `code` — the URL `:id` is **not** used as, or
  turned into, the order's code; a client cannot pick the public
  order code this way. `:id` can be any placeholder (e.g. the same
  `external_id` value, for readability), since matching is done by
  `external_id`, not by the URL.
- If an order already exists with that `external_id`, it's updated
  in place (response status `200`) — a retried request converges on
  the same order instead of creating a duplicate.
- Without `_upsert: true`, `PUT` to a nonexistent `:id` returns `404`
  as usual.
- `_upsert: true` without an `external_id` in the body returns `422`
  — the flag requires `external_id` so a typo in the URL `:id` alone
  can't silently create an unintended order.

This is the same `external_id` field documented on `Order` and on
`POST /v2/orders` — a collision there is rejected with `422`;
here, under `_upsert`, a "collision" is the intended match and
updates the existing order instead.

## Stock restoration on cancellation

Setting `status` to `cancelled` automatically restores/releases reserved
stock, but only when both of these hold:

- the order's `fulfillment_status` is still unsent (`queued`,
  `preparing`, or `ready` — not yet `shipped`/`delivered`), and
- stock was actually reserved for the order in the first place (line
  items on non-stock-tracked products, or without a `variant_id` at all,
  never reserved anything, so there's nothing to restore for them).

Cancelling an order that has already shipped does **not** auto-restore
stock. Restoration is independent of payment state — it isn't affected by
whether the order was paid or refunded.

<Operation source="v2" id="updateorder" />
