Variant availability (beta)
Beta. The response may gain keys and status values; ignore what you do not recognise.
Answers, for up to 100 Shopify variants and one buyer country, whether a preorder offer applies, how many units are left, and what shipping text the shopper sees. You pass the country and never deal with Shopify Markets, offer scopes or metafields.
GET /api/v2/external/preorders/product_variants/availability?country=DE&variant_ids[]=44556677&variant_ids[]=44556678Request
| Parameter | Required | Notes |
|---|---|---|
country | yes | ISO 3166-1 alpha-2 (DE, us). The buyer's country: use the same value you pass to the Storefront API's @inContext(country:). |
variant_ids[] | yes | 1 to 100 Shopify variant ids, numeric or as gid://shopify/ProductVariant/…. Also accepted as one comma-separated value. |
A GET costs 1 rate-limit point whatever the number of ids.
Response
{
"country": "DE",
"product_variants": [
{
"variant_id": 44556677,
"enabled": true,
"status": "active",
"preorder_type": "out_of_stock",
"limit": { "max_units": 100, "units_remaining": 63 },
"shipping": {
"text": "Ships 01 Dec 2026",
"delivery": { "type": "on_date", "date": "2026-12-01T00:00:00+01:00", "days_after_checkout": null }
},
"preorder": { "id": "6f1c0c0e-2f0a-4c57-9d0f-6a1d5a3a1b11", "schedule": { "start_date": null, "end_date": "2026-11-15T23:59:00+01:00" } }
},
{
"variant_id": 44556678,
"enabled": false,
"status": "not_enrolled",
"preorder_type": null,
"limit": null,
"shipping": null,
"preorder": null
}
],
"errors": []
}One entry per distinct valid id, in the order you sent them. Every key is always present.
| Key | Type | Meaning |
|---|---|---|
enabled | boolean | true when a preorder offer applies to this variant in this country and still has allowance. It does not mean "in stock": see preorder_type. |
status | string | Why. active, sold_out, scheduled, paused, ended, not_in_country, not_enrolled. |
preorder_type | string or null | out_of_stock or in_stock: the inventory condition under which the variant sells as a preorder. Only set while an offer applies. |
limit | object or null | max_units and units_remaining (never below 0). null when no limit applies: the offer is unlimited, or no offer applies. |
shipping | object or null | text is the sentence the shopper sees, already rendered, with any per-variant override applied; null when the merchant configured none. delivery is the structured promise behind it, or null when the text is free-form. Only set while an offer applies. |
shipping.delivery.type | string | asap, on_date (see date), within_days (see days_after_checkout), unknown. |
preorder | object or null | The preorder offer the status refers to: the one that applies, or the scheduled, paused or ended one that explains the status. schedule.start_date and schedule.end_date are the offer's schedule, the same values and names as the schedule block on GET /preorders/product_variants/:variant_id: set only while the offer has a schedule, ISO 8601 with the store's timezone offset, null otherwise. null for not_enrolled and not_in_country. |
errors | array | One entry per malformed id: { "variant_id": "abc", "error": "not a Shopify variant id" }. Malformed ids never fail the call. |
status
status | enabled | Meaning |
|---|---|---|
active | true | An offer applies and has allowance left |
sold_out | false | An offer applies but its limit is reached |
scheduled | false | An offer is set to open later; see preorder.schedule.start_date |
paused | false | The merchant has disabled the offer |
ended | false | The offer is past its end date |
not_in_country | false | The variant's offers are restricted to other markets |
not_enrolled | false | The variant is on no offer, is unknown to STOQ, or was deleted in Shopify |
When several offers cover a variant in the country, the one that applies is chosen the way the storefront chooses it: an offer restricted to the buyer's market outranks an unrestricted one. If the offer that applies is sold out, the result is sold_out even when another offer still has allowance; the storefront does not fall through to it either. An offer that is scheduled, paused or ended never blocks another offer. When no offer applies, status follows a fixed priority: scheduled, then paused, then ended, then not_in_country, then not_enrolled. Only one status is ever returned.
Treat an unknown status value as enabled: false and ignore keys you do not recognise; both may be added without notice.
Purchasable right now
STOQ does not hold live inventory, so enabled is half of the answer. Check the Storefront API for the same country:
preorder_type | Preorder while | Storefront check |
|---|---|---|
out_of_stock | the variant is out of stock and "Continue selling when out of stock" is on | availableForSale && currentlyNotInStock |
in_stock | the variant has stock | availableForSale && !currentlyNotInStock; quantityAvailable caps what is left |
Purchasable as a preorder = enabled and the check for preorder_type.
Allowance
Units are counted when the order is created, regardless of payment status, so unpaid, deposit and fully paid orders count the same. Allowance is restored when the order is cancelled, including a cancelled split preorder order, but not by a refund, and restocking makes no difference. units_remaining is read from STOQ's database and is current as of the last processed order webhook, normally seconds after the order event. For an offer restricted to specific markets the count is cached for up to a minute.
A limit is shared across every market an offer is restricted to; it is not enforced per market. Two offers on the same variant keep separate limits.
Errors
| Case | Status |
|---|---|
country missing or not a two-letter code | 422 |
No variant_ids, or more than 100 | 422 |
| A malformed id among valid ones | 200, listed in errors |
| Unknown or deleted variant | 200, status: "not_enrolled" |
Change detection
There are no webhooks for availability. Re-read this endpoint for the variants on screen, and on a timer for the variants you track. The Shopify Flow triggers "Preorder offer enabled" and "Preorder offer disabled" fire when an offer is switched on or off, including scheduled openings and closes.

