Home
Preorders

Offer capabilities

The twelve capability groups exposed on a preorder offer. Each has a Read action, an Update (deep partial PATCH) for settings and toggles, and intent-bearing POST actions for operations with side effects.

A capability is a coherent sub-group of an offer's configuration. Every capability follows the same shape:

  • GET /preorders/offers/:id/{capability} — read current state
  • PATCH /preorders/offers/:id/{capability} — deep partial update of settings, including every boolean toggle
  • One POST per intent-bearing action — only for operations with side effects beyond writing settings
Note

The granularity rule. Named POST actions exist only for operations with side effects (Shopify mutations, variant fan-out, state transitions) or high-traffic narrow edits like set_button_text. Plain settings — and all boolean toggles such as badge.enabled or terms.enabled — are set via the capability's PATCH. The PATCH is deep-partial: fields you don't send are left alone. Each capability section below lists its toggleable field paths.

The tables below are sourced from the live /help manifest. Every capability is also exposed as MCP tools.

Widget

Storefront UI — badge, button text & colors, billing widget, disclaimer.

Path prefix: /preorders/offers/:id/widget

MethodActionPathDescription
GETread(root)Read the widget configuration for a preorder offer.
PATCHupdate(root)Deep partial update of any subset of widget configuration.
POSTset_badge_colorsset_badge_colorsSet the preorder badge's text and background colors.
POSTset_badge_textset_badge_textSet the preorder badge text.
POSTset_billing_widget_textset_billing_widget_textSet the billing widget's title and description (the PDP payment-breakdown block).
POSTset_button_colorsset_button_colorsSet the preorder button's text and background colors (implicitly enables custom colors).
POSTset_button_textset_button_textSet the preorder button's call-to-action label.
POSTset_disclaimer_styleset_disclaimer_styleSet the disclaimer banner's colors and border radius.
POSTset_disclaimer_textset_disclaimer_textSet the disclaimer banner text shown under the preorder button.

Toggles via PATCH .../widget: badge.enabled, disclaimer.enabled, button.colors.enabled, billing_widget.enabled. Clear a value by sending null.

PATCH /preorders/offers/:id/widget
{ "badge": { "enabled": false } }
Note

The billing-widget title and description are shared with the first payment option's copy (see payments/set_option_copy).

Inventory

Inventory provider, reservation timing, and the continue-selling (oversell) policy for newly attached variants.

Path prefix: /preorders/offers/:id/inventory

MethodActionPathDescription
GETread(root)Read the inventory configuration for a preorder offer.
PATCHupdate(root)Deep partial update of inventory settings.
POSTset_providerset_providerSet the inventory provider (stoq or shopify).
POSTset_reservation_timingset_reservation_timingSet when inventory is reserved (on_sale or on_fulfillment).

Toggles via PATCH .../inventory: continue_selling.enabled and continue_selling.auto_apply_to_new_variants — both map to the same underlying auto-flip-on-attach flag (newly attached variants get their Shopify inventory_policy flipped to CONTINUE). When both fields are present, auto_apply_to_new_variants wins.

PATCH /preorders/offers/:id/inventory
{ "continue_selling": { "enabled": true } }
Note

Continue-selling on the offer only governs future variant attachments — neither field flips already-attached variants. To flip existing variants, use products/bulk_toggle_inventory_policy, or pass update_inventory_policy: true to the offer's enable / disable lifecycle actions. Setting provider to shopify forces the products source to custom.

Shipping

Delivery date / window, shipping copy, fulfillment hold, split-order behavior.

Path prefix: /preorders/offers/:id/shipping

MethodActionPathDescription
GETread(root)Read shipping settings for a preorder offer.
PATCHupdate(root)Deep partial update of shipping settings.
POSTset_delivery_asapset_delivery_asapSet delivery to "as soon as possible" (no specific date or window).
POSTset_delivery_dateset_delivery_dateSet an exact delivery date for the preorder.
POSTset_delivery_windowset_delivery_windowSet a delivery window in days from checkout (e.g. "ships within 14 days").
POSTset_shipping_textset_shipping_textSet the customer-facing shipping text shown on the PDP.
POSTset_split_order_tagset_split_order_tagSet the tag applied to split orders on Shopify.
POSTset_split_transaction_gatewayset_split_transaction_gatewaySet the payment gateway used for the split-order transaction (e.g. "Store Credit").

