> ## Documentation Index > Fetch the complete documentation index at: https://docs.restaurant365.com/llms.txt > Use this file to discover all available pages before exploring further. # Sales Analytics > Retrieves published forecast sales Maximum date range is 14 days; a wider range returns 400. Note: despite the name, most interval fields are labor metrics and the whole jobDetails array is per-job labor. **Security** The requesting user must have the following permission to retrieve sales analytics: - Sales & Cash → Forecasts → Weekly Forecasting → View Weekly Forecasting ## OpenAPI ````json GET /public/v1/labor/sales-analytics { "openapi": "3.0.1", "info": { "title": "R365 Public API", "contact": { "name": "R365 Services Team", "email": "r365@restaurant365.com" }, "version": "1.0" }, "security": [ { "Bearer": [] } ], "paths": { "/public/v1/labor/sales-analytics": { "get": { "tags": [ "labor" ], "summary": "Sales Analytics", "description": "Retrieves published forecast sales Maximum date range is 14 days; a wider range returns 400. Note: despite the name, most interval fields are labor metrics and the whole jobDetails array is per-job labor.\n\n**Security**\n\nThe requesting user must have the following permission to retrieve sales analytics:\n\n- Sales & Cash → Forecasts → Weekly Forecasting → View Weekly Forecasting", "parameters": [ { "$ref": "#/components/parameters/TenantId" }, { "name": "locationId", "in": "query", "description": "Identifier of the location to get forecast data", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "startDate", "in": "query", "description": "Start date to get forecast data", "required": true, "schema": { "type": "string", "format": "date" } }, { "name": "endDate", "in": "query", "description": "End date to get forecast data", "required": true, "schema": { "type": "string", "format": "date" } } ], "responses": { "200": { "description": "Published forecast sales", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/LocationLaborAnalyticsResponse" } }, "application/json": { "schema": { "$ref": "#/components/schemas/LocationLaborAnalyticsResponse" } }, "text/json": { "schema": { "$ref": "#/components/schemas/LocationLaborAnalyticsResponse" } } } }, "400": { "description": "Bad Request — a parameter value is malformed, of the wrong type, or outside its allowed range." }, "401": { "description": "Unauthorized — the bearer token is missing, invalid or expired, or is not valid for the specified tenant." }, "403": { "description": "Forbidden — the caller lacks the permission required for this operation." }, "404": { "description": "Not Found — the requested resource does not exist, or the supplied continuation token is unknown or has expired." }, "409": { "description": "Conflict — the request conflicts with the current state of the resource and cannot be applied." }, "422": { "description": "Unprocessable Entity — a required parameter is missing, or a supplied parameter value is invalid." }, "429": { "description": "Too Many Requests — the caller has exceeded the rate limit; retry after a short delay." }, "500": { "description": "Internal Server Error — an unexpected error occurred while processing the request." } } } } }, "components": { "parameters": { "TenantId": { "name": "x-r365-context-tenant-id", "in": "header", "required": true, "description": "Identifies the R365 tenant the request applies to. Required on every request.", "schema": { "type": "string" } } }, "schemas": { "LocationLaborAnalyticsResponse": { "type": "object", "properties": { "locationId": { "type": "string", "format": "uuid", "description": "Unique identifier of the location." }, "locationName": { "type": "string", "nullable": true, "description": "Display name of the location." }, "dailyData": { "type": "array", "items": { "$ref": "#/components/schemas/DateIntervals" }, "nullable": true, "description": "Forecast data grouped by date for the requested period." } } }, "DateIntervals": { "type": "object", "properties": { "date": { "type": "string", "format": "date-time", "description": "Forecast date." }, "intervals": { "type": "array", "items": { "$ref": "#/components/schemas/Interval" }, "nullable": true, "description": "Forecast intervals within the date." } } }, "Interval": { "type": "object", "properties": { "startDateTime": { "type": "string", "format": "date-time", "description": "Start date and time of the interval." }, "publishedAt": { "type": "string", "format": "date-time", "nullable": true, "description": "Date and time the forecast was published. Null when the forecast has not been published yet." }, "publishedByName": { "type": "string", "nullable": true, "description": "Username of the user who published the forecast." }, "forecastedNetSales": { "type": "number", "format": "double", "description": "Forecasted net sales amount for the interval (precision 10,2)." }, "forecastedGrossSales": { "type": "number", "format": "double", "description": "Forecasted gross sales amount for the interval (precision 10,2)." }, "forecastedEntree": { "type": "number", "format": "double", "description": "Forecasted entree count for the interval (precision 10,2)." }, "forecastedLabor": { "type": "number", "format": "double", "description": "Forecasted labor cost for the interval (precision 5,2)." }, "actualNetSales": { "type": "number", "format": "double", "description": "Actual net sales amount recorded for the interval (precision 5,2)." }, "actualGrossSales": { "type": "number", "format": "double", "description": "Actual gross sales amount recorded for the interval (precision 5,2)." }, "actualEntreeCount": { "type": "integer", "format": "int32", "description": "Actual entree count recorded for the interval." }, "actualLabor": { "type": "number", "format": "double", "description": "Actual labor cost recorded for the interval (precision 5,2)." }, "actualLaborOTHours": { "type": "number", "format": "double", "description": "Actual overtime hours recorded for the interval (precision 5,2)." }, "actualLaborDollars": { "type": "number", "format": "double", "description": "Actual labor dollars recorded for the interval (precision 5,2)." }, "optimalLaborVariance": { "type": "number", "format": "double", "description": "Difference between optimal and actual labor (OptimalLabor - ActualLabor, precision 5,2)." }, "optimalLabor": { "type": "number", "format": "double", "description": "Optimal labor cost for the interval (precision 5,2)." }, "jobDetails": { "type": "array", "items": { "$ref": "#/components/schemas/JobDetail" }, "nullable": true, "description": "Per-job breakdown of forecasted and actual labor within the interval." } } }, "JobDetail": { "type": "object", "properties": { "jobId": { "type": "string", "format": "uuid", "description": "Job identifier." }, "jobName": { "type": "string", "nullable": true, "description": "Job name." }, "laborForecast": { "type": "number", "format": "double", "description": "Forecasted labor cost for the job within the interval (precision 5,2)." }, "actualLabor": { "type": "number", "format": "double", "description": "Actual labor cost recorded for the job within the interval (precision 5,2)." }, "actualLaborOTHours": { "type": "number", "format": "double", "description": "Actual overtime hours recorded for the job within the interval (precision 5,2)." }, "actualLaborDollars": { "type": "number", "format": "double", "description": "Actual labor dollars recorded for the job within the interval (precision 5,2)." } } } }, "securitySchemes": { "Bearer": { "type": "http", "scheme": "Bearer" } } } } ````