Update the shipping address for an order that has not yet gone into production. On a live order the new address is checked as POST /order checks one (POST /addresses/validate's check), and an address that cannot be right as written is refused 422 address_invalid before the facility or the order is touched; a test order is never refused for it. Our own facilities ship to US addresses only, so an address outside the US is refused 422 destination_unavailable before anything is changed.
- 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.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
namestringrequirednon-empty
companystringaddress1stringrequirednon-empty
address2stringcitystringrequirednon-empty
statestringrequirednon-empty
zipstringrequirednon-empty
countrystringrequiredISO 3166-1 alpha-2 country code
exactly 2 characters
phonestringemailstring (email)
Request
PUT /api/v1/order/{id}/address
curl -X PUT "https://portal.printedsimply.com/api/v1/order/test_ord_wVK9ZiG-VYiPrlSeBUBmrUVk/address" \
-H "x-api-key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: update-order-address-$(date +%s)" \
-d '{
"name": "Jane Doe",
"address1": "456 Oak Ave",
"city": "Austin",
"state": "TX",
"zip": "78702",
"country": "US"
}'Response 200
Address updated
data
order_idstringrequiredThe order's id, the one every order operation takes. On a live order, the facility's reply supplies it when it carries one.
portal_order_idstringrequiredThis platform's own id for the order (
ord_…). On a live order, the facility's reply supplies it when it carries one.statusstringThe order's status; the amendment does not move it. Always present on a sandbox answer, one of pending_approval, pending_payment, paid, accepted, in_production, quality_check, shipped, delivered, cancelled, issue_flagged, rerouting, pending, processing, on-hold, completed, refunded, failed. On a live answer, the facility's own value when its reply carries one, and otherwise absent: it is never filled from our record (read GET /order/{id}).
providerstringAlways
merchfarmon a sandbox answer. On a live answer, the facility's own value when its reply carries one, and otherwise absent.ship_toobjectrequiredThe address the order now ships to, as accepted. On a live order, the facility's own
ship_towhen its reply carries one; otherwise the address on our record, which this call has just written.test_modebooleanPresent and true on a sandbox order; absent on a live one, as on GET /order/{id}.
Always
true
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": {
"order_id": "test_ord_wVK9ZiG-VYiPrlSeBUBmrUVk",
"portal_order_id": "ord_wVK9ZiG-VYiPrlSeBUBmrUVk",
"status": "paid",
"provider": "merchfarm",
"ship_to": {
"name": "Jane Doe",
"address1": "456 Oak Ave",
"city": "Austin",
"state": "TX",
"zip": "78702",
"country": "US"
},
"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).404Resource not found
order_not_modifiable — the order has gone into production (or later), past the point where its address can change: an order takes a change only while it is pending_payment, paid or accepted. Terminal for this order.
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.
destination_unavailable — the new address is outside the US, and the order is already with one of our own facilities, which ship to US addresses only.
details.reasonisdestination_not_usanddetails.countrynames the destination; cancel the order and place a new one. address_invalid — a live order's new address cannot be right as written:details.findings[]names eacherror(zip_format,state_unknown,zip_state_mismatch, ordelivery_point_not_foundwhere USPS verification is configured) with its field, anddetails.address_checkis the whole check, as POST /addresses/validate answers it. Nothing was sent to the facility and the order still ships to its previous address. A test order is never refused for it.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.not_supported_by_provider — the order was produced by an independent network shop, which does not accept amendments at all. Not a timing problem and never retryable, which is what separates it from the 409.
fulfillment_error — the facility refused the change, answered while still holding the previous address, or did not confirm it (unreachable, timed out, or a reply that could not be read). The order's ship_to and its webhooks are unchanged either way. When the facility refused, or is known to hold the previous address, the order still ships there. When the facility did not confirm, the order is read back from it: if it already holds the new address the request answers 200 as if it had confirmed, and if that cannot be told the message says the change may not have been applied. Retrying the same request is safe in every case: it sends the same address again.
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.