Reports
Back-in-stock analytics — the same numbers as the Back in Stock Overview and Reports pages, as JSON.
BetaAPI v2 is in public beta: endpoints, fields and behaviour can change before general availability. See the changelog
Last updated
The back-in-stock reports resource returns the numbers the merchant sees on the Back in Stock Overview and the Reports > Back in stock pages, like the preorder reports. Each report is a JSON read; reads run against read replicas. There is no CSV export in the API.
Path prefix: /back_in_stock/reports, under the base URL https://app.stoqapp.com/api/v2/external.
Report manifest
Section titled “Report manifest”GET /back_in_stock/reportsReturns the catalog of available reports — { "reports": [{ "name", "description", "aliases", "url" }] } — generated from the live registry so it can’t drift from the actual report actions.
Shared filters
Section titled “Shared filters”| Param | Type | Notes |
|---|---|---|
from, to |
ISO 8601 date or timestamp | Window — defaults to the last 30 days. A bare date is that whole day in the shop’s time zone |
range |
all_time |
The dashboard’s All time, instead of from/to |
Each report takes only the filters its dashboard view has; they are listed with the report. Shopify ids in requests and responses are shopify_*_id, a gid string in responses. Every response echoes the resolved window at the top: "window": { "from": "...", "to": "..." }, or null for range=all_time.
Where the numbers come from
Section titled “Where the numbers come from”Every report calls the same service as the dashboard view it names, so the numbers match the dashboard. summary is summed from the shop’s daily totals, as the Overview tiles are (all time reads the lifetime totals, as the Home card does). The charts (signups, notifications, conversions) count live, as the Overview charts do: the bucket size is daily up to 60 days, weekly up to 180 days, then monthly (interval in the response), and buckets are UTC days, weeks and months, as on the charts. date is the bucket’s first day.
| Method | Path | Dashboard view |
|---|---|---|
GET |
/back_in_stock/reports/summary |
Overview tiles |
GET |
/back_in_stock/reports/signups |
Overview signups chart |
GET |
/back_in_stock/reports/notifications |
Overview notifications chart |
GET |
/back_in_stock/reports/conversions |
Overview orders chart |
GET |
/back_in_stock/reports/products_in_demand |
Reports > Products in demand table |
GET |
/back_in_stock/reports/product_revenue |
Reports > Revenue table |
GET |
/back_in_stock/reports/wait_duration |
The wait-time chart: median, longest, histogram |
GET |
/back_in_stock/reports/engagement |
Reports > Engagement |
Summary
Section titled “Summary”The Back in stock Overview tiles, and the same totals as the Home analytics card. Shop-wide only: send from/to or range=all_time. A window is summed from the shop’s daily totals; range=all_time reads revenue, orders, signups, emails_sent and sms_sent from the shop’s lifetime totals, as Home’s All time does. For people still waiting use products_in_demand.
{ "window": { "from": "...", "to": "..." }, "currency": "USD", "totals": { "revenue": "4812.50", "orders": 96, "average_order_value": "50.13", "unique_customers": 81, "signups": 420, "notifications_sent": 461, "emails_sent": 410, "sms_sent": 51 }}revenue,orders: orders attributed to an alert at medium or high confidence, and their value.unique_customers: the dashboard’s buyers tile, summed over the days.signups: every signup created; a shopper signed up by email and SMS counts twice, as on the tile.sms_sent: every back-in-stock SMS sent, delivered or not, the count plan usage bills.
Signups
Section titled “Signups”The Overview signups chart: signups created per bucket.
{ "window": { "...": "..." }, "interval": "daily", "series": [ { "date": "2026-06-01", "signups": 24 } ]}Notifications
Section titled “Notifications”The Overview notifications chart: emails and delivered SMS sent per bucket, and the orders attributed to alerts.
{ "window": { "...": "..." }, "interval": "daily", "series": [ { "date": "2026-06-01", "notifications_sent": 115, "emails_sent": 101, "sms_sent": 14, "orders": 3 } ]}notifications_sent is emails_sent plus sms_sent.
Conversions
Section titled “Conversions”The Overview orders chart: orders attributed to an alert at medium or high confidence, and their revenue.
{ "window": { "...": "..." }, "interval": "daily", "currency": "USD", "series": [ { "date": "2026-06-01", "orders": 8, "revenue": "401.00" } ]}Products in demand
Section titled “Products in demand”The Products in demand table: variants (or products) ranked by demand — the answer to “what should I restock first?”. total is signups created in the window. pending is how many of them have not been notified yet. A row appears when it has a signup in the window; send range=all_time for everyone waiting now. Deleted variants are left out when the shop has the dashboard set to hide them.
| Param | Notes |
|---|---|
group_by |
variant (default) / product |
sort_by |
pending (default) / total / last_requested_at |
direction |
desc (default) / asc |
count_by |
customers / signups; omitted, the dashboard default. The response echoes it |
search |
Product title or SKU, as the dashboard search box |
vendors |
Comma-separated vendor names |
tags |
Comma-separated product tags, as the dashboard’s Tag filter |
shopify_market_ids |
Comma-separated, each numeric or gid://shopify/Market/…, as the dashboard’s market filter |
include_inventory |
true adds inventory_available to variant rows, the table’s Inventory column. Asks Shopify once per page |
include_prices |
true adds price and compare_at_price to variant rows, the table’s Price and Compare at columns. Asks Shopify once per page |
page, per_page |
per_page default 25, max 500 |
{ "window": { "...": "..." }, "group_by": "variant", "sort_by": "pending", "direction": "desc", "count_by": "customers", "rows": [ { "shopify_variant_id": "gid://shopify/ProductVariant/123", "shopify_product_id": "gid://shopify/Product/456", "variant_title": "Small / Blue", "product_title": "Classic Tee", "sku": "TEE-S-BLU", "image_url": "https://cdn.shopify.com/s/files/tee-blue.jpg", "deleted": false, "variants_count": 6, "inventory_available": 0, "price": "25.00", "compare_at_price": "30.00", "pending": 42, "total": 65, "last_requested_at": "2026-06-09T08:30:00Z" } ], "meta": { "total_count": 1, "page": 1, "per_page": 25, "total_pages": 1 }}With group_by=product, rows have shopify_product_id, product_title, image_url and variants_count, and no variant fields; include_inventory and include_prices add nothing to them. deleted is the dashboard’s “(Deleted)” label: on a product row, every variant of the product is deleted. image_url is the variant’s image, else the product’s.
inventory_available is the stock available in the locations the shop’s market or location filter allows, summed, as the Inventory column shows it; it is null when Shopify has no level for the variant. price and compare_at_price are strings in the shop’s currency, null when Shopify has none. last_requested_at is the latest signup in the window.
With count_by=signups, every signup counts, so a shopper signed up for one variant by email and SMS counts twice. With count_by=customers, a signup is one person waiting on one variant: the same shopper signing up for the same variant by email and by SMS counts once, and the same shopper signing up for two sizes counts twice.
Wait duration
Section titled “Wait duration”| Param | Notes |
|---|---|
shopify_variant_id, shopify_product_id |
gid or numeric; one variant or product, as the dashboard’s wait-time chart |
shopify_market_ids |
Comma-separated, each numeric or gid://shopify/Market/…, as the waitlist page’s Markets filter |
Returns median_wait_days, max_wait_days, interval and distribution (paid plans only; distribution_included_in_plan says which). For how many are waiting, use products_in_demand.
Example: signups over the last 90 days
Section titled “Example: signups over the last 90 days”curl 'https://app.stoqapp.com/api/v2/external/back_in_stock/reports/signups?from=2026-03-01&to=2026-06-01' \ -H "X-Auth-Token: $STOQ_API_KEY"The 92-day window returns weekly buckets, as the dashboard chart does.
Thanks for letting us know.
Still stuck? Ask Quinn or chat with support