Skip to content

Update Purchase Order

PUT
/purchase_orders/{id}

🚀 Paid plan only

Updates a purchase order. Also accepts PATCH.

state is a plain attribute assignment with no inclusion check, so only ever send draft, active or completed - any other value persists and hides the purchase order from every state filter. Moving to active has server-side effects: it creates stock entries for every variant at the destination warehouse and is what enables the supplier emails.

received_quantity on a line item is a DELTA, not a target: stored received becomes previous + received_quantity, warehouse physical stock is adjusted by the delta, the variant cost price is recalculated and received_at is stamped. It is NOT idempotent and there is no reverse, so send it once and never retry it automatically. For a purchase order in a currency other than the company’s, set currency_rate explicitly - it defaults to 0 and the cost-price recalculation multiplies by it.

Line items are edited by id and added by omitting the id. There is no _destroy: use Delete Purchase Order Line Item. Add only ONE new line item per request - a second line for a variant already on the purchase order is dropped silently.

id
required
integer

Purchase order ID.

Example
491
x-api-key
string

E.g. 123

Example
123
object
purchase_order
required
object
supplier_id

Supplier ID. Required; must belong to the company.

integer
destination_warehouse_id

Warehouse ID stock is delivered to. Required; must belong to the company.

integer
state

Lifecycle state: draft -> active -> completed.

string
Allowed values: draft active completed
number

PO number. Auto-generated if blank.

string
reference_number

Must be unique per company.

string
expected_date

Expected delivery date (must fall between 2010-01-01 and 2035-01-01).

string format: date-time
currency_code

Default GBP. Cannot be changed once the PO is active.

string
currency_rate
number
estimated_delivery_days

Recalculated as whole days from created_at to expected_date on any save that changes either date, overwriting a value sent in the same request. Sent on its own it is stored as given. Send expected_date and omit this.

integer
note
string
shipping_and_handling
number
send_to_supplier

DEAD FIELD - it is stored and wired to nothing. Use send_supplier_report_email.

boolean
send_supplier_report_email

Emails the supplier the purchase order on save, but ONLY when the purchase order is (or becomes) active - a draft never emails, silently. Delivery is also suppressed entirely for some companies (multi-channel accounts, and sellers who have not used the standalone app) and the response looks identical, so never report it as sent.

boolean
supplier_report_format

NOT validated, so any string is accepted - deliberately left unconstrained here. Only pdf or csv attaches a document; every other value, and omitting it, sends the email with no attachment (unlike the reminder path, which defaults to pdf).

string
shipping_address_line_1
string
shipping_address_line_2
string
shipping_address_town
string
shipping_address_state
string
shipping_address_postcode
string
shipping_address_country
string
billing_address_line_1
string
billing_address_line_2
string
billing_address_town
string
billing_address_state
string
billing_address_postcode
string
billing_address_country
string
purchase_order_product_variants_attributes

Line items.

Array<object>
object
id

Existing line item ID (update requests only).

integer
product_variant_id

Must exist in the company and not be deleted. Required for create requests.

integer
quantity

Must be greater than 0. Required for create requests.

integer
cost

Unit cost. Must be greater than 0. Required for create requests.

number
tax_rate

Required for create requests.

number
display_position
integer
shipped
boolean
supplier_reference_number

Updates the supplier product variant reference.

string
supplier_title

Updates the supplier product variant title.

string
received_quantity

Update requests only — increments the received count for the line item. Cannot be negative.

integer
Example
{
"purchase_order": {
"state": "active",
"note": "Updated note",
"purchase_order_product_variants_attributes": [
{
"id": 1575,
"received_quantity": 5
}
]
}
}

OK. Returns the updated purchase order. NOTE: a COMPLETED purchase order also answers 200 while applying NOTHING - every column is blocked and nested line items are dropped silently, so read state before offering an edit.

object
billing_address_country
string
nullable
billing_address_line_1
string
nullable
billing_address_line_2
string
nullable
billing_address_postcode
string
nullable
billing_address_state
string
nullable
billing_address_town
string
nullable
created_at
string format: date-time
created_by
object
email
string
id
number
login
string
created_by_id
number
nullable
currency_code
string
nullable
currency_rate