Toggles via PATCH .../shipping:

Field pathEffect
fulfillment.holdHold (true) / release (false) fulfillment orders containing preorder items
display.show_shipping_timelinetrue shows the detailed PDP timeline; false the simplified text
fulfillment.split.enabledTurn order splitting on/off
fulfillment.split.hold_fulfillmentsHold the split order's fulfillments
fulfillment.split.sequential_numberGive split orders a sequential order name
PATCH /preorders/offers/:id/shipping
{ "fulfillment": { "hold": true, "split": { "enabled": true } } }

Payments

Payment modes (full / partial / both), deposit percentage, auto-collect, discounts, payment-option copy.

Path prefix: /preorders/offers/:id/payments

MethodActionPathDescription
GETread(root)Read the payment configuration for a preorder offer.
PATCHupdate(root)Deep partial update of payment settings.
POSTdisable_optiondisable_optionRemove a payment option (full or partial) from the offer.
POSTenable_optionenable_optionAdd a payment option (full or partial) to the offer.
POSTset_deposit_percentset_deposit_percentSet the deposit percentage charged at checkout on the partial payment option.
POSTset_discountset_discountSet the preorder discount.
POSTset_discount_textset_discount_textSet the discount blurb shown on the offer's payment options.
POSTset_modeset_modeSwitch the offer between full, partial, and full_and_partial payment modes.
POSTset_option_copyset_option_copySet the merchant-facing copy on a payment option (title, description, discount text).

Toggles via PATCH .../payments: remaining_balance.auto_collect, remaining_balance.auto_collect_on_fulfillment. Clear the discount via { "discount": { "type": "no_discount" } }.

PATCH /preorders/offers/:id/payments
{ "remaining_balance": { "auto_collect": false } }

Notes from the manifest:

  • set_deposit_percent — requires a partial payment option (mode partial or full_and_partial); use set_mode first. Percent must be 1–99 (100% upfront is full payment mode).
  • enable_option — idempotent; newly added options start from the dashboard defaults.
  • disable_option — only valid on full_and_partial offers; an offer must keep at least one payment option.
  • set_discounttype is one of percentage, price, fixed_amount, no_discount.
  • set_discount_text — pass option_type (full | partial) to target one option; omit to apply to every option. Supports the {{ discount }} placeholder.

Limits

Min/max per order, per-customer and total caps, remaining-units display.

Path prefix: /preorders/offers/:id/limits

MethodActionPathDescription
GETread(root)Read order-quantity limits for a preorder offer.
PATCHupdate(root)Deep partial update of quantity limits.
POSTset_max_per_customerset_max_per_customerSet the maximum quantity a single customer can preorder across all their orders.
POSTset_max_per_orderset_max_per_orderSet the maximum quantity a customer can preorder per order.
POSTset_min_per_orderset_min_per_orderSet the minimum quantity a customer must preorder per order.
POSTset_total_maxset_total_maxSet the total quantity that can be preordered across all customers.

Toggles and clears via PATCH .../limits: display.show_remaining (true/false) toggles the remaining-units display; clear a limit by sending nullper_customer.max: null removes the per-customer limit, total.max: null removes the total cap.

PATCH /preorders/offers/:id/limits
{ "display": { "show_remaining": true }, "total": { "max": null } }
Warning

per_customer.max and total.max are stored config only today — storefront enforcement of these limits is follow-up work and not live yet.

Checkout

Terms acceptance, order tags applied at checkout, mixed-cart policy.

Path prefix: /preorders/offers/:id/checkout

MethodActionPathDescription
GETread(root)Read checkout settings for a preorder offer.
PATCHupdate(root)Deep partial update of checkout settings.
POSTadd_order_tagadd_order_tagAdd a tag to the set applied to orders containing this offer.
POSTremove_order_tagremove_order_tagRemove a tag from the set applied to orders containing this offer.
POSTset_mixed_cart_error_messageset_mixed_cart_error_messageSet the error message shown when a blocked mixed cart reaches checkout.
POSTset_order_tagsset_order_tagsReplace the entire set of tags applied to orders containing this offer.
POSTset_terms_textset_terms_textSet the terms-acceptance text shown next to the checkbox.

