Change the quantity of an item. Charges the delta if increasing, refunds if decreasing: the line's goods, and what the new quantity does to the order's shipping. The order ships one parcel, so it is re-priced for the new quantity by the method the order is recorded as shipping by (standard when it recorded none), on its own lane, folded as POST /order folds it: the lines before and after are priced on today's terms and the difference moves with the goods, in the same direction. An increase never refunds shipping and a decrease never charges it; a decrease never refunds the shipping line below what the smaller parcel costs today. shipping says what moved; total_delta_cents is the whole charge or (negative) refund, the figure the key's spend caps see on an increase. On an order shipping by letter, an increase the letter cannot take is refused 400 letter_mail_unavailable with details.reason, as POST /order refuses the same lines, and nothing moves; a parcel method no longer offered refuses an increase with 400 shipping_method_unavailable. A decrease is never refused for either: its goods are refunded and its shipping stays as charged.
- Credential
- An API key in
x-api-key - Scopes
orders:write
Parameters
idpath · stringrequiredThe order's
order_id, or itsportal_order_id(ord_…): either resolves the same order. An id the order answered to before it was re-routed resolves too.itemIdpath · stringrequiredItem ID
Idempotency-Keyheader · string (uuid)Unique key for idempotent requests. If you retry a request with the same key within 24 hours, you receive the original response. The key is bound to the request payload: reusing it for a different payload returns 422
idempotency_key_reuserather than the original response, so a changed request is never silently dropped. The binding is over the JSON's content, not its bytes — keys in another order or other whitespace are the same request. Generate a new key for each new request. On an operation that moves money (an order, a batch, an item, a shipping or address change, a cancellation's refund), a key that cannot be checked because the idempotency ledger is unreachable is answered 503idempotency_unavailablewithRetry-After, and nothing runs or is charged: retry with the same key.
Request body application/json, required
quantityintegerrequired1 to 10000
Request
PUT /api/v1/{id}/item/{itemId}
curl -X PUT "https://portal.printedsimply.com/api/v1/test_ord_wVK9ZiG-VYiPrlSeBUBmrUVk/item/itm_fowT5-1iZwSnQcGX0ByoA64l" \
-H "x-api-key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: update-item-$(date +%s)" \
-d '{
"quantity": 5
}'Response 200
Item updated
data
test_modebooleanTrue when the order is a sandbox order.
itemobjectrequireditem.idstringitem.skustringitem.previous_quantityintegeritem.new_quantityintegeritem.unit_pricestringitem.deltastringThe line's goods delta. What the card moved is
total_delta_cents.shippingobjectrequiredWhat an item change did to the order's shipping line. The order ships one parcel, so adding a line or changing a quantity re-prices it: by the order's recorded method on its own lane, the lines before and after priced on today's terms, the difference charged with the goods on an increase and refunded with them on a decrease.
shipping.methodstringrequiredThe method the parcel was priced by: the order's recorded one, or
standardwhen it recorded none.One of
standardpriorityexpresslettershipping.shipping_classobject | nullrequiredThe parcel the order's lines now pack into, as POST /shipping/estimate reports it: a weight band (
parcel_1lb,parcel_2lb,parcel_5lb,parcel_over_5lb), with_tubewhen it ships rolled. Null on a letter.shipping.shipping_class.namestringrequiredshipping.shipping_class.weight_oznumberrequiredEstimated shipped weight in ounces, packing tube included.
shipping.delta_centsintegerrequiredWhat this change moved on the shipping line, in cents: positive when it was charged, negative when it was refunded, 0 when the parcel's price did not change (or a decrease's shipping could not be priced and stays as charged).
shipping.shipping_centsintegerrequiredThe order's shipping line after this change, in cents.
total_delta_centsintegerrequiredEverything this call moved, in cents: the line's goods delta and
shipping.delta_cents, charged when positive and refunded across the order's charges when negative. The figure the key's spend caps see on an increase and order.updated'stotal_delta_cents. On a sandbox order nothing moves and this is what a live order would move.
meta
pageintegertotalintegerlimitintegerThe page size actually applied, which is not necessarily the one asked for — the operation's own ceiling wins.
pagesintegertotaloverlimit, rounded up.next_cursorstring | nullOn a cursor-paged operation: send this back as
cursorfor the next page. Null on the last page. Absent on operations that do not page by cursor.has_morebooleanOn a list operation whose
metaisListMeta: whether another page follows this one.
{
"status": "success",
"data": {
"item": {
"id": "itm_vNx36IWd8kx2dCQqkFbsTVg3",
"sku": "magnet-4x4",
"previous_quantity": 25,
"new_quantity": 5,
"unit_price": "$2.47",
"delta": "$-49.40"
},
"shipping": {
"method": "standard",
"shipping_class": {
"name": "parcel_2lb",
"weight_oz": 17.1
},
"delta_cents": -700,
"shipping_cents": 1399
},
"total_delta_cents": -5640,
"test_mode": true
},
"request_id": "4e3753e1-48dd-4313-bfd8-48e4af4e116a"
}Errors
Invalid request body or parameters. When the request failed the operation's schema,
detailscarriesformErrors(problems with the request as a whole),fieldErrors(messages keyed by top-level field) anderrors: one{ pointer, code, message }per refused value,pointeran RFC 6901 JSON pointer into the body (or into the object of query parameters, for a query parameter) —/items/0/sku, with~written~0and/written~1, and""for the request as a whole. POST /v1/orders/bulk answerserrorsas one{ index, details }per refused order, eachdetailswith its own pointers from the request body (/orders/3/items/0/sku); POST /v1/orders/multi-ship keepserrorsas the{ formErrors, fieldErrors }it always published; POST /v1/mockups/generate and POST /v1/products/recommend keep their fields at the top ofdetails, witherrorsbeside them. A refusal of a rule the schema cannot state (an asset that does not exist, an expiry too soon) names it inmessageand carries noerrors.Missing, invalid or expired API key:
missing_api_key(none sent),invalid_api_key(unknown or revoked),key_expired(past the expiry set when it was created; create a new key).402Payment failed or no payment method configured
403sandbox_onlysandbox_only — the account is restricted to sandbox mode and the request used a live key.
404Resource not found
order_not_modifiable — the order has gone into production (or later), past the point where its items can change. shopper_paid_order — a quantity increase on an order a shopper paid for (a drop, a checkout link or an agent checkout); it would be charged to your card and refunded to the shopper. A decrease is allowed and refunds the shopper's own charge.
payload_too_large — the request body exceeded this route's byte cap (256 KB unless the route raises it with a written reason). It is refused before it is parsed, so nothing was created. Send fewer rows, or use the endpoint's own asynchronous door where it has one.
variable_data_invalid — the line was placed with per-unit variable data, which fixes its quantity to the units it carries (
details.problems[0].codeiscount_mismatch). Nothing was charged or refunded; cancel the line and order it again with the units you want. artwork_required — a new quantity for a line with no artwork on record, on a live order at our own plant (details.item_id,details.sku): the change is sent to the plant with the line's SKU and its file, and the plant prints every line from a file, so it is refused before anything is charged or refunded. Cancel the line and add it again with a print_file. A test key is not refused, and a PUT that restates the current quantity sends the plant nothing. sku_not_available — a quantity increase on a line our own plant does not make (one placed before this portal sold only its own products); refused before anything is charged, anddetails.skusnames it. A decrease is allowed.Rate limit exceeded. Two windows can produce this status and
error.codesays which:rate_limit_exceededfor the per-minute sliding window,daily_quota_exceededfor the plan's daily quota. Both carryRetry-After; the daily one also carriesX-Daily-LimitandX-Daily-Remaining. The per-minute limits are plan-based — see Rate Limits above, or call GET /v1/me for this credential's own figures.refund_failed — the quantity decrease was applied but the refund for it could not be processed. The money is owed and support is alerted; do not retry, which would decrease the quantity again.
not_supported_by_provider — the order was produced by an independent network shop, which does not accept amendments at all. Never retryable, unlike the 409. Live PrintedSimply quantity changes are also refused before any charge or refund because the plant handler is not confirmed.
502Production system error
idempotency_unavailable — the request carried an
Idempotency-Keyand the ledger that makes it mean at-most-once could not be reached, so nothing ran and nothing was charged; retry the same request with the same key afterRetry-After.