Offer
The preorder offer (selling plan) resource: CRUD, lifecycle, schedule, discard/restore.
BetaAPI v2 is in public beta: endpoints, fields and behaviour can change before general availability. See the changelog
Last updated
A preorder offer is the top-level entity merchants configure. It carries everything from deposit configuration to widget copy, and attaches to a set of product variants. v2 splits the surface into:
- CRUD — list / read / create / update / discard / restore / duplicate.
- Lifecycle — enable / disable / schedule / unschedule.
- Capabilities — twelve sub-groups for each configuration concern. See Offer capabilities.
Path prefix: /preorders/offers
List offers
Section titled “List offers”GET /preorders/offersReturns paginated offers in the shop, newest first. The response key is offers:
{ "offers": [ { "id": "uuid", "name": "Spring Drop", "...": "..." } ], "summary": { "total": 12, "live": 7, "scheduled": 1, "off": 4 }, "meta": { "total_count": 12, "page": 1, "per_page": 25, "total_pages": 1 }}| Param | Type | Default |
|---|---|---|
page |
integer | 1 |
per_page |
integer | 25 |
search |
string | Matches offer name, internal name, or an attached product’s title |
status |
all / live / scheduled / off / deleted |
all |
shopify_market_ids |
array of Shopify Market GIDs (numeric ids also accepted) | |
sort |
created_at desc / created_at asc / internal_name asc / internal_name desc / preorder_revenue desc / preorder_revenue asc |
created_at desc |
expand |
comma-separated or array: inventory, shipping, payments, markets, products |
none |
expand adds those capability blocks to each row, in the same shape as the capability’s own read (for example GET /preorders/offers/:id/shipping). Use it to read a page of offers with their settings in one call. The products block has the collection id but not its name; read GET /preorders/offers/:id/products for the name.
status=deleted lists the deleted offers, the Deleted offer group of the Reports orders filter; every other value, all included, leaves them out. Pass their ids to the orders list’s offer_id.
summary counts every offer that matches the filters, not only this page, by its current_status (live, scheduled, off; with status=deleted, total and deleted).
Aliases: “list offers”, “show all offers”, “preorder offers”, “all preorders”
Read an offer
Section titled “Read an offer”GET /preorders/offers/:idReturns the full offer including a capabilities block summarizing every capability’s current state.
Create an offer
Section titled “Create an offer”POST /preorders/offers| Body field | Required | Notes |
|---|---|---|
name |
no | Merchant-facing name (defaults to “Preorder”) |
internal_name |
no | Slug/reference (defaults to name) |
Capability settings are configured after creation via their respective capability actions — there is intentionally no kitchen-sink create body.
Returns: 202 Accepted with the new offer (like every v2 write — see Errors & Responses).
Update top-level fields
Section titled “Update top-level fields”PATCH /preorders/offers/:idFor only the fields not owned by a capability — name and internal_name. Deep partial: absent fields are unchanged; name cannot be blank; internal_name: null restores the default label (“Preorder N”). Capability keys and read-only fields return 422.
Aliases: “rename offer”, “change offer name”, “rename preorder”, “change internal name”, “relabel offer”, “edit offer”
Notes: everything else lives on a capability. Settings and toggles go through the capability’s PATCH; side-effectful operations have named POST actions. See Offer capabilities.
Discard (soft-delete)
Section titled “Discard (soft-delete)”POST /preorders/offers/:id/discardAliases: “delete”, “remove”, “archive”, “trash”, “soft delete”
Notes: The dashboard’s Archive: the offer is turned off, its schedule removed and its variants reset on Shopify before it is discarded. If Shopify refuses, the response is 502 and nothing changes. Recoverable indefinitely via restore.
Restore
Section titled “Restore”POST /preorders/offers/:id/restoreAliases: “undelete”, “undiscard”, “undo delete”, “bring back” Notes: The offer comes back off with no schedule. Variant attachments are not restored. Re-attach via the Products capability.
Duplicate
Section titled “Duplicate”POST /preorders/offers/:id/duplicateAliases: “copy offer”, “clone offer”, “duplicate preorder”, “copy preorder”
Notes: The dashboard’s Duplicate. Returns 202 with the new offer, in the same shape as GET /preorders/offers/:id. The copy keeps every setting, payment option and batch, is named “<internal_name> (Copy)”, and starts off with no products, no schedule and no automatic hold release. A ship or balance date already in the past is reset.
Lifecycle
Section titled “Lifecycle”The lifecycle actions are intent-bearing wrappers around state changes that have side effects on inventory policy and Shopify selling-plan-group sync.
Enable
Section titled “Enable”POST /preorders/offers/:id/enable| Body field | Type | Default | Notes |
|---|---|---|---|
update_inventory_policy |
boolean | false | If true, flips attached variants’ inventory_policy to CONTINUE |
shopify_variant_ids |
array | all attached | Restrict the inventory-policy flip to these Shopify variant gids |
Aliases: “turn on”, “activate”, “launch”, “go live”, “start offer”
Notes: Variants are left at their existing inventory policy unless update_inventory_policy: true is passed. On a scheduled offer, enable starts it now, as the dashboard does: the start date is cleared, an end date is kept, and with no end date the schedule is removed.
Disable (pause)
Section titled “Disable (pause)”POST /preorders/offers/:id/disable| Body field | Type | Default | Notes |
|---|---|---|---|
update_inventory_policy |
boolean | false | If true, flips attached variants’ inventory_policy back to DENY |
shopify_variant_ids |
array | all attached | Restrict the inventory-policy flip to these Shopify variant gids |
Aliases: “pause”, “turn off”, “deactivate”, “stop offer”, “end preorder”, “disable and stop overselling”, “close out preorder”
Notes: On a scheduled or dated offer, disable also removes the schedule, as the dashboard does, so the offer stays off instead of starting on its start date.
Schedule
Section titled “Schedule”POST /preorders/offers/:id/schedule| Body field | Type | Notes |
|---|---|---|
start |
Shop-local time, e.g. 2026-09-30T18:00 (no Z or offset) |
Optional |
end |
Shop-local time | Optional |
Aliases: “set schedule”, “schedule launch”, “set start date”, “set end date”, “schedule offer”
Notes: Like the editor: start only, or a window, turns the offer off until the start; end only turns it on until the end. Changing the kind of schedule turns the countdown off, reported in also_changed.
Unschedule
Section titled “Unschedule”POST /preorders/offers/:id/unscheduleAliases: “clear schedule”, “remove schedule”, “no schedule”, “unschedule offer”
Removes the schedule. A live offer stays on; any other stays off.
Bulk enable / disable
Section titled “Bulk enable / disable”POST /preorders/offers/bulk_enablePOST /preorders/offers/bulk_disable| Body field | Type | Default | Notes |
|---|---|---|---|
ids |
array of offer ids | required | The offers to turn on (or off) |
update_inventory_policy |
boolean | false | bulk_enable: flips the attached variants to CONTINUE. bulk_disable: flips them to DENY |
Aliases: “bulk enable offers”, “turn on offers”, “bulk disable offers”, “turn off offers”
Notes: The Offers list’s bulk Enable / Disable. Each offer changes as the single enable / disable does (a scheduled offer starts now; disabling removes the schedule). The inventory policy flip applies to offers that use STOQ inventory; an offer with more than 250 variants is flipped in the background. An unknown id, another shop’s offer or a deleted offer returns 422 under errors.ids and nothing changes. An offer that cannot change (for example the plan’s offer limit) is counted in failed with its reason in failed_errors; the others still change. Returns 202:
{ "total": 2, "updated": 2, "inventory_updates_initiated": 1, "offers": [{ "id": "…", "name": "…", "current_status": "live", "…": "…" }] }Capability surface
Section titled “Capability surface”Every other action on an offer is grouped under one of twelve capabilities — see Offer capabilities for the full tables. Each capability has:
- a
Readaction (GET the capability’s current state) - an
Updateaction (PATCH, deep partial) — the home of all settings and boolean toggles - named
POSTactions only where an operation has side effects beyond writing settings
(Translations is the one exception: it has no PATCH — translation writes are keyed set / unset / set_many actions.)
Thanks for letting us know.
Still stuck? Ask Quinn or chat with support