Retrieve products in demand
API v2 is in public beta: endpoints and fields can change before general availability. See the changelog
/back_in_stock/reports/products_in_demandCosts 1 rate-limit point · Rate limits
The Products in demand table: variants (or products) ranked by back-in-stock demand, with signups created in the window, how many of them are still waiting, and the last request.
The same rows as the dashboard table. total counts signups created in the window; pending counts those of them not yet notified. count_by=customers counts a shopper signed up on several channels once; omitted, it follows the dashboard default, and the response's count_by says which. group_by=product ranks products instead of variants. search matches product title or SKU; vendors, tags and shopify_market_ids are comma-separated lists, as the table's filters. Deleted variants are hidden when the shop's dashboard hides them. image_url is the variant's image, else the product's. Variant rows only: include_inventory=true adds inventory_available, the stock available in the locations the shop's market or location filter allows (summed, null when Shopify has no level), and include_prices=true adds price and compare_at_price in the shop's currency, as the table's Inventory and Price columns. Each asks Shopify once per page. include_totals=true adds totals { pending, total }, the pending and total columns summed over every row the filters keep, not just this page.
Also searched asdemand reportwhat should I restockmost wanted productstop requested variantsproducts in demandrestock priorities
Query parameters
group_bystringOne ofvariantproductsort_bystringOne ofpendingtotallast_requested_atdirectionstringOne ofascdesccount_bystringOne ofcustomerssignupsfromstringtostringrangestringshopify_market_idsarraysearchstringvendorsstringtagsstringpagestringper_pagestringinclude_inventorystringinclude_pricesstringinclude_totalsstring
Returns
windowobjectShow 2 child attributesHide child attributes
fromstringExample:2026-05-26T00:00:00ZtostringExample:2026-06-25T23:59:59Z
group_bystringExample:variantsort_bystringExample:pendingdirectionstringExample:desccount_bystringExample:customersrowsarray of objectsShow 8 child attributesHide child attributes
shopify_variant_idstringExample:gid://shopify/ProductVariant/47284734423096shopify_product_idstringExample:gid://shopify/Product/8784906035384variant_titlestringExample:Blue / Mediumproduct_titlestringExample:Classic SneakerskustringExample:CS-BLU-MpendingintegerExample:47totalintegerExample:89last_requested_atstringExample:2026-06-25T11:30:00Z
metaobjectShow 4 child attributesHide child attributes
total_countintegerExample:287pageintegerExample:1per_pageintegerExample:50total_pagesintegerExample:6
Errors
Missing or invalid X-Auth-Token.
The request failed validation.
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 "https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand" \
-H "X-Auth-Token: $STOQ_API_KEY"const res = await fetch("https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand", {
headers: {
"X-Auth-Token": process.env.STOQ_API_KEY,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand",
headers={"X-Auth-Token": os.environ["STOQ_API_KEY"]},
)
data = res.json()require "net/http"
require "json"
uri = URI("https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand")
req = Net::HTTP::Get.new(uri, "X-Auth-Token" => ENV["STOQ_API_KEY"])
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)curl "https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand?group_by=variant&sort_by=pending&direction=asc" \
-H "X-Auth-Token: $STOQ_API_KEY"const res = await fetch("https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand?group_by=variant&sort_by=pending&direction=asc", {
headers: {
"X-Auth-Token": process.env.STOQ_API_KEY,
},
});
const data = await res.json();import os
import requests
res = requests.get(
"https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand?group_by=variant&sort_by=pending&direction=asc",
headers={"X-Auth-Token": os.environ["STOQ_API_KEY"]},
)
data = res.json()require "net/http"
require "json"
uri = URI("https://app.stoqapp.com/api/v2/external/back_in_stock/reports/products_in_demand?group_by=variant&sort_by=pending&direction=asc")
req = Net::HTTP::Get.new(uri, "X-Auth-Token" => ENV["STOQ_API_KEY"])
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body){
"window": {
"from": "2026-05-26T00:00:00Z",
"to": "2026-06-25T23:59:59Z"
},
"group_by": "variant",
"sort_by": "pending",
"direction": "desc",
"count_by": "customers",
"rows": [
{
"shopify_variant_id": "gid://shopify/ProductVariant/47284734423096",
"shopify_product_id": "gid://shopify/Product/8784906035384",
"variant_title": "Blue / Medium",
"product_title": "Classic Sneaker",
"sku": "CS-BLU-M",
"pending": 47,
"total": 89,
"last_requested_at": "2026-06-25T11:30:00Z"
},
{
"shopify_variant_id": "gid://shopify/ProductVariant/47284734455864",
"shopify_product_id": "gid://shopify/Product/8784906035384",
"variant_title": "Red / Large",
"product_title": "Classic Sneaker",
"sku": "CS-RED-L",
"pending": 23,
"total": 56,
"last_requested_at": "2026-06-25T09:15:00Z"
}
],
"meta": {
"total_count": 287,
"page": 1,
"per_page": 50,
"total_pages": 6
}
}{
"errors": [
"Invalid API key"
],
"code": "auth_invalid",
"details": [
{
"code": "auth_invalid",
"message": "Invalid API key",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"name is required"
],
"code": "validation_failed",
"details": [
{
"code": "validation_failed",
"message": "name is required",
"path": null,
"value": null,
"expected": null
}
]
}{
"errors": [
"Rate limit exceeded"
],
"code": "rate_limited",
"details": [
{
"code": "rate_limited",
"message": "Rate limit exceeded",
"path": null,
"value": null,
"expected": null
}
]
}