Decimal serialized as a JSON string. Coerce before arithmetic. Defaults to 0. Set it explicitly for a purchase order in a currency other than the company’s: receiving multiplies the cost price by it.

string
destination_warehouse
object
address_line_1
string
nullable
address_line_2
string
nullable
city
string
nullable
click_and_collect_days
nullable
click_and_collect_enabled
boolean
country
string
nullable
created_at
string format: date-time
created_by_id
number
nullable
cut_off_times
nullable
cut_off_times_enabled
boolean
default_min_reorder
number
nullable
deleted_at
string format: date-time
nullable
deleted_by_id
number
nullable
display_position
number
nullable
eori_id
string
nullable
external_id
string
nullable
id
number
inventory_type_code
string
nullable
ioss_id
string
nullable
letterbox_address_status
nullable
name
string
phone
string
nullable
post_code
string
nullable
region
string
nullable
requested_carrier_account
nullable
tax_id
string
nullable
trading_name
string
nullable
uk_ims_id
string
nullable
updated_at
string format: date-time
updated_by_id
number
nullable
destination_warehouse_id
number
estimated_delivery_days

Whole days from created_at to expected_date, recalculated on any save that changes either date. A value you send is kept only until expected_date next changes, so treat it as derived and drive it with expected_date.

number
nullable
expected_date
string format: date-time
nullable
id
number
note
string
nullable
number
string
product_variants_count
number
purchase_order_product_variants

The line items. This is the key - there is no line_items field on a purchase order.

Array<object>
object
cost

Unit cost. Decimal serialized as a JSON string. Coerce before arithmetic.

string
created_at
string format: date-time
created_by_id
number
nullable
id

Line item id. Pass it to the line-item sub-routes.

number
product_variant_id

The SELLABLE id, the same id the sellables endpoints return. No translation is needed in either direction.

number
purchase_order_id
number
quantity

Units ordered.

number
received

Units received so far. Set indirectly by sending received_quantity as a delta, and never settable directly.

number
nullable
received_at
string format: date-time
nullable
shipped
boolean
nullable
supplier_id

Always the purchase order’s supplier - a sent value is overwritten.

number
tax_rate

Decimal serialized as a JSON string. Coerce before arithmetic.

string
total_amount_excluding_tax

Decimal serialized as a JSON string. Coerce before arithmetic.

string
total_amount_including_tax

Decimal serialized as a JSON string. Coerce before arithmetic.

string
updated_at
string format: date-time
updated_by_id
number
nullable
supplier_product_variant
object
average_cost

Decimal serialized as a JSON string. Coerce before arithmetic.

string
cost

Decimal serialized as a JSON string. Coerce before arithmetic.

string
created_by_id
number
nullable
default_supplier
boolean
has_active_purchase_order
boolean
id
number
lead_time
number
nullable
product_variant_id
number
reference_number
string
nullable
supplier_id
number
tax_rate
number
nullable
title
string
nullable
updated_by_id
number
nullable
supplier

The same supplier shape as the purchase order’s own supplier.

object
product_variant
object
active_channels
Array
allocated_stock_level_at_all_warehouses
number
available_stock_level_at_all_warehouses
number
channel_sellables
Array
cost_price
number
created_at
string
created_by_id
number
full_title
string
id
number
images
Array
inventory
object
allocated_stock_level_at_all_warehouses
number
available_stock_level_at_all_warehouses
number
incoming_stock_level_at_all_warehouses
number
infinite
boolean
physical_stock_level_at_all_warehouses
number
margin
number
measurement_attributes
object
depth
number
dimensions_unit
string
height
number
id
number
width
number
min_reorder_level
number
model_number
string
on_hand_value
number
price
number
product
object
description
string
estimated_delivery
nullable
hs_tariff_number
nullable
id
number
main_image
object
binary_data
nullable
content_type
nullable
created_at
string
created_by_id
nullable
deleted_at
nullable
deleted_by_id
nullable
display_position
nullable
id
number
picture_content_type
nullable
picture_file_name
nullable
picture_file_size
nullable
picture_order
number
picture_updated_at
nullable
product_id
number
src
string
updated_at
string
updated_by_id
nullable
main_image_src
string
origin_country
nullable
tax_rate
number
title
string
weight
number
product_title
string
profit
number
quantity_to_reorder
number
sellable_title
string
sku_code
string
stock_entries
Array<object>
object
allocated_stock_level
number
available_stock_level
number
incoming_stock_level
number
infinite
boolean
location
nullable
physical_stock_level
number
sellable_id
number
sellable_on_hand_value
number
stock_running_low
boolean
updated_at
string
warehouse
object
address_line_1
string
address_line_2
string
city
string
click_and_collect_days
nullable
click_and_collect_enabled
boolean
country
nullable
created_at
string
created_by_id
number
default_min_reorder
number
deleted_at
nullable
deleted_by_id
nullable
id
number
inventory_type_code
string
name
string
phone
nullable
post_code
string
region
string
requested_carrier_account
nullable
updated_at
string
updated_by_id
nullable
user_id
nullable
warehouse_id
number
stock_level_at_all_warehouses
number
tax_rate
number
title
string
total_quantity_sold
number
type
string
upc_code
string
updated_at
string
variant_option_specifics
Array
variant_property_specifics
Array
weight
number
received_at
string format: date-time
nullable
received_product_variants_count
number
reference_number

Unique per company when present. A duplicate is a 400.

string
nullable
sent_at
string format: date-time
nullable
shipping_address_country
string
nullable
shipping_address_line_1
string
nullable
shipping_address_line_2
string
nullable
shipping_address_postcode
string
nullable
shipping_address_state
string
nullable
shipping_address_town
string
nullable
shipping_and_handling

Decimal serialized as a JSON string. Coerce before arithmetic.

string
state

Only these three values are ever returned. The received-status values accepted by the list state filter are filter-only inputs.

string
Allowed values: draft active completed
subtotal

Computed on read, never stored. Decimal serialized as a JSON string. Coerce before arithmetic.

string
supplier
object
accounting_contact_email
string
nullable
accounting_contact_name
string
nullable
accounting_phone_number
string
nullable
active_purchase_order_count
number
address_line_1
string
nullable
address_line_2
string
nullable
city
string
nullable
completed_purchase_order_count
number
country
string
nullable
created_at
string format: date-time
created_by_id
number
nullable
currency_code
string
nullable
deleted_at
string format: date-time
nullable
deleted_by_id
number
nullable
id
number
name
string
post_code
string
nullable
purchase_order_template

The template used to render this supplier’s purchase order document, on a plan with customizable templates.

string
nullable
region
string
nullable
reminder_email_template
string
nullable
sales_contact_email

Reminder and report emails go here. Can be blank, and the send still reports success.

string
nullable
sales_contact_name
string
nullable
sales_phone_number
string
nullable
updated_at
string format: date-time
updated_by_id
number
nullable
supplier_id
number
supplier_report_format

Write-only: there is no stored column, so List and Get always return null. A Create or Update response echoes the value sent in that same request.

string
nullable
total_excluding_tax

Decimal serialized as a JSON string. Coerce before arithmetic.

string
total_including_tax

Use this for the purchase order value, computed on read and never stored. Decimal serialized as a JSON string. Coerce before arithmetic.

string
total_tax

Decimal serialized as a JSON string. Coerce before arithmetic.

string
units_ordered
number
units_received
number
updated_at
string format: date-time
updated_by_id
number
nullable
user_id
number

Validation failed. currency_code and supplier_id cannot be changed once the PO is active (“can’t update on state active”). On UPDATE the line-item messages are prefixed “Purchase order product variants …”.

The company’s plan does not include purchase orders, or the user lacks the manage_purchase_orders permission. Body is {"error_messages":[...]}. Checked before the body is read.

Purchase order not found (or belongs to another company). Also returned INSTEAD OF a 400 when a changed supplier_id, destination_warehouse_id or any line-item product_variant_id does not resolve in the company.