Update a shipping on an offer
API v2 is in public beta: endpoints and fields can change before general availability. See the changelog
/preorders/offers/{id}/shippingCosts 2 rate-limit points · Rate limits
Update any subset of the shipping settings on a preorder offer: the shipping timeline text, delivery timing, fulfillment handling (hold, split or separate orders) and hold release.
Deep partial: absent fields are unchanged, null clears. Settings the save changes on its own (the purchase option and payments when separate orders turns on, split fulfillments when delivery leaves asap) are listed in also_changed. reschedule_existing_orders: true is the editor's "Reschedule existing orders to this date" checkbox: after the save, every unfulfilled, uncancelled preorder on the offer has its scheduled fulfillments moved to the offer's ship date (ships_at), or to its own order date plus days_after_checkout, in the background. It needs delivery_timing exact_time after the save, can be sent alone to re-apply the current date, and does not email customers (send a shipping update from the orders endpoints for that). When sent, the response has rescheduled_orders_queued.
Also searched asedit shippingchange shipping settingschange deliverychange fulfillmentmodify shippingenable fulfillment holdhold preorder fulfillmentsturn on fulfillment holdprevent shipping until releasedhold all fulfillmentshold ordershold fulfillmentsdisable fulfillment holdrelease fulfillmentsstop holding fulfillmentsturn off fulfillment holdlet preorder ship immediatelydisable splitdisable split ordersdisable split fulfillmentsturn off order splittingstop separating preordersrelease fulfillment holdenable splitturn on order splittingenable split ordersseparate preorder from regularenable split fulfillmentsenable split hold fulfillmentshold split order fulfillmentshold fulfillments on split orderdon't ship split order immediatelydisable split hold fulfillmentsrelease split order fulfillmentsship split order immediatelystop holding split orderenable split sequential numbersequential split order numbersnumber split orders sequentiallysequential order name for splitdisable split sequential numberno sequential split order numbersstop numbering split orders sequentiallyauto release holdsautomatically release holdsrelease holds on a datestop releasing holds automaticallyrelease holds after paymentset delivery asapship asapset delivery to asapship as soon as possibleset delivery dateship on dateset ship dateset exact delivery dateset delivery windowship within daysset delivery in daysset ship windowfulfillment hold reasonset shipping textchange shipping textupdate shipping messageset delivery textchange PDP shipping lineset split order suffixchange split suffixset split order name suffixrename split order suffixchange split order label textset split order tagchange split tagset split order labelset split transaction gatewayset split payment gatewaychange split order gateway
Path parameters
idstringRequired
Headers
Idempotency-KeystringA fresh unique key for every write (a new UUID, say); reuse it only to retry that write. Keys are remembered for 1 hour: the same key and the same request within that hour returns the first result, with
Idempotent-Replayed: true, without running again; the same key with a different method, path or body is refused (422idempotency_key_reused); a retry while the first is still running gets 409idempotency_key_in_progress. Keys are per store. Server errors and rate limits are not kept, so their retry runs.
Request body
timelineobjectShow 3 child attributesHide child attributes
scopestringsame shows one shipping text for every product; per_variant uses each variant's own shipping text (set per variant).
One ofsameper_variantshow_shipping_textbooleanShow shipping timeline on the widget. Also turns the cart line-item property (advanced.cart_attributes.show_shipping) on or off when it changes, as the editor does; sending the current value changes nothing.
shipping_textstringThe line under the preorder button. Required while show_shipping_text is true.
delivery_timingstringFulfillment status of preorder items: asap is Unfulfilled (ship now), exact_time is Scheduled (needs ships_at or days_after_checkout and the Shopify purchase option), unknown is On hold (no date promised). asap and unknown clear ships_at and days_after_checkout.
One ofasapexact_timeunknownships_atstringShip date: a date (2026-11-05), read as midnight in the shop time zone, or an ISO 8601 datetime (kept as that exact moment). Returned as the UTC datetime. Sending it alone makes delivery_timing exact_time on that date. Also sets timeline.variant_shipping_text (the {{ date }} value) to the date in the shop time zone, as the editor does: "05 Nov 2026".
days_after_checkoutintegerShip N days after checkout. Sending it alone makes delivery_timing exact_time with that delay; ships_at is then null. Also sets timeline.variant_shipping_text to "N days after checkout", as the editor does.
fulfillmentobjectShow 3 child attributesHide child attributes
handlingstringnone; hold_all holds every fulfillment; split_fulfillments ships in-stock items first (needs delivery_timing asap); separate_orders moves preorder items to their own order, which switches the Shopify purchase option off and resets partial payment, the discount and a Scheduled status (listed in also_changed).
One ofnonehold_allsplit_fulfillmentsseparate_ordershold_reasonstringThe hold reason shown in Shopify.
separate_ordersobjectShow 8 child attributesHide child attributes
groupingstringoffer creates one separate order per offer; variant one per variant; ship_date one per ship date (batch or shipping text), which needs timeline.scope per_variant or batches on.
One ofvariantoffership_datenumber_formatstringsequential gives each separate order its own order number; suffix appends suffix to the original order name.
One ofsequentialsuffixsuffixstringSuffix appended to the separate order name.
hold_fulfillmentsbooleanHold fulfillments on the separate order until they're released.
tagstringTag applied to the separate preorder order.
transaction_gatewaystringPayment gateway recorded on the separate order transaction.
original_order_hold_tagstringTag on the original order while it is being split. Removed once the split finishes.
original_order_split_tagstringTag on the original order after the preorder items move to a separate order.
on_holdobjectShow 3 child attributesHide child attributes
release_schedulestringscheduled releases held fulfillments on release_at; manual leaves them held.
One ofscheduledmanualrelease_atstringISO 8601. Required while release_schedule is scheduled.
require_paymentbooleanOnly release once the balance is paid.
reschedule_existing_ordersbooleantrue also moves the scheduled fulfillments of existing unfulfilled preorders on this offer to the ship date (ships_at, or each order date plus days_after_checkout), as the editor's "Reschedule existing orders to this date" checkbox does. Needs delivery_timing exact_time. No customer email.
localestringLanguage the translated fields are written in, such as 'fr' or 'pt-BR'. Omitted: the shop's default language. Untranslated fields ignore it.
Returns
timelineobjectShow 4 child attributesHide child attributes
scopestringExample:sameshow_shipping_textbooleanExample:trueshipping_textstringExample:Shipping: {{ date }}variant_shipping_textstringExample:ASAP
delivery_timingstringExample:exact_timeships_atanydays_after_checkoutintegerExample:30fulfillmentobjectShow 3 child attributesHide child attributes
handlingstringExample:hold_allhold_reasonstringExample:Waiting on stockseparate_ordersobjectShow 8 child attributesHide child attributes
groupingstringExample:offernumber_formatstringExample:suffixsuffixstringExample:SPLIThold_fulfillmentsbooleanExample:falsetagstringExample:STOQ-split-ordertransaction_gatewaystringExample:Prepaidoriginal_order_hold_taganyoriginal_order_split_tagany
on_holdobjectShow 3 child attributesHide child attributes
release_schedulestringExample:manualrelease_atanyrequire_paymentbooleanExample:false
Errors
Missing or invalid X-Auth-Token.
The resource does not exist for this shop, or the action path is not registered.
An earlier request with the same Idempotency-Key is still running. Wait, then resend the same request with the same key.
Invalid fields: one details entry per field error, its path the canonical section path. Nothing was saved.
Rate limited: cost-weighted per token (read 1, write 2; 360 points / 60s). Check Retry-After.
Every error has the same shape: see Errors.
curl -X PATCH "https://app.stoqapp.com/api/v2/external/preorders/offers/73a74948-2b57-4cc3-971f-2b441828c977/shipping" \
-H "X-Auth-Token: $STOQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"days_after_checkout": 30,
"fulfillment": {
"handling": "hold_all",
"hold_reason": "Waiting on stock"
}
}'const res = await fetch("https://app.stoqapp.com/api/v2/external/preorders/offers/73a74948-2b57-4cc3-971f-2b441828c977/shipping", {
method: "PATCH",
headers: {
"X-Auth-Token": process.env.STOQ_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"days_after_checkout": 30,
"fulfillment": {
"handling": "hold_all",
"hold_reason": "Waiting on stock"
}
}),
});
const data = await res.json();import os
import requests
res = requests.patch(
"https://app.stoqapp.com/api/v2/external/preorders/offers/73a74948-2b57-4cc3-971f-2b441828c977/shipping",
headers={"X-Auth-Token": os.environ["STOQ_API_KEY"]},
json={
"days_after_checkout": 30,
"fulfillment": {
"handling": "hold_all",
"hold_reason": "Waiting on stock"
}
},
)
data = res.json()require "net/http"
require "json"
uri = URI("https://app.stoqapp.com/api/v2/external/preorders/offers/73a74948-2b57-4cc3-971f-2b441828c977/shipping")
req = Net::HTTP::Patch.new(uri, "X-Auth-Token" => ENV["STOQ_API_KEY"], "Content-Type" => "application/json")
req.body = {
days_after_checkout: 30,
fulfillment: {
handling: "hold_all",
hold_reason: "Waiting on stock"
}
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){
"timeline": {
"scope": "same",
"show_shipping_text": true,
"shipping_text": "Shipping: {{ date }}",
"variant_shipping_text": "ASAP"
},
"delivery_timing": "exact_time",
"ships_at": null,
"days_after_checkout": 30,
"fulfillment": {
"handling": "hold_all",
"hold_reason": "Waiting on stock",
"separate_orders": {
"grouping": "offer",
"number_format": "suffix",
"suffix": "SPLIT",
"hold_fulfillments": false,
"tag": "STOQ-split-order",
"transaction_gateway": "Prepaid",
"original_order_hold_tag": null,
"original_order_split_tag": null
}
},
"on_hold": {
"release_schedule": "manual",
"release_at": null,
"require_payment": false
}
}{
"errors": [
"Invalid API key"
],
"code": "auth_invalid",
"details": [
{
"code": "auth_invalid",
"message": "Invalid API key",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"Offer not found"
],
"code": "not_found",
"details": [
{
"code": "not_found",
"message": "Offer not found",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"A request with this Idempotency-Key is still running"
],
"code": "idempotency_key_in_progress",
"details": [
{
"code": "idempotency_key_in_progress",
"message": "A request with this Idempotency-Key is still running",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"widget.button.text_color must be a hex color"
],
"code": "invalid_params",
"details": [
{
"code": "invalid_params",
"message": "must be a hex color",
"path": "widget.button.text_color",
"value": "blue",
"expected": {
"type": "string"
}
}
]
}{
"errors": [
"Rate limit exceeded"
],
"code": "rate_limited",
"details": [
{
"code": "rate_limited",
"message": "Rate limit exceeded",
"path": null,
"value": null,
"expected": null
}
]
}