Toggles via PATCH .../checkout: terms.enabled, terms.disable_button_until_acknowledged, terms.include_in_line_item_properties, mixed_cart.allowed.

PATCH /preorders/offers/:id/checkout
{ "terms": { "enabled": true }, "mixed_cart": { "allowed": false } }

Countdown

Countdown timer on the PDP — mode, style, copy, custom end date.

Path prefix: /preorders/offers/:id/countdown

MethodActionPathDescription
GETread(root)Read the countdown timer configuration for a preorder offer.
PATCHupdate(root)Deep partial update of countdown settings.
POSTset_custom_end_dateset_custom_end_dateSet the custom end date for the countdown timer.
POSTset_ends_textset_ends_textSet the text shown when the offer is closing.
POSTset_modeset_modeSet whether the countdown follows the offer's schedule (to_schedule_end) or a custom date (to_custom_date).
POSTset_starts_textset_starts_textSet the text shown before the offer has started.
POSTset_styleset_styleSet the countdown visual style (type, colors, border radius).
POSTset_unit_labelsset_unit_labelsSet the unit labels (Days/Hours/Mins/Secs).

Toggle via PATCH .../countdown: enabled (true/false) shows or hides the countdown.

PATCH /preorders/offers/:id/countdown
{ "enabled": true, "mode": "to_custom_date", "custom_end_date": "2026-07-01T00:00:00Z" }
Note

set_custom_end_date has no visible effect unless mode is to_custom_date. In the PATCH body, text is an alias for ends_text — both write the same field, and an explicit ends_text wins when both are sent.

Integrations

POS and B2B behavior. This capability is PATCH-only — there are no named actions.

Path prefix: /preorders/offers/:id/integrations

MethodActionPathDescription
GETread(root)Read integration settings (POS, B2B).
PATCHupdate(root)Deep partial update of integration settings.

Toggles via PATCH .../integrations: pos.enabled, pos.skip_inventory_check, b2b.enabled.

PATCH /preorders/offers/:id/integrations
{ "pos": { "enabled": false }, "b2b": { "enabled": true } }

Markets

Multi-market scoping — which Shopify markets the offer applies to.

Path prefix: /preorders/offers/:id/markets

MethodActionPathDescription
GETread(root)Read market scoping for a preorder offer.
PATCHupdate(root)Deep partial update of market scoping.
POSTadd_marketadd_marketAdd a market to the preorder offer's scope.
POSTremove_marketremove_marketRemove a market from the preorder offer's scope.
POSTset_marketsset_marketsReplace the entire set of markets a preorder offer applies to.

Toggle via PATCH .../markets: enabled (true/false) turns market-based scoping on or off. The offer applies to all markets when scoping is off, or when scoping is on with an empty market list:

PATCH /preorders/offers/:id/markets
{ "enabled": true, "market_ids": ["gid://shopify/Market/123"] }
  • All markets: { "enabled": false }, or { "enabled": true, "market_ids": [] }, or { "enabled": true, "applies_to_all_markets": true } (which also clears the list).
  • market_ids accepts Shopify GIDs or numeric IDs.
  • For incremental edits, keep using add_market / remove_market / set_markets.

Products

Variant attachment — source mode, add/remove variants, exclusions, inventory-policy bulk toggle, and per-variant settings.

Path prefix: /preorders/offers/:id/products

MethodActionPathDescription
GETread(root)Read the products configuration (source rule + variant summary).
PATCHupdate(root)Set the source rule plus its matching sub-block (source + one of all / collection / custom).
POSTadd_variantsadd_variantsAttach variants to a custom-source preorder offer.
POSTbulk_toggle_inventory_policybulk_toggle_inventory_policyFlip the Shopify inventory policy on variants attached to the offer (CONTINUE or DENY).
POSTremove_variantsremove_variantsRemove variants from a custom-source preorder offer.
POSTset_collectionset_collectionChange the collection driving a collection-sourced offer.
POSTset_excluded_variantsset_excluded_variantsReplace the explicit excluded-variant list for an all-source offer.
POSTset_exclusion_tagset_exclusion_tagSet the exclusion tag for an all-source offer (variants with this tag are excluded).
POSTset_source_to_allset_source_to_allSwitch the offer to apply to every variant in the shop, minus exclusions. Requires confirm: true.
POSTset_source_to_collectionset_source_to_collectionSwitch the offer to a collection-driven variant source.
POSTset_source_to_customset_source_to_customSwitch the offer to a custom variant list. Optionally seed with variant IDs.

Notes from the manifest:

  • PATCH .../products — delegates to the set_source_to_* actions; switching source resets the variant set. source: "all" requires confirm: true. Only the sub-block matching source may be provided.
  • add_variants / set_source_to_custom — variant attachment runs through the bulk-variant addition service asynchronously (202 + job_id).
  • bulk_toggle_inventory_policy — async; omit variant_ids to apply to all attached variants.
  • set_collection — collection-sourced offers only; returns 409 Conflict otherwise. Use set_source_to_collection to switch a non-collection offer.
  • set_source_to_collection — new variants added to the collection in Shopify are not auto-picked-up; call the action again to refresh.

Per-variant settings sub-resource

Variants attached to an offer carry per-offer overrides, addressed by Shopify variant ID:

MethodPathDescription
GET/preorders/offers/:id/products/variantsList the attached variants with their per-variant settings, paginated (page, per_page).
GET/preorders/offers/:id/products/variants/:variant_idRead the per-offer settings of one attached variant.
PATCH/preorders/offers/:id/products/variants/:variant_idSet per-offer overrides on the variant — shipping_text, max_count, market_overrides.
PATCH /preorders/offers/:id/products/variants/:variant_id
{ "shipping_text": "Ships in August", "max_count": 50 }

Sending null clears an override; the variant falls back to the offer-level value. market_overrides writes the per-market metafields (market_shipping_text, market_preorder_max_count) keyed by Shopify market GID.

Advanced

Line-item-property customisation, button-text overrides, custom CSS, and Shopify selling-plan-group attachment.

Path prefix: /preorders/offers/:id/advanced

MethodActionPathDescription
GETread(root)Read power-user settings (line item properties, button-text overrides, Shopify selling plan attachment, custom CSS).
PATCHupdate(root)Deep partial update of advanced settings.
POSTattach_to_shopify_selling_planattach_to_shopify_selling_planRe-attach the offer to a Shopify selling plan group (resume syncing).
POSTdetach_from_shopify_selling_plandetach_from_shopify_selling_planDetach the offer from Shopify selling plan groups; Stoq continues to manage it via the storefront integration.
POSTset_button_text_overrideset_button_text_overrideOverride the widget button text for one state (before_launch, after_launch, or out_of_stock).
POSTset_custom_cssset_custom_cssSet custom CSS overrides for this offer's storefront widget. Send an empty string to clear.
POSTset_custom_line_item_propertyset_custom_line_item_propertySet a free-text custom line item property added to every preorder cart line.

Toggles and clears via PATCH .../advanced:

  • Line-item-property toggles: line_item_properties.include_shipping_text, .include_payment_breakdown, .include_acknowledgement (true/false each).
  • button_text_overrides is deep-partial per state — { "button_text_overrides": { "out_of_stock": null } } clears that one override (the read shape still emits all three states, with null for unset).
  • custom_css is cleared with an empty string or null.
PATCH /preorders/offers/:id/advanced
{ "line_item_properties": { "include_payment_breakdown": false } }
Warning

detach_from_shopify_selling_plan is strongly discouraged for most merchants — it breaks Shopify-native integrations like checkout selling-plan display and third-party subscription apps. It does not delete the existing Shopify selling plan group; it just stops syncing.

Translations

Per-locale overrides for offer copy fields. No PATCH — translations are keyed writes, not a settings document.

Path prefix: /preorders/offers/:id/translations

MethodActionPathDescription
GETread(root)Read every translation override, plus the full enumeration of translatable field paths.
POSTclear_localeclear_localeRemove all translation overrides for one locale.
POSTsetsetSet a single translation override (one locale, one field).
POSTset_manyset_manySet many translation overrides for one locale, atomically — invalid paths abort the whole write.
POSTunsetunsetRemove a translation override (one locale, one field).
Note

The read endpoint is also the source of truth for the catalog of translatable field paths — clients shouldn't hardcode this list, they should fetch and use it.