Download OpenAPI specification:
Official OpenAPI specification for the Avia Dashboard API.
Use this API to fetch dashboard data for one or all stores using Avia.
Authentication:
All API tokens are generated and obtained through the Shopify app. Do not use
this API to obtain or manage tokens; use the Avia app installed in your
Shopify store to generate and manage your API key. Send the API key in the
X-API-Key header on each request.
Rate limit: The current version of the API has a rate limit of 1 request per hour per client. Plan your integrations accordingly.
Response formats:
Claude / MCP access:
Every endpoint above (except /health/) is also exposed as an MCP (Model Context
Protocol) tool, so you can ask an LLM like Claude natural-language questions about
your dashboard data instead of calling this API directly. The MCP server is hosted
at https://mcp.avia-app.cloud/mcp and forwards your X-API-Key
unmodified to this API — it stores no credentials itself. Connect with the Claude
Code CLI:
claude mcp add --transport http avia-mcp https://mcp.avia-app.cloud/mcp \
-H "X-API-Key: <your Avia dashboard API key>" \
-H "X-Shopify-Domain: <your-shop>.myshopify.com"
The X-Shopify-Domain header is an optional default so you don't have to repeat your
shop domain in every question; omit it to specify shopify_domain per request instead.
For Claude Desktop or other MCP clients without custom-header support on remote
connections, use the mcp-remote bridge — see
github.com/Retailogists/avia-api-mcp for setup details and the full tool list.
Returns key dashboard metrics for this store only (same shape as all-stores summary). Traffic and session metrics from BigQuery; CVR, AOV, and revenue per visitor from ShopifyQL. Defaults to yesterday when startDate and endDate are omitted.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when the store was open. The time range spans from the earliest opening hour to the latest closing hour across all days of the week (e.g., if open 9am-7pm Mon-Fri and 8am-3pm weekends, the range will be 8am-7pm). |
{- "uniqueVisitors": 0,
- "total_visitors": 0,
- "dwellTimeSeconds": 0,
- "averageDailyTraffic": 0,
- "startDate": "string",
- "endDate": "string",
- "cvr_unique": 0,
- "cvr_total": 0,
- "revenue_per_visitor_unique": 0,
- "revenue_per_visitor_total": 0,
- "aov": 0,
- "totalSales": 0,
- "totalOrders": 0,
- "operatingHours": {
- "property1": 0,
- "property2": 0
}, - "storeTimezone": "string"
}Return the full dashboard payload for a single store location.
Includes demographics, heatmaps, opportunity-loss table, anomalies, and forecasts. Same data shape as the all-stores dashboard, filtered to this location. Defaults to yesterday when dates are omitted.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when the store was open. The time range spans from the earliest opening hour to the latest closing hour across all days of the week (e.g., if open 9am-7pm Mon-Fri and 8am-3pm weekends, the range will be 8am-7pm). | |
string or null Comparison period type. "dod" compares current period data to the previous day, "wow" compares to the previous week. Defaults to "wow". |
{- "gender": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "age": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "ageByGender": [
- { }
], - "periodConversionRate": 0,
- "visitorsPerRevenue": 0,
- "cvr": 0,
- "dailyTraffic": [
- {
- "date": "string",
- "traffic": 0
}
], - "heatmap": [
- {
- "hour": 0,
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "dailyAverages": {
- "visits": 0,
- "orders": 0,
- "sales": 0
}, - "heatmapDailyTotals": [
- {
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "locations": [
- "string"
], - "startDate": "string",
- "endDate": "string",
- "applyOperatingHours": true,
- "forecastResult": [ ],
- "forecastUpliftResult": [ ],
- "dwellTimeSeconds": 0,
- "uniqueVisitors": 0,
- "anomaliesVisitsHourly": [ ],
- "anomaliesVisits4h": [ ],
- "anomaliesCvrHourly": [ ],
- "anomaliesCvr4h": [ ],
- "opportunityLossData": [ ],
- "comparisonPeriod": "string",
- "comparisonWeightedTotals": { },
- "extraDevices": [ ]
}Returns the list of registered devices for the specified store.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
{- "devices": [
- {
- "id": 0,
- "serial_number": "string",
- "status": "string",
- "device_type": "string",
- "name": "string",
- "created_at": "string",
- "updated_at": "string"
}
]
}Same as all-stores GET /api/{shopify_domain}/visits with locationId set: three parallel
BigQuery series (dup uniques, dup row counts, normalized in_count), merged dailyUnique and
dailyTraffic as sorted [{date, traffic}, ...].
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null Default: "true" If true, filters results to only include hours when the store was open. |
{- "dailyUnique": [
- {
- "date": "string",
- "traffic": 0
}
], - "dailyTraffic": [
- {
- "date": "string",
- "traffic": 0
}
], - "startDate": "string",
- "endDate": "string",
- "locationId": "string",
- "applyOperatingHours": true
}Predicts the rolling 14-day forecasted traffic per hour per store starting with today's date. Operating hours are always applied automatically; data is filtered to only include hours when the store is open.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
{- "traffic_forecast_hourly": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "traffic_forecast_4h": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "insight": { },
- "accuracy": 100
}Returns detected visit anomalies with hourly and 4-hour bucket groupings for the specified store. Each anomaly includes the anomaly value (integer) and type ('positive' or 'negative').
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when the store was open. The time range spans from the earliest opening hour to the latest closing hour across all days of the week (e.g., if open 9am-7pm Mon-Fri and 8am-3pm weekends, the range will be 8am-7pm). |
{- "anomalies_visits_hourly": {
- "property1": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}, - "property2": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}
}, - "anomalies_visits_4h": {
- "property1": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}, - "property2": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}
}
}Returns detected conversion rate (CVR) anomalies with hourly and 4-hour bucket groupings for the specified store. CVR is expressed as a percentage. Each anomaly includes the anomaly value (CVR percentage as integer) and type ('positive' or 'negative').
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when the store was open. The time range spans from the earliest opening hour to the latest closing hour across all days of the week (e.g., if open 9am-7pm Mon-Fri and 8am-3pm weekends, the range will be 8am-7pm). |
{- "anomalies_cvr_hourly": {
- "property1": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}, - "property2": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}
}, - "anomalies_cvr_4h": {
- "property1": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}, - "property2": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}
}
}Returns stockout alerts for a location: top products and variants with inventory and 14-day demand projections. Response includes success, shop, serverTime, received (locationId), averageCvr14d, cvr14dDetails, dailyCvr14d, dailyTraffic14d, forecastDailyVisits14d, expectedOrdersByDate14d, expectedProductOrdersByDate14dByProductId, expectedUnitsDemandByDate14dByProductId, stockoutProjectionByProductId, totalUnitsSoldAllVariants14d, topVariants, and topProducts. See StockoutAlertsResponseSchema for the full response shape.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| shopify_location_id required | integer Shopify location ID for the store. |
string or null Start date (YYYY-MM-DD). | |
string or null End date (YYYY-MM-DD). | |
string or null If true, filters results to only include hours when the store was open. |
{- "success": true,
- "shop": "string",
- "serverTime": "string",
- "received": {
- "property1": "string",
- "property2": "string"
}, - "averageCvr14d": 0,
- "cvr14dDetails": {
- "startDate": "string",
- "endDate": "string",
- "traffic": 0,
- "orders": 0,
- "operatingHours": { },
- "timezone": "string",
- "applyOperatingHours": true
}, - "dailyCvr14d": [
- { }
], - "dailyTraffic14d": [
- { }
], - "forecastDailyVisits14d": [
- {
- "forecastDate": "string",
- "predictedVisits": 0
}
], - "expectedOrdersByDate14d": {
- "property1": 0,
- "property2": 0
}, - "expectedProductOrdersByDate14dByProductId": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "expectedUnitsDemandByDate14dByProductId": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "expectedSalesByDate14dByProductId": { },
- "stockoutProjectionByProductId": {
- "property1": {
- "startingAvailableUnits": 0,
- "expectedUnitsDemandTotal14d": 0,
- "remainingUnitsByDate14d": {
- "property1": 0,
- "property2": 0
}, - "variants": {
- "property1": {
- "variantId": "string",
- "title": "string",
- "startingAvailableUnits": 0,
- "expectedUnitsDemandTotal14d": 0,
- "stockoutDate": "string",
- "remainingUnitsByDate14d": {
- "property1": 0,
- "property2": 0
}
}, - "property2": {
- "variantId": "string",
- "title": "string",
- "startingAvailableUnits": 0,
- "expectedUnitsDemandTotal14d": 0,
- "stockoutDate": "string",
- "remainingUnitsByDate14d": {
- "property1": 0,
- "property2": 0
}
}
}, - "productStockoutDate": "string"
}, - "property2": {
- "startingAvailableUnits": 0,
- "expectedUnitsDemandTotal14d": 0,
- "remainingUnitsByDate14d": {
- "property1": 0,
- "property2": 0
}, - "variants": {
- "property1": {
- "variantId": "string",
- "title": "string",
- "startingAvailableUnits": 0,
- "expectedUnitsDemandTotal14d": 0,
- "stockoutDate": "string",
- "remainingUnitsByDate14d": {
- "property1": 0,
- "property2": 0
}
}, - "property2": {
- "variantId": "string",
- "title": "string",
- "startingAvailableUnits": 0,
- "expectedUnitsDemandTotal14d": 0,
- "stockoutDate": "string",
- "remainingUnitsByDate14d": {
- "property1": 0,
- "property2": 0
}
}
}, - "productStockoutDate": "string"
}
}, - "totalUnitsSoldAllVariants14d": 0,
- "topVariants": [
- { }
], - "topProducts": [
- { }
]
}Returns all stores (locations) for the specified client.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
{- "stores": [
- {
- "id": 0,
- "shopify_location_id": 0,
- "name": "string",
- "address": "string",
- "timezone": "string",
- "open_time": "string",
- "close_time": "string",
- "is_active": true,
- "created_at": "string",
- "updated_at": "string"
}
]
}List registered entrance devices across every store for the client, for
use by UI location/device pickers. Excludes POS devices (same scope as
the serial numbers fed into BigQuery traffic queries) and unregistered
devices. Pair a device's id with its locationId as the deviceId
query param on /summary, /summary/full, /opportunity-loss,
/demographics, /visits, and /heatmap.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
{- "devices": [
- {
- "id": 0,
- "serialNumber": "string",
- "name": "string",
- "locationId": "string",
- "storeName": "string"
}
]
}Returns locations in the same format the dashboard expects: list of
{ id, name, active }. Only includes stores that have at least one
registered (ENTRANCE) traffic device; active is true when the location
has at least one active license. hasActiveLicenses is true when at
least one returned location is active.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
{- "locations": [
- {
- "id": "string",
- "name": "string",
- "active": true
}
], - "hasActiveLicenses": true
}Returns key dashboard metrics for each requested locationId, computed in
parallel. Each result pairs a location_id with a data object holding
the same kind of metrics as /summary, plus store-economics ratios
(revenue per store size, revenue per rent, traffic-to-rent) when store
size/rent are configured — those ratio fields are null otherwise. Also
includes sales_per_hour (gross sales for the period divided by the
store's total operating hours in that period, from its configured
store_hours schedule — not staff/labor hours); null when the store has
no operating-hours schedule configured, or when it was closed the whole
period.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| locationId required | Array of strings non-empty One or more Shopify location IDs. Repeat the parameter ( |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null Default: "true" If true, filters results to only include hours when the store was open. |
[- {
- "location_id": "string",
- "data": {
- "start_date": "string",
- "end_date": "string",
- "unique_visitors": 0,
- "total_visitors": 0,
- "dwell_time_seconds": 0,
- "cvr_unique": 0,
- "cvr_total": 0,
- "revenue_per_visitor_unique": 0,
- "revenue_per_visitor_total": 0,
- "aov": 0,
- "total_sales": 0,
- "total_net_sales": 0,
- "total_discounts": 0,
- "total_orders": 0,
- "women_pct_unique": 0,
- "men_pct_unique": 0,
- "women_pct_total": 0,
- "men_pct_total": 0,
- "revenue_per_store_size": 0,
- "revenue_per_rent": 0,
- "traffic_to_rent_ratio_unique": 0,
- "traffic_to_rent_ratio_total": 0,
- "sales_per_hour": 0
}
}
]Returns key dashboard metrics aggregated across all stores for the specified client, or for a
single store when locationId is set. Traffic and session metrics from BigQuery; CVR, AOV, and
revenue per visitor from ShopifyQL. Defaults to yesterday when startDate and endDate are omitted.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
Array of strings or null One or more Shopify location IDs. When exactly one is given, the response is scoped to that store; omit for all locations. | |
integer or null Narrow to a single registered entrance device (its internal id, from | |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when stores were open. The time range spans from the earliest opening hour to the latest closing hour across all days of the week. |
{- "uniqueVisitors": 0,
- "total_visitors": 0,
- "dwellTimeSeconds": 0,
- "averageDailyTraffic": 0,
- "startDate": "string",
- "endDate": "string",
- "cvr_unique": 0,
- "cvr_total": 0,
- "revenue_per_visitor_unique": 0,
- "revenue_per_visitor_total": 0,
- "aov": 0,
- "totalSales": 0,
- "totalOrders": 0,
- "operatingHours": {
- "property1": 0,
- "property2": 0
}, - "storeTimezone": "string"
}Two breakdowns: unique visitors (genderUnique, ageUnique, ageByGenderUnique)—latest enter
per visitor key (global_id + local date + camera SN)—and all duplicate rows (genderTotal,
ageTotal, ageByGenderTotal), one count per device_duplicates_normalized row. Empty views are
filled from in_count on device_events_normalized with the same filters as dashboard traffic.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
Array of strings or null One or more Shopify location IDs. Repeat the parameter or comma-separate within a value. Omit for all locations. | |
integer or null Narrow to a single registered entrance device (its internal id, from | |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null Default: "true" If true, filters results to only include hours when the store(s) were open. |
{- "genderUnique": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "ageUnique": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "ageByGenderUnique": [
- {
- "age": "string",
- "gender": "string",
- "count": 0
}
], - "genderTotal": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "ageTotal": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "ageByGenderTotal": [
- {
- "age": "string",
- "gender": "string",
- "count": 0
}
], - "startDate": "string",
- "endDate": "string",
- "locationId": "string",
- "applyOperatingHours": true
}Returns the full dashboard payload expected by the Shopify app frontend. All data (locations,
user tier, shop info, summary, heatmaps, revenue, anomalies, opportunity loss) is computed here.
Scoped to a single store when exactly one locationId is given, otherwise aggregated across all
stores for the client.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
Array of strings or null One or more Shopify location IDs. When exactly one is given, the response is scoped to that store. | |
string or null Metric to display in the heatmap. Defaults to visits. | |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when stores were open. Defaults to true. | |
string or null Comparison period type. "dod" compares to the previous day, "wow" to the previous week. Defaults to wow. |
{- "gender": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "age": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "ageByGender": [
- {
- "age": "string",
- "gender": "string",
- "count": 0
}
], - "revenue": {
- "totalRevenue": 0,
- "orderCount": 0,
- "averageOrderValue": 0,
- "posOrderCount": 0,
- "posRevenue": 0,
- "period": "string",
- "revenuePerVisitor": 0,
- "timestamp": "string",
- "isRealData": true,
- "locationId": "string"
}, - "dailyTraffic": [
- { }
], - "heatmap": {
- "property1": [
- 0
], - "property2": [
- 0
]
}, - "rawHeatmapData": [
- {
- "hour": 0,
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "dailyTotals": [
- 0
], - "heatmapDailyTotals": [
- 0
], - "allHeatmapData": { },
- "locations": [
- { }
], - "shop": "string",
- "startDate": "string",
- "endDate": "string",
- "locationId": "string",
- "heatmapMetric": "visits",
- "operatingHours": { },
- "applyOperatingHours": true,
- "failedDevices": [
- "string"
], - "hasActiveLicenses": true,
- "activeDeviceCount": 0,
- "validDeviceCount": 0,
- "totalRegisteredDeviceCount": 0,
- "userTier": "string",
- "forecastResult": { },
- "forecastUpliftResult": { },
- "dwellTimeSeconds": 0,
- "uniqueVisitors": 0,
- "anomaliesVisitsHourly": [ ],
- "anomaliesVisits4h": [ ],
- "anomaliesCvrHourly": [ ],
- "anomaliesCvr4h": [ ],
- "opportunityLossData": [ ],
- "comparisonPeriod": "dod",
- "comparisonWeightedTotals": { },
- "shopInfo": {
- "currencyCode": "string",
- "currency": "string",
- "locale": "string",
- "localeName": "string",
- "currencySymbol": "string"
}, - "extraDevices": [ ]
}Three parallel BigQuery loads (same camera / date / operating-hours filters):
global_id + local date + camera SN) per day
(summed across cameras) from device_duplicates_normalized.COUNT(*) per day on device_duplicates_normalized (no
per-visitor deduplication).in_count per day from device_events_normalized.dailyUnique / dailyTraffic — sorted lists of { "date", "traffic" } merged from the above
(unique ↔ normalized; dup rows ↔ merged unique). Raw series dailyUniqueByGlobalId,
dailyDuplicateTableRows, dailyNormalizedTraffic are unchanged.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
Array of strings or null One or more Shopify location IDs. Repeat the parameter or comma-separate within a value. Omit for all locations. | |
integer or null Narrow to a single registered entrance device (its internal id, from | |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null Default: "true" If true, filters results to only include hours when the store(s) were open. |
{- "dailyUnique": [
- {
- "date": "string",
- "traffic": 0
}
], - "dailyTraffic": [
- {
- "date": "string",
- "traffic": 0
}
], - "startDate": "string",
- "endDate": "string",
- "locationId": "string",
- "applyOperatingHours": true
}Return heatmap payload in the same format as the full dashboard: heatmap, rawHeatmapData,
heatmapDailyTotals, allHeatmapData (visits, cvr, aov, combined), forecastResult,
forecastUpliftResult, operatingHours, etc. Single-store or aggregate depending on whether exactly
one locationId is provided.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
Array of strings or null One or more Shopify location IDs. When exactly one is given, the response is scoped to that store; otherwise aggregated across all locations. | |
integer or null Narrow to a single registered entrance device (its internal id, from | |
string or null Default: "visits" Metric to display in the heatmap. Defaults to visits. | |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null Default: "true" If true, filters results to only include hours when the store(s) were open. |
{- "heatmap": {
- "property1": [
- 0
], - "property2": [
- 0
]
}, - "rawHeatmapData": [
- {
- "hour": 0,
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "dailyTotals": [
- 0
], - "heatmapDailyTotals": [
- 0
], - "allHeatmapData": { },
- "forecastResult": { },
- "forecastUpliftResult": { },
- "operatingHours": { },
- "startDate": "string",
- "endDate": "string",
- "heatmapMetric": "visits",
- "locationId": "string",
- "applyOperatingHours": true
}Returns a JSON object keyed by Shopify locationId, where each value matches the
payload from GET /api/{shopify_domain}/heatmap?locationId=... (heatmap, rawHeatmapData,
dailyTotals, heatmapDailyTotals, allHeatmapData, forecastResult, operatingHours, etc.).
?locationId=1&locationId=2. Comma-separated
values in a single parameter are also accepted.false), regardless of the value passed.visits | cvr | aov | combined (default visits).Non-numeric location IDs yield an empty heatmap/heatmapDailyTotals payload for that key.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| locationId required | Array of strings non-empty One or more Shopify location IDs. Repeat the parameter ( |
| startDate required | string^\d{4}-\d{2}-\d{2}$ Start date (YYYY-MM-DD). |
| endDate required | string^\d{4}-\d{2}-\d{2}$ End date (YYYY-MM-DD). |
string or null Default: "false" Accepted but ignored; this endpoint always disables operating-hours filtering. | |
string or null Default: "visits" Metric for the reduced heatmap and daily totals. Defaults to visits. |
{- "property1": {
- "heatmap": {
- "property1": [
- 0
], - "property2": [
- 0
]
}, - "rawHeatmapData": [
- {
- "hour": 0,
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "dailyTotals": [
- 0
], - "heatmapDailyTotals": [
- 0
], - "allHeatmapData": { },
- "forecastResult": { },
- "forecastUpliftResult": { },
- "operatingHours": { },
- "startDate": "string",
- "endDate": "string",
- "heatmapMetric": "visits",
- "locationId": "string",
- "applyOperatingHours": true
}, - "property2": {
- "heatmap": {
- "property1": [
- 0
], - "property2": [
- 0
]
}, - "rawHeatmapData": [
- {
- "hour": 0,
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "dailyTotals": [
- 0
], - "heatmapDailyTotals": [
- 0
], - "allHeatmapData": { },
- "forecastResult": { },
- "forecastUpliftResult": { },
- "operatingHours": { },
- "startDate": "string",
- "endDate": "string",
- "heatmapMetric": "visits",
- "locationId": "string",
- "applyOperatingHours": true
}
}Returns a JSON object keyed by Shopify locationId, where each value is
{ rawHeatmapData, startDate, endDate, locationId }. Unlike /heatmap/by-location,
rawHeatmapData rows are keyed by real calendar date (YYYY-MM-DD) + hour instead of
weekday + hour, so one range request returns actual daily history rather than a
7-weekday rollup.
?locationId=1&locationId=2. Comma-separated
values in a single parameter are also accepted./heatmap/by-location), regardless
of any applyOperatingHours value — there is no such parameter on this endpoint.orders/sales come from ShopifyQL and default to 0/0.0 when ShopifyQL data is
absent; rows with orders == 0 from refund-only lines are filtered out upstream (same
rule as the weekday-grouped heatmap endpoints).| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| locationId required | Array of strings non-empty One or more Shopify location IDs. Repeat the parameter ( |
| startDate required | string^\d{4}-\d{2}-\d{2}$ Start date (YYYY-MM-DD). |
| endDate required | string^\d{4}-\d{2}-\d{2}$ End date (YYYY-MM-DD). |
{- "property1": {
- "rawHeatmapData": [
- {
- "date": "string",
- "hour": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "startDate": "string",
- "endDate": "string",
- "locationId": "string"
}, - "property2": {
- "rawHeatmapData": [
- {
- "date": "string",
- "hour": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "startDate": "string",
- "endDate": "string",
- "locationId": "string"
}
}Returns opportunity loss data for the given date range and filters. Same
semantics as /dashboard: startDate, endDate, locationId (optional),
applyOperatingHours, comparisonPeriod ("wow" or "dod").
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
Array of strings or null Optional location ID(s) to scope the query. Repeat the parameter for multiple locations; omit for all locations. | |
integer or null Narrow to a single registered entrance device (its internal id, from | |
string or null Default: "true" If true, filters results to only include hours when the store(s) were open. | |
string or null Default: "wow" Comparison period type. "dod" compares to the previous day, "wow" to the previous week. Defaults to "wow". |
{- "opportunityLossData": [
- { }
], - "comparisonPeriod": "dod",
- "comparisonWeightedTotals": { },
- "startDate": "string",
- "endDate": "string",
- "locationId": "string"
}Returns a full dashboard-style summary (demographics, opportunity loss,
daily traffic, raw heatmap rows, forecasts, revenue metrics) used to
populate the comparison pane. Same filter semantics as /opportunity-loss
and /dashboard.
Note: unlike /dashboard, the heatmap field here is the raw per-hour
row array (same content as rawHeatmapData), not a pivoted hour-to-week
map.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
Array of strings or null Optional location ID(s) to scope the query. Repeat the parameter for multiple locations; omit for all locations. | |
integer or null Narrow to a single registered entrance device (its internal id, from | |
string or null Default: "true" If true, filters results to only include hours when the store(s) were open. | |
string or null Default: "wow" Comparison period type. "dod" compares to the previous day, "wow" to the previous week. Defaults to "wow". |
{- "gender": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "age": [
- {
- "category": "string",
- "count": 0,
- "percentage": 0
}
], - "ageByGender": [
- { }
], - "dailyTraffic": [
- {
- "date": "string",
- "traffic": 0
}
], - "heatmap": [
- {
- "hour": 0,
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "rawHeatmapData": [
- {
- "hour": 0,
- "day": 0,
- "visits": 0,
- "totalTraffic": 0,
- "orders": 0,
- "sales": 0
}
], - "heatmapDailyTotals": [
- { }
], - "allHeatmapData": { },
- "locations": [
- "string"
], - "deviceId": 0,
- "startDate": "string",
- "endDate": "string",
- "applyOperatingHours": true,
- "forecastResult": [ ],
- "forecastUpliftResult": [ ],
- "dwellTimeSeconds": 0,
- "uniqueVisitors": 0,
- "anomaliesVisitsHourly": [ ],
- "anomaliesVisits4h": [ ],
- "anomaliesCvrHourly": [ ],
- "anomaliesCvr4h": [ ],
- "opportunityLossData": [ ],
- "comparisonPeriod": "dod",
- "comparisonWeightedTotals": { },
- "dailyAverages": { },
- "revenue_per_visitor_unique": 0,
- "cvr_unique": 0,
- "revenue_per_visitor_total": 0,
- "cvr_total": 0,
- "total_visitors": 0,
- "revenue_per_visitor": 0,
- "cvr": 0,
- "aov": 0,
- "totalSales": 0,
- "totalOrders": 0,
- "shopInfo": {
- "currencyCode": "string",
- "currency": "string",
- "locale": "string",
- "localeName": "string",
- "currencySymbol": "string"
}, - "locationId": "string"
}Returns POS metrics in the same structure as the Shopify app api.pos.metrics route. Used by the POS extension. Traffic and demographics from BigQuery; revenue and orders from ShopifyQL. Same filter semantics as /dashboard and /summary: startDate/endDate default to yesterday.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
Array of strings or null One or more Shopify location IDs. When exactly one is given, the response is scoped to that store; omit for all locations. | |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when stores were open. Defaults to true. |
{- "shop": "string",
- "locationId": "string",
- "startDate": "string",
- "endDate": "string",
- "applyOperatingHours": true,
- "timezone": "string",
- "shopInfo": {
- "currencyCode": "string",
- "currency": "string",
- "locale": "string",
- "localeName": "string",
- "currencySymbol": "string"
}, - "metrics": {
- "totalTraffic": 0,
- "uniqueVisitors": 0,
- "conversionRate": 0,
- "revenuePerVisitor": 0,
- "demographics": {
- "gender": [
- {
- "label": "string",
- "range": "string",
- "count": 0,
- "percentage": 0
}
], - "age": [
- {
- "label": "string",
- "range": "string",
- "count": 0,
- "percentage": 0
}
]
}, - "hourlyVisits": [
- {
- "hour": 0,
- "actual": 0,
- "forecasted": 0
}
]
}
}Predicts the rolling 14-day forecasted traffic per hour aggregated across all stores for the specified client, starting with today's date. Built by aggregating each store's forecast rows by (day-of-week, hour) and projecting that pattern onto the next 14 calendar dates. Unlike the per-store variant, this aggregate response never includes an "insight" or "accuracy" field.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
{- "traffic_forecast_hourly": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "traffic_forecast_4h": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "insight": { },
- "accuracy": 100
}Returns a JSON object keyed by Shopify locationId, where each value is the exact same
payload as GET /api/{shopify_domain}/stores/{shopify_location_id}/ai/traffic-forecast
(traffic_forecast_hourly, traffic_forecast_4h, insight, accuracy) — so a forecast
sync can fetch N locations in one request instead of N serial per-location calls.
?locationId=1&locationId=2. Comma-separated
values in a single parameter are also accepted./ai/traffic-forecast endpoint, each per-location value always
includes an insight field (empty object when no insight is available), matching the
per-store variant.accuracy is computed per location, from that location's own devices only — a store
with multiple devices gets one weighted accuracy percentage combining all of them, not
a per-device breakdown.| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
| locationId required | Array of strings non-empty One or more Shopify location IDs. Repeat the parameter ( |
{- "property1": {
- "traffic_forecast_hourly": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "traffic_forecast_4h": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "insight": { },
- "accuracy": 100
}, - "property2": {
- "traffic_forecast_hourly": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "traffic_forecast_4h": {
- "property1": {
- "property1": 0,
- "property2": 0
}, - "property2": {
- "property1": 0,
- "property2": 0
}
}, - "insight": { },
- "accuracy": 100
}
}Returns detected visit anomaly keys (date -> hour or 4-hour bucket label) aggregated across all stores for the specified client. Unlike the CVR anomalies endpoint, each bucket's value is always an empty object; only the presence of a key indicates an anomaly was detected for that date/hour (or date/bucket). This aggregate shape intentionally omits the anomaly magnitude and direction that the per-store variant includes.
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when stores were open. |
{- "anomalies_visits_hourly": {
- "property1": {
- "property1": { },
- "property2": { }
}, - "property2": {
- "property1": { },
- "property2": { }
}
}, - "anomalies_visits_4h": {
- "property1": {
- "property1": { },
- "property2": { }
}, - "property2": {
- "property1": { },
- "property2": { }
}
}
}Returns detected conversion rate (CVR) anomalies with hourly and 4-hour bucket groupings aggregated across all stores for the specified client. CVR is expressed as a percentage. Each anomaly includes the anomaly value (CVR percentage as integer) and type ('positive', 'negative', or 'neutral').
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
string or null Start date (YYYY-MM-DD). Defaults to yesterday. | |
string or null End date (YYYY-MM-DD). Defaults to yesterday. | |
string or null If true, filters results to only include hours when stores were open. |
{- "anomalies_cvr_hourly": {
- "property1": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}, - "property2": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}
}, - "anomalies_cvr_4h": {
- "property1": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}, - "property2": {
- "property1": {
- "anomaly": 0,
- "type": "positive"
}, - "property2": {
- "anomaly": 0,
- "type": "positive"
}
}
}
}Returns top variants with inventory data for CVR investigation. Response includes success, shop, serverTime (ISO), received (date, locationId), inventoryMessage, inventoryMessageParams, outOfStockSummary (products, variants), and topProducts (array of variants with stock data).
| shopify_domain required | string Shopify myshopify domain (e.g., brand-x.myshopify.com). |
string or null Date (YYYY-MM-DD) for the investigation. When omitted, topProducts items are NOT enriched with stock fields (stockOnDate/stockSource/hadOutOfStock/outOfStockDate/stockDetails are absent). | |
string or null Optional location ID to scope the investigation. |
{- "success": true,
- "shop": "string",
- "serverTime": "string",
- "received": {
- "date": "string",
- "locationId": "string"
}, - "inventoryMessage": "string",
- "inventoryMessageParams": { },
- "outOfStockSummary": {
- "products": 0,
- "variants": 0
}, - "topProducts": [
- {
- "variantId": "string",
- "variantTitle": "string",
- "sku": "string",
- "productId": "string",
- "productTitle": "string",
- "productHandle": "string",
- "featuredImageUrl": "string",
- "unitsSold": 0,
- "ordersCount": 0,
- "avgUnitsPerOrder": 0,
- "stockOnDate": "in_stock",
- "stockSource": "bigquery",
- "hadOutOfStock": true,
- "outOfStockDate": "string",
- "stockDetails": { }
}
]
}Returns a labor efficiency report for the given date range: KPIs (average sales-per-labor-hour,
total/understaffed/overstaffed labor hours and slot counts) and a per-store breakdown with
flagged understaffed/overstaffed time slots. Pass includeHourly=true to also get the raw
hourly markers (sales, orders, visitors, staffing, CVR, SPLH) used to compute the report.
| startDate required | string <date> Start date (YYYY-MM-DD). |
| endDate required | string <date> End date (YYYY-MM-DD). |
string or null Optional shop/client filter. Omit to include all clients. | |
Array of strings or null Optional Shopify location ID filter. Repeat the parameter for multiple locations. | |
| includeHourly | boolean Default: false When true, includes the raw hourly markers array for each store. |
{- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "generated_at": "2019-08-24T14:15:22Z",
- "kpis": {
- "avg_splh": 0,
- "total_labor_hours": 0,
- "understaffed_hours": 0,
- "overstaffed_hours": 0,
- "understaffed_slots": 0,
- "overstaffed_slots": 0
}, - "stores": [
- {
- "store_id": 0,
- "location_id": "string",
- "store_name": "string",
- "store_group": "string",
- "efficiency_score": 0,
- "avg_splh": 0,
- "splh_variance_pct": 0,
- "avg_cvr": 0,
- "total_hours": 0,
- "warnings": [
- "string"
], - "flagged_slots": [
- {
- "date": "2019-08-24",
- "start_hour": 0,
- "end_hour": 0,
- "flag": "UNDERSTAFFED",
- "hours_gap": 0,
- "label": "string",
- "benchmark_splh": 0,
- "cvr_benchmark": 0
}
], - "hourly": [
- {
- "date": "2019-08-24",
- "hour": 0,
- "gross_sales": 0,
- "orders": 0,
- "visitors": 0,
- "floor_count": 0,
- "splh": 0,
- "cvr": 0,
- "flag": "UNDERSTAFFED",
- "hours_gap": 0,
- "cvr_benchmark": 0,
- "warning_codes": [
- "string"
]
}
]
}
]
}