SmartQ.tv SmartQ.tv
Developer API Examples

Representative Response Examples

These are representative response-shape examples. They intentionally use placeholder values such as GROUP_ID, LOCATION_ID, ISO_TIMESTAMP, STATUS_STRING, and venue-neutral IDs or timestamps instead of venue-specific data.

Authentication

Obtain and reuse a 24-hour access token

Run the exchange only from a trusted server. Cache the access token and renew it several minutes before its fixed 86,400-second expiry. No refresh token is issued, and an application revocation invalidates outstanding tokens immediately.

cURL

curl --request POST https://api.smartq.tv/oauth/token \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=client_credentials" \
  --data-urlencode "client_id=YOUR_CLIENT_ID" \
  --data-urlencode "client_secret=YOUR_CLIENT_SECRET"

Node.js / JavaScript

const tokenResponse = await fetch("https://api.smartq.tv/oauth/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "client_credentials",
    client_id: process.env.SMARTQ_CLIENT_ID,
    client_secret: process.env.SMARTQ_CLIENT_SECRET,
  }),
});
if (!tokenResponse.ok) throw new Error(`Token request failed: ${tokenResponse.status}`);
const { access_token, expires_in } = await tokenResponse.json();
const response = await fetch("https://api.smartq.tv/v1/GROUP_ID/locations", {
  headers: { Authorization: `Bearer ${access_token}` },
});

Python

import os
import requests

token_response = requests.post(
    "https://api.smartq.tv/oauth/token",
    data={
        "grant_type": "client_credentials",
        "client_id": os.environ["SMARTQ_CLIENT_ID"],
        "client_secret": os.environ["SMARTQ_CLIENT_SECRET"],
    },
    timeout=10,
)
token_response.raise_for_status()
access_token = token_response.json()["access_token"]
response = requests.get(
    "https://api.smartq.tv/v1/GROUP_ID/locations",
    headers={"Authorization": f"Bearer {access_token}"},
    timeout=10,
)

PHP

$tokenRequest = curl_init("https://api.smartq.tv/oauth/token");
curl_setopt_array($tokenRequest, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Content-Type: application/x-www-form-urlencoded"],
    CURLOPT_POSTFIELDS => http_build_query([
        "grant_type" => "client_credentials",
        "client_id" => getenv("SMARTQ_CLIENT_ID"),
        "client_secret" => getenv("SMARTQ_CLIENT_SECRET"),
    ]),
]);
$token = json_decode(curl_exec($tokenRequest), true)["access_token"];

Successful token JSON contains access_token, token_type: Bearer, expires_in: 86400, and the current optional scope string. Token endpoint errors are invalid_request, unsupported_grant_type, generic invalid_client, or rate-limited temporarily_unavailable.

locations:read

Discovery Example

{
  "ok": true,
  "version": "v1",
  "resource": "locations",
  "groupId": "GROUP_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "token": {
    "scopeType": "group_or_location",
    "scopes": ["locations:read", "shiftq:menu:read", "shiftq:sales:read", "matriq:read"],
    "rateLimitPerMinute": "NUMBER",
    "expiresAt": "APPLICATION_EXPIRY_OR_NULL",
    "accessTokenExpiresAt": "ACCESS_TOKEN_EXPIRY_OR_NULL_FOR_SUPPORT_MANAGED",
    "credentialType": "CLIENT_CREDENTIALS_OR_SUPPORT_MANAGED",
    "status": "active_or_revoked_or_expired",
    "allowedLocationIds": ["LOCATION_ID_IF_LOCATION_SCOPED"],
    "tokenPrefix": "SUPPORT_MANAGED_TOKEN_PREFIX_OR_EMPTY"
  },
  "data": {
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "REFRESH_DESCRIPTION"
    },
    "locations": [
      {
        "id": "LOCATION_ID",
        "name": "LOCATION_NAME",
        "locationShortName": "LOCATION_SHORT_NAME",
        "timezone": "IANA_TIMEZONE",
        "slug": "LOCATION_SLUG",
        "status": "STATUS_STRING",
        "modulesEnabled": {
          "shiftq": "BOOLEAN",
          "sportsq": "BOOLEAN",
          "matriq": "BOOLEAN",
          "campaigns": "BOOLEAN",
          "orderboard": "BOOLEAN"
        },
        "resources": ["RESOURCE_NAME"],
        "endpoints": {
          "root": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID",
          "modules": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/modules",
          "shiftq": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/shiftq",
          "sportsq": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/sportsq",
          "matriq": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/matriq"
        }
      }
    ]
  }
}
shiftq:read

ShiftQ Overview Example

{
  "ok": true,
  "version": "v1",
  "resource": "shiftq",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "sales": { "cadence": "CADENCE_STRING", "description": "SALES_REFRESH_DESCRIPTION" },
      "labor": { "cadence": "CADENCE_STRING", "description": "LABOR_REFRESH_DESCRIPTION" },
      "kitchen": { "cadence": "CADENCE_STRING", "description": "KITCHEN_REFRESH_DESCRIPTION" },
      "posMenu": { "cadence": "CADENCE_STRING", "description": "POS_MENU_REFRESH_DESCRIPTION" },
      "clockIns": { "cadence": "CADENCE_STRING", "description": "CLOCK_IN_REFRESH_DESCRIPTION" },
      "employees": { "cadence": "CADENCE_STRING", "description": "EMPLOYEE_REFRESH_DESCRIPTION" },
      "reservations": { "cadence": "CADENCE_STRING", "description": "RESERVATION_REFRESH_DESCRIPTION" }
    },
    "summary": {
      "businessDate": "YYYYMMDD",
      "salesUpdatedAt": "ISO_TIMESTAMP",
      "laborUpdatedAt": "ISO_TIMESTAMP",
      "top5Leaderboard": [
        { "employeeId": "EMPLOYEE_ID", "employeeName": "EMPLOYEE_NAME", "metric": "METRIC_NAME", "value": "NUMBER", "rank": "NUMBER" }
      ],
      "clockedInCount": "NUMBER",
      "soldOutItemCount": "NUMBER",
      "exceptionCounts": {
        "wrongJobCodeClockIns": "NUMBER",
        "scheduledButMissing": "NUMBER",
        "clockedInButNotScheduled": "NUMBER",
        "earlyClockIns": "NUMBER",
        "lateClockIns": "NUMBER"
      },
      "managerOnDutyCount": "NUMBER",
      "roleGroupCount": "NUMBER",
      "newTeamMemberCount": "NUMBER",
      "reservationDayCount": "NUMBER",
      "reservationPartyCount": "NUMBER",
      "kitchenAvgTicketTimeMinutes": "NUMBER",
      "kitchenExpediterAvgTicketTimeMinutes": "NUMBER",
      "kitchenReadyQueueCount": "NUMBER",
      "kitchenInProgressCount": "NUMBER",
      "kitchenStationCount": "NUMBER"
    }
  }
}
shiftq:read

ShiftQ Kitchen Example

{
  "ok": true,
  "version": "v1",
  "resource": "shiftq/kitchen",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "KITCHEN_REFRESH_DESCRIPTION"
    },
    "currentBusinessDate": "YYYYMMDD",
    "requestedBusinessDate": "YYYYMMDD",
    "bucketAvailable": true,
    "retentionDays": 366,
    "latestMetadata": {
      "updatedAt": "ISO_TIMESTAMP",
      "businessDate": "YYYYMMDD",
      "dateKey": "YYYY-MM-DD",
      "liveBusinessDate": "YYYYMMDD",
      "bucketIntervalMinutes": 15,
      "lastStatus": "ok",
      "lastHttpStatus": 200,
      "lastError": "ERROR_STRING_IF_PRESENT",
      "averageBasis": "ticket_count",
      "avgKitchenTicketTimeMinutes": 11.42,
      "avgKitchenTicketTimeDivisorField": "prepTicketCount",
      "avgKitchenTicketTimeDivisorValue": 37,
      "avgExpediterTicketTimeMinutes": 13.58,
      "avgExpediterTicketTimeDivisorField": "expediterTicketCount",
      "avgExpediterTicketTimeDivisorValue": 31,
      "avgExpoClearMinutes": 3.1,
      "prepTicketCount": 37,
      "prepRowCount": 88,
      "expediterTicketCount": 31,
      "expediterRowCount": 75,
      "expediterLevelCount": 1,
      "stationCount": 3,
      "salesCategoryCount": 2,
      "timeBucketCount": 6,
      "thirtyMinuteBucketCount": 6
    },
    "currentSnapshot": {
      "businessDate": "YYYYMMDD",
      "dateKey": "YYYY-MM-DD",
      "metricsBusinessDate": "YYYYMMDD",
      "metricsDateKey": "YYYY-MM-DD",
      "timezone": "IANA_TIMEZONE",
      "updatedAt": "ISO_TIMESTAMP",
      "dayStartMs": 1753632060000,
      "selectionMode": "prepStations",
      "trackedPrepStations": ["PREP_STATION_GUID"],
      "trackAllPrepStations": false,
      "availablePrepStations": [
        {
          "id": "PREP_STATION_GUID",
          "name": "Grill",
          "includeWithExpediter": false,
          "expoRouting": "EXPO"
        }
      ],
      "trackedSalesCategories": ["FOOD"],
      "trackAllSalesCategories": false,
      "availableSalesCategories": ["FOOD", "NA BEVERAGES"],
      "queue": {
        "inProgressCount": 4,
        "readyQueueCount": 2,
        "oldestReadyMinutes": 6
      },
      "averages": {
        "averageBasis": "ticket_count",
        "avgKitchenTicketTimeMinutes": 11.42,
        "avgKitchenTicketTimeSource": "prep_station_ticket_average",
        "avgKitchenTicketTimeDivisorField": "counts.prepTicketCount",
        "avgKitchenTicketTimeDivisorValue": 37,
        "avgExpediterTicketTimeMinutes": 13.58,
        "avgExpediterTicketTimeSource": "first_level_expediter_ticket_average",
        "avgExpediterTicketTimeDivisorField": "counts.expediterTicketCount",
        "avgExpediterTicketTimeDivisorValue": 31,
        "avgExpoClearMinutes": 3.1
      },
      "counts": {
        "clearedTicketCount": 33,
        "prepTicketCount": 37,
        "prepRowCount": 88,
        "sourceTicketCount": 24,
        "expediterTicketCount": 31,
        "expediterRowCount": 75,
        "expediterSourceTicketCount": 31,
        "expediterLevelCount": 1,
        "stationCount": 3,
        "salesCategoryCount": 2,
        "timeBucketCount": 6,
        "thirtyMinuteBucketCount": 6
      },
      "expediterTicketAverages": [
        {
          "fulfillmentLevel": 1,
          "stationName": "Expediter Level 1",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 31,
          "averageTicketTimeMinutes": 13.58,
          "ticketCount": 31,
          "rowCount": 75,
          "minTicketTimeMinutes": 5.2,
          "maxTicketTimeMinutes": 21.6
        }
      ],
      "stationTicketAverages": [
        {
          "stationGuid": "PREP_STATION_GUID",
          "stationName": "Grill",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 12,
          "averageTicketTimeMinutes": 10.67,
          "ticketCount": 12,
          "rowCount": 24,
          "minTicketTimeMinutes": 4.1,
          "maxTicketTimeMinutes": 17.8
        }
      ],
      "salesCategoryTicketAverages": [
        {
          "salesCategory": "FOOD",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 37,
          "averageTicketTimeMinutes": 11.42,
          "ticketCount": 37,
          "rowCount": 88,
          "minTicketTimeMinutes": 3.9,
          "maxTicketTimeMinutes": 19.2
        }
      ],
      "timeBuckets": [
        {
          "bucketStartMs": 1753632000000,
          "bucketEndMs": 1753632900000,
          "bucketStartIso": "ISO_TIMESTAMP",
          "bucketEndIso": "ISO_TIMESTAMP",
          "bucketLabel": "LOCAL_15_MINUTE_RANGE",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 9,
          "averageTicketTimeMinutes": 10.8,
          "ticketCount": 9,
          "rowCount": 21,
          "minTicketTimeMinutes": 4.6,
          "maxTicketTimeMinutes": 17.4,
          "stationTicketAverages": [
            {
              "stationGuid": "PREP_STATION_GUID",
              "stationName": "Grill",
              "averageBasis": "ticket_count",
              "averageDivisorField": "ticketCount",
              "averageDivisorValue": 4,
              "averageTicketTimeMinutes": 10.12,
              "ticketCount": 4,
              "rowCount": 8,
              "minTicketTimeMinutes": 4.8,
              "maxTicketTimeMinutes": 14.5
            }
          ],
          "expediterTicketAverages": [
            {
              "fulfillmentLevel": 1,
              "stationName": "Expediter Level 1",
              "averageBasis": "ticket_count",
              "averageDivisorField": "ticketCount",
              "averageDivisorValue": 8,
              "averageTicketTimeMinutes": 12.4,
              "ticketCount": 8,
              "rowCount": 19,
              "minTicketTimeMinutes": 5.1,
              "maxTicketTimeMinutes": 17.2
            }
          ],
          "salesCategoryTicketAverages": [
            {
              "salesCategory": "FOOD",
              "averageBasis": "ticket_count",
              "averageDivisorField": "ticketCount",
              "averageDivisorValue": 9,
              "averageTicketTimeMinutes": 10.8,
              "ticketCount": 9,
              "rowCount": 21,
              "minTicketTimeMinutes": 4.6,
              "maxTicketTimeMinutes": 17.4
            }
          ]
        }
      ],
      "bucketIntervalMinutes": 15,
      "status": {
        "state": "ok",
        "httpStatus": 200,
        "error": "ERROR_STRING_IF_PRESENT"
      },
      "retentionDays": 366
    },
    "requestedBucket": {
      "businessDate": "YYYYMMDD",
      "dateKey": "YYYY-MM-DD",
      "metricsBusinessDate": "YYYYMMDD",
      "metricsDateKey": "YYYY-MM-DD",
      "timezone": "IANA_TIMEZONE",
      "updatedAt": "ISO_TIMESTAMP",
      "dayStartMs": 1753545660000,
      "selectionMode": "prepStations",
      "trackedPrepStations": ["PREP_STATION_GUID"],
      "trackAllPrepStations": false,
      "availablePrepStations": [
        {
          "id": "PREP_STATION_GUID",
          "name": "Grill",
          "includeWithExpediter": false,
          "expoRouting": "EXPO"
        }
      ],
      "trackedSalesCategories": ["FOOD"],
      "trackAllSalesCategories": false,
      "availableSalesCategories": ["FOOD", "NA BEVERAGES"],
      "queue": {
        "inProgressCount": 3,
        "readyQueueCount": 1,
        "oldestReadyMinutes": 4
      },
      "averages": {
        "averageBasis": "ticket_count",
        "avgKitchenTicketTimeMinutes": 10.94,
        "avgKitchenTicketTimeSource": "prep_station_ticket_average",
        "avgKitchenTicketTimeDivisorField": "counts.prepTicketCount",
        "avgKitchenTicketTimeDivisorValue": 32,
        "avgExpediterTicketTimeMinutes": 12.71,
        "avgExpediterTicketTimeSource": "first_level_expediter_ticket_average",
        "avgExpediterTicketTimeDivisorField": "counts.expediterTicketCount",
        "avgExpediterTicketTimeDivisorValue": 27,
        "avgExpoClearMinutes": 2.8
      },
      "counts": {
        "clearedTicketCount": 29,
        "prepTicketCount": 32,
        "prepRowCount": 74,
        "sourceTicketCount": 21,
        "expediterTicketCount": 27,
        "expediterRowCount": 63,
        "expediterSourceTicketCount": 27,
        "expediterLevelCount": 1,
        "stationCount": 3,
        "salesCategoryCount": 2,
        "timeBucketCount": 5,
        "thirtyMinuteBucketCount": 5
      },
      "expediterTicketAverages": [
        {
          "fulfillmentLevel": 1,
          "stationName": "Expediter Level 1",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 27,
          "averageTicketTimeMinutes": 12.71,
          "ticketCount": 27,
          "rowCount": 63,
          "minTicketTimeMinutes": 5,
          "maxTicketTimeMinutes": 19.3
        }
      ],
      "stationTicketAverages": [
        {
          "stationGuid": "PREP_STATION_GUID",
          "stationName": "Grill",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 10,
          "averageTicketTimeMinutes": 10.11,
          "ticketCount": 10,
          "rowCount": 20,
          "minTicketTimeMinutes": 4,
          "maxTicketTimeMinutes": 16.6
        }
      ],
      "salesCategoryTicketAverages": [
        {
          "salesCategory": "FOOD",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 32,
          "averageTicketTimeMinutes": 10.94,
          "ticketCount": 32,
          "rowCount": 74,
          "minTicketTimeMinutes": 3.8,
          "maxTicketTimeMinutes": 18.7
        }
      ],
      "timeBuckets": [
        {
          "bucketStartMs": 1753545600000,
          "bucketEndMs": 1753546500000,
          "bucketStartIso": "ISO_TIMESTAMP",
          "bucketEndIso": "ISO_TIMESTAMP",
          "bucketLabel": "11:00 AM - 11:15 AM",
          "averageBasis": "ticket_count",
          "averageDivisorField": "ticketCount",
          "averageDivisorValue": 7,
          "averageTicketTimeMinutes": 10.3,
          "ticketCount": 7,
          "rowCount": 16,
          "minTicketTimeMinutes": 4.2,
          "maxTicketTimeMinutes": 15.9,
          "stationTicketAverages": [
            {
              "stationGuid": "PREP_STATION_GUID",
              "stationName": "Grill",
              "averageBasis": "ticket_count",
              "averageDivisorField": "ticketCount",
              "averageDivisorValue": 3,
              "averageTicketTimeMinutes": 9.92,
              "ticketCount": 3,
              "rowCount": 6,
              "minTicketTimeMinutes": 4.4,
              "maxTicketTimeMinutes": 13.8
            }
          ],
          "expediterTicketAverages": [
            {
              "fulfillmentLevel": 1,
              "stationName": "Expediter Level 1",
              "averageBasis": "ticket_count",
              "averageDivisorField": "ticketCount",
              "averageDivisorValue": 6,
              "averageTicketTimeMinutes": 11.9,
              "ticketCount": 6,
              "rowCount": 14,
              "minTicketTimeMinutes": 4.8,
              "maxTicketTimeMinutes": 16.1
            }
          ],
          "salesCategoryTicketAverages": [
            {
              "salesCategory": "FOOD",
              "averageBasis": "ticket_count",
              "averageDivisorField": "ticketCount",
              "averageDivisorValue": 7,
              "averageTicketTimeMinutes": 10.3,
              "ticketCount": 7,
              "rowCount": 16,
              "minTicketTimeMinutes": 4.2,
              "maxTicketTimeMinutes": 15.9
            }
          ]
        }
      ],
      "bucketIntervalMinutes": 15,
      "status": {
        "state": "ok",
        "httpStatus": 200,
        "error": "ERROR_STRING_IF_PRESENT"
      },
      "retentionDays": 366
    },
    "endpoints": {
      "current": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/shiftq/kitchen",
      "byBusinessDate": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/shiftq/kitchen?businessDate=YYYYMMDD"
    }
  }
}

Compatibility note: live ShiftQ kitchen responses also return thirtyMinuteBuckets as an alias of timeBuckets while existing consumers migrate to the 15-minute bucket contract. Historical reads accept both businessDate=YYYYMMDD and businessDay=YYYYMMDD, using the local 4:01 AM through 4:00 AM business day. avgExpoClearMinutes is always included in kitchen metadata and bucket records; it returns null when no cleared expo tickets were recorded for that business day.

Kitchen averages are ticket-based. Use averages.avgKitchenTicketTimeDivisorValue with counts.prepTicketCount for the prep average, averages.avgExpediterTicketTimeDivisorValue with counts.expediterTicketCount for the Expediter Level 1 average, and each nested station, sales-category, bucket, and expediter average uses that row's own ticketCount. rowCount is raw Toast item-fulfillment volume, not the averaging divisor.

shiftq:read

ShiftQ Reservations Example

{
  "ok": true,
  "version": "v1",
  "resource": "shiftq/reservations",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "RESERVATION_REFRESH_DESCRIPTION"
    },
    "source": "pos_reservations_digest",
    "reservations": {
      "venueLabel": "VENUE_LABEL",
      "asOf": "ISO_TIMESTAMP",
      "asOfLabel": "DISPLAY_LABEL",
      "dayCount": "NUMBER",
      "totalParties": "NUMBER",
      "totalCovers": "NUMBER",
      "days": [
        {
          "dayKey": "YYYY-MM-DD",
          "label": "DAY_LABEL",
          "parties": "NUMBER",
          "covers": "NUMBER",
          "items": [
            {
              "id": "RESERVATION_ID",
              "displayTime": "TIME_LABEL",
              "guestName": "GUEST_NAME",
              "partySize": "NUMBER",
              "notes": "NOTES_STRING"
            }
          ]
        }
      ]
    }
  }
}
shiftq:read

POS Reservations Alias Example

{
  "ok": true,
  "version": "v1",
  "resource": "shiftq/toastReservations",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "RESERVATION_REFRESH_DESCRIPTION"
    },
    "source": "pos_reservations_digest",
    "reservations": {
      "venueLabel": "VENUE_LABEL",
      "asOf": "ISO_TIMESTAMP",
      "dayCount": "NUMBER",
      "totalParties": "NUMBER",
      "totalCovers": "NUMBER",
      "days": ["DAY_ROW_OBJECT"]
    }
  }
}
shiftq:read

ShiftQ Group Leaderboard Example

{
  "ok": true,
  "version": "v1",
  "resource": "shiftq/group-leaderboard",
  "groupId": "GROUP_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "groupId": "GROUP_ID",
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "GROUP_LEADERBOARD_REFRESH_DESCRIPTION"
    },
    "updatedAt": "ISO_TIMESTAMP",
    "count": "NUMBER",
    "leaderboard": {
      "byNetSales": [
        {
          "locationId": "LOCATION_ID",
          "locationName": "LOCATION_NAME",
          "locationShortName": "LOCATION_SHORT_NAME",
          "netSales": "NUMBER",
          "discountsPercent": "NUMBER",
          "laborPercent": "NUMBER",
          "voidsPercent": "NUMBER"
        }
      ],
      "byLowestLaborPercent": ["SAME_ROW_STRUCTURE"],
      "byLowestDiscountsPercent": ["SAME_ROW_STRUCTURE"],
      "byLowestVoidsPercent": ["SAME_ROW_STRUCTURE"]
    },
    "locationEndpoints": [
      {
        "id": "LOCATION_ID",
        "name": "LOCATION_NAME",
        "shiftq": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/shiftq",
        "sales": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/shiftq/sales"
      }
    ]
  }
}
shiftq:read

ShiftQ Reviews

GET /v1/{groupId}/{locationId}/shiftq/reviews is the only customer-facing Reviews route. Google review-content redistribution is currently blocked before records are read.

{
  "ok": false,
  "error": "provider-content-redistribution-unavailable"
}
shiftq:menu:read

ShiftQ POS Menu Example

{
  "ok": true,
  "version": "v1",
  "resource": "shiftq/pos-menu",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "POS_MENU_REFRESH_DESCRIPTION"
    },
    "syncStatus": {
      "lastStatus": "STATUS_STRING",
      "lastCheckedAt": "ISO_TIMESTAMP",
      "lastSyncedAt": "ISO_TIMESTAMP",
      "fullMenuRewrite": "POLICY_STRING",
      "incrementalBaseUpdates": "POLICY_STRING",
      "stockOverlayRefresh": "CADENCE_STRING"
    },
    "menuMetadata": {
      "restaurantGuid": "POS_RESTAURANT_GUID",
      "lastUpdated": "ISO_TIMESTAMP"
    },
    "menuSnapshot": {
      "lastUpdated": "ISO_TIMESTAMP",
      "lastSynced": "ISO_TIMESTAMP"
    },
    "soldOutItems": {
      "count": "NUMBER",
      "items": [
        { "key": "LOCATION_ID:INDEX:ITEM_NAME", "name": "ITEM_NAME" }
      ]
    }
  }
}
sportsq:read

SportsQ Examples

SportsQ Core / Event Availability

SportsQ Overview, Provider Availability, Packages / Networks, and Events by Date remain the established event-availability resources. Events by Date returns sporting events for the requested date with location-aware viewing options when available.

Provider Availability

GET /v1/GROUP_ID/LOCATION_ID/sportsq/provider

{
  "ok": true,
  "version": "v1",
  "resource": "sportsq/provider",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "data": {
    "location": {
      "groupId": "GROUP_ID",
      "locationId": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "availability": {
      "status": "AVAILABLE",
      "requestedDate": "2026-08-31",
      "effectiveDate": "2026-08-31",
      "freshness": "EXACT_DATE",
      "updatedAt": "ISO_TIMESTAMP",
      "providerCount": 1,
      "channelCount": 1,
      "packageCount": 0,
      "viewingOptionCount": 1
    },
    "providers": [
      {
        "id": "linear-provider",
        "name": "Linear Provider",
        "type": "linear",
        "available": true,
        "availabilityState": "AVAILABLE",
        "lineupId": "LINEUP_ID",
        "market": "MARKET_NAME",
        "channels": [
          { "number": "123", "name": "Sports Network", "type": "network" }
        ]
      }
    ],
    "regionalSportsNetworks": [
      {
        "id": "regional-network",
        "name": "Regional Sports Network",
        "channel": "123"
      }
    ]
  }
}

SportsQ TV Guide

GET /v1/GROUP_ID/LOCATION_ID/sportsq/tv-guide requires sportsq:read and TV Guide enabled at the requested location.

The response combines the location's market-specific local/broadcast lineup, selected viewing package, enabled sports packages and add-ons, and SmartQ's canonical channel corrections. Local affiliates are not derived from package tables, and rows are deduplicated by stable station/channel identity.

{
  "ok": true,
  "resource": "sportsq/tv-guide",
  "data": {
    "locationId": "LOCATION_ID",
    "timezone": "America/New_York",
    "tvGuideEnabled": true,
    "providers": [
      {
        "providerId": "provider-195",
        "name": "DIRECTV",
        "logoUrl": "https://admin.smartq.tv/assets/directv.png",
        "lineups": [
          { "lineupId": "36473D", "role": "regional", "market": "Atlanta, GA" },
          { "lineupId": "2381D", "role": "national", "market": "National" }
        ],
        "viewingPackage": {
          "id": "commercial-xtra",
          "name": "Commercial Xtra Pack",
          "logoUrl": null
        },
        "sportsPackages": [
          { "id": "nflSundayTicket", "name": "NFL Sunday Ticket", "logoUrl": "https://admin.smartq.tv/assets/sportsq/networks/nfl-sunday-ticket.png" }
        ],
        "availableChannels": [
          { "id": "station-466:206", "channelId": "station-466:206", "stationId": "station-466", "channelNumber": "206", "name": "ESPN", "logoUrl": "https://admin.smartq.tv/assets/sportsq/UpdatedNetworks/Providers/Updates/ESPN.png", "logoAvailable": true, "logoStatus": "curated" }
        ],
        "channelsEndpoint": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/sportsq/tv-guide/provider-195/channels",
        "guideEndpoint": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/sportsq/tv-guide/provider-195/guide?date={YYYY-MM-DD}",
        "guideDates": ["2026-09-15", "2026-09-16", "2026-09-17", "2026-09-18", "2026-09-19", "2026-09-20", "2026-09-21"]
      }
    ]
  }
}

providerId is a logical TV provider identifier. Some providers combine underlying regional and national lineups; SmartQ presents them as one provider and exposes lineup metadata for information only. Use one returned guideDates value in guideEndpoint. The required date query is a real YYYY-MM-DD calendar date in the returned location/provider timezone. Programs overlapping any part of that local day are included, including cross-midnight programs. There is no separate range request.

Choose the route by question: /channels is the logical provider channel catalog; availableChannels is the location's effective subset after local lineup, package, add-on, and normalization rules; /guide?date= is actual programming for that date. For the event-specific answer to where a game can be shown at the location, use /sportsq/YYYY-MM-DD and its viewingOptions.

The Programming Guide by Date response returns the logical providerId, informational lineups, date, timezone, canonical channels, and a top-level programs array with channelId, startsAt, endsAt, and title metadata. It contains television programming only—not SportsQ events, teams, leagues, event status, or viewingOptions.

For standard TV providers, shared means logical-provider data without location filtering; it does not bypass SmartQ's canonical channel-number, name, logo, alternate-feed, or business-sports corrections. Regional lineup data takes precedence over duplicate national rows, while national lineups supplement channels and programs. The shared provider responses do not add location-specific package availability flags. Filter the shared guide with availableChannels from the location response.

Channel and guide data for standard TV providers is normalized and shared by logical provider using existing regional and national lineup caches. EverPass availability is location-specific and reflects the venue's connected EverPass account and content schedule. The same endpoint pattern is used, while authorization and schedule lookup remain bound to the selected location.

DIRECTV provider-195 composes the regional/location lineup with the 2381D national supplemental lineup as one logical provider. Regional rows take precedence on overlap; clients do not choose or pin a lineup ID. EverPass is not a conventional numbered lineup and may have no numeric channel position. Its venue-specific streaming/event availability appears through date programming, event matching, and viewingOptions; do not force it into a network-to-number mapping. EverPass guide programs include provider-reported sport, scheduled stopIso/endsAt, and sportsPackageName when recognized.

Channel artwork uses the same canonical SmartQ asset registry as SportsQ Admin. Injected NFL Sunday Ticket, Thursday Night Football, RedZone, and ESPN+ for Business rows reuse the same curated package logos shown in SportsQ Settings. Provider station artwork is sanitized and served from a SmartQ-controlled asset URL. If artwork is unavailable, logoUrl is null, logoAvailable is false, and logoStatus is pending or unavailable. Unavailable artwork has logoReason of processing-failed or no-source; pending artwork has no reason. Available artwork uses canonical or curated. The generic SmartQ mark is a UI-only last resort, not a station logo.

SportsQ TV Guide Provider Channels

GET /v1/GROUP_ID/LOCATION_ID/sportsq/tv-guide/provider-195/channels

{
  "providerId": "provider-195",
  "channels": [
    {
      "id": "station-466:206",
      "channelId": "station-466:206",
      "stationId": "station-466",
      "channelNumber": "206",
      "callSign": "ESPN",
      "name": "ESPN",
      "logoUrl": "https://admin.smartq.tv/assets/sportsq/UpdatedNetworks/Providers/Updates/ESPN.png",
      "logoAvailable": true,
      "logoStatus": "curated"
    }
  ]
}

SportsQ Programming Guide by Date

GET /v1/GROUP_ID/LOCATION_ID/sportsq/tv-guide/provider-195/guide?date=2026-09-17

The result uses the same canonical channel identities and SmartQ-controlled artwork, then adds the selected local date, timezone, nested channel programs, and a flattened programs list. It does not create another feed, cache, worker, or media download.

Packages

GET /v1/GROUP_ID/LOCATION_ID/sportsq/packages returns the established network catalog and this canonical projection:

{
  "ok": true,
  "resource": "sportsq/packages",
  "data": {
    "canonical": {
      "location": {
        "groupId": "GROUP_ID",
        "locationId": "LOCATION_ID"
      },
      "availability": {
        "status": "AVAILABLE",
        "requestedDate": "2026-08-31",
        "effectiveDate": "2026-08-31",
        "freshness": "EXACT_DATE"
      },
      "programmingPackage": {
        "id": "base-package",
        "name": "Base Package",
        "imageUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID"
      },
      "packages": [
        {
          "id": "sports-addon",
          "name": "Sports Add-on",
          "type": "addon",
          "imageUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID",
          "enabled": true
        }
      ],
      "regionalSportsNetworks": []
    }
  }
}

Events by Date

GET /v1/GROUP_ID/LOCATION_ID/sportsq/YYYY-MM-DD requires a real, zero-padded date and never falls back to another day or location.

Example: GET https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/sportsq/2026-08-31

{
  "ok": true,
  "version": "v1",
  "resource": "sportsq/2026-08-31",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "data": {
    "location": {
      "groupId": "GROUP_ID",
      "locationId": "LOCATION_ID",
      "timezone": "IANA_TIMEZONE"
    },
    "date": "2026-08-31",
    "updatedAt": "ISO_TIMESTAMP",
    "health": {
      "schedule": {
        "status": "AVAILABLE",
        "eventCount": 1
      },
      "providerAvailability": {
        "status": "AVAILABLE",
        "requestedDate": "2026-08-31",
        "effectiveDate": "2026-08-31",
        "freshness": "EXACT_DATE",
        "updatedAt": "ISO_TIMESTAMP",
        "providerCount": 1,
        "channelCount": 1,
        "packageCount": 0,
        "viewingOptionCount": 1
      }
    },
    "events": [
      {
        "id": "SPORTSQ_EVENT_ID",
        "name": "Away Team at Home Team",
        "startsAt": "ISO_TIMESTAMP",
        "status": {
          "state": "live",
          "label": "Live",
          "detail": "Second Period",
          "period": 2,
          "clock": "04:10"
        },
        "sport": { "id": "sport-id", "name": "Sport" },
        "league": { "id": "league-id", "name": "League", "abbreviation": "LG", "imageUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID", "logoUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID" },
        "participants": [
          {
            "type": "team",
            "id": "team-id",
            "name": "Home Team",
            "role": "home",
            "imageUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID",
            "logoUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID",
            "score": "10",
            "winner": true
          }
        ],
        "eventImageUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID",
        "imageUrl": "https://api.smartq.tv/v1/assets/sports-logo/sm_ASSET_ID",
        "venue": { "id": "venue-id", "name": "Venue", "city": "City", "state": "ST", "country": "USA", "indoor": false },
        "viewingOptions": [
          {
            "provider": {
              "id": "linear-provider",
              "name": "Linear Provider",
              "type": "linear"
            },
            "network": {
              "id": "sports-network",
              "name": "Sports Network",
              "type": "network"
            },
            "channel": "123",
            "available": true,
            "broadcastTier": "national",
            "broadcastPriority": 2,
            "logoUrl": null
          }
        ]
      }
    ]
  }
}

Event IDs are stable SportsQ identifiers. They do not currently imply a separate event-detail Customer API route.

Schedule health and venue provider-availability health are reported separately. A valid event schedule with missing location viewing data returns PROVIDER_DATA_UNAVAILABLE, not a misleading fully healthy state.

viewingOptions contains only sources available to this location. Use the lowest broadcastPriority: regional (1), national (2), package/supplemental slot (3), streaming (4). Each option retains provider, network, and channel identity for same-tier ties. For EverPass, provider.name remains EverPass while network.name identifies the provider-reported sports package when recognized; unmatched events retain provider sport and scheduled end time. DETSN/DETSPN resolves to Detroit Sports Network where eligible. logoUrl is a canonical SmartQ URL or null; team logoUrl, league logoUrl, and event imageUrl use the same canonical asset family. Canonical asset URLs are immutable and cacheable for one year. This does not describe what is currently assigned to a television.

Schedule status values: AVAILABLE, SCHEDULE_DATA_UNAVAILABLE. Provider status values: AVAILABLE, PROVIDER_DATA_UNAVAILABLE, PROVIDER_DATA_STALE, PROVIDER_DATA_PARTIAL. Freshness values: EXACT_DATE, STALE_DATE, MISSING.

Existing integrations can continue using every supported SportsQ route without code changes. SportsQ TV Guide is an additive resource family.

SportsQ Overview

GET /v1/GROUP_ID/LOCATION_ID/sportsq supports an optional ?date=YYYY-MM-DD query. Its established response includes location, date, refresh, settings, selections, network catalog, and guide data. New integrations should use the focused resources above instead of depending on implementation fields.

matriq:read

MatriQ Overview Example

{
  "ok": true,
  "version": "v1",
  "resource": "matriq",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "gateway": { "cadence": "CADENCE_STRING" },
      "devices": { "cadence": "CADENCE_STRING" },
      "providerAvailable": { "cadence": "CADENCE_STRING", "description": "PROVIDER_REFRESH_DESCRIPTION" },
      "aiScheduler": { "cadence": "CADENCE_STRING", "description": "AI_SCHEDULER_REFRESH_DESCRIPTION" }
    },
    "summary": {
      "deviceIds": ["DEVICE_ID"],
      "providerCount": "NUMBER",
      "aiSchedulerPublished": "BOOLEAN",
      "aiSchedulerRunning": "BOOLEAN"
    }
  }
}
Existing resource

Provider Availability

This established shape is retained for existing integrations. New integrations should use the provider-neutral Provider Availability, Packages / Networks, and Events by Date resources. Internal storage and device fields are intentionally omitted.

{
  "ok": true,
  "version": "v1",
  "resource": "providerAvailable",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "businessDate": {
      "active": "YYYYMMDD",
      "calendarDate": "YYYY-MM-DD",
      "timezone": "IANA_TIMEZONE"
    },
    "providers": [
      {
        "providerKey": "PROVIDER_KEY",
        "providerLabel": "PROVIDER_LABEL",
        "providerLogo": "https://admin.smartq.tv/assets/directv.png"
      }
    ],
    "providersAvailable": [
      {
        "eventId": "EVENT_ID",
        "title": "EVENT_TITLE",
        "league": "LEAGUE_NAME",
        "leagueLogo": "LEAGUE_LOGO_URL",
        "homeTeam": "HOME_TEAM_NAME",
        "awayTeam": "AWAY_TEAM_NAME",
        "homeLogo": "HOME_TEAM_LOGO_URL",
        "awayLogo": "AWAY_TEAM_LOGO_URL",
        "providerLabel": "PROVIDER_LABEL",
        "providerLogo": "https://admin.smartq.tv/assets/directv.png",
        "channelNumber": "CHANNEL_NUMBER"
      }
    ]
  }
}
matriq:read

Auto Scheduler Example

A scheduled Detroit Sports Network selection uses the same canonical network ID and SmartQ-hosted logo as the SportsQ viewing option. Channel 663-3 remains the tuneable channel; broadcastTier is regional and broadcastPriority is 1. Other scheduled channels are unchanged.

{
  "ok": true,
  "version": "v1",
  "resource": "matriq/aiScheduler",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "AI_SCHEDULER_REFRESH_DESCRIPTION"
    },
    "deviceIds": ["DEVICE_ID"],
    "currentBusinessDay": "YYYY-MM-DD",
    "statusUpdatedAt": "ISO_TIMESTAMP",
    "publishedDraftUpdatedAt": "ISO_TIMESTAMP",
    "status": {
      "running": "BOOLEAN",
      "published": "BOOLEAN",
      "draftExists": "BOOLEAN",
      "runtime": {
        "emergencyStopActive": "BOOLEAN",
        "lastStartAt": "ISO_TIMESTAMP_OR_NULL",
        "lastStopAt": "ISO_TIMESTAMP_OR_NULL"
      }
    },
    "publishedDraft": {
      "businessDay": "YYYY-MM-DD",
      "published": "BOOLEAN",
      "status": "STATUS_STRING",
      "draft": {
        "plans": [
          { "events": [{ "title": "Detroit Tigers at Toronto Blue Jays", "chosenChannelId": "detroit-sports-network", "channels": [{ "channelId": "detroit-sports-network", "channelNumber": "663-3", "name": "Detroit Sports Network", "networkId": "detroit-sports-network", "networkName": "Detroit Sports Network", "logoUrl": "https://api.smartq.tv/v1/assets/sports-logo/ASSET_ID", "broadcastTier": "regional", "broadcastPriority": 1 }] }] }
        ]
      }
    },
    "actions": {
      "emergencyStop": {
        "label": "Emergency Stop Auto Scheduler",
        "method": "POST",
        "endpoint": "https://api.smartq.tv/v1/GROUP_ID/LOCATION_ID/matriq/aiScheduler/emergency-stop",
        "scope": "matriq:ai-scheduler:stop",
        "description": "ACTION_DESCRIPTION"
      }
    }
  }
}
matriq:ai-scheduler:stop

Emergency Stop Example

{
  "ok": true,
  "version": "v1",
  "resource": "matriq/aiScheduler/emergency-stop",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "status": "queued_or_applied_or_failed",
    "deviceId": "DEVICE_ID",
    "commandId": "COMMAND_ID",
    "requestedAt": "ISO_TIMESTAMP",
    "reason": "REASON_STRING",
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "AI_SCHEDULER_REFRESH_DESCRIPTION"
    }
  }
}
campaigns:read

Campaigns Example

{
  "ok": true,
  "version": "v1",
  "resource": "campaigns",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "CAMPAIGN_REFRESH_DESCRIPTION"
    },
    "campaigns": [
      {
        "id": "CAMPAIGN_ID",
        "name": "CAMPAIGN_NAME",
        "status": "STATUS_STRING",
        "startsAt": "ISO_TIMESTAMP",
        "endsAt": "ISO_TIMESTAMP"
      }
    ],
    "deviceStatus": {
      "healthy": "NUMBER",
      "warning": "NUMBER",
      "offline": "NUMBER"
    }
  }
}
orderboard:read

OrderBoard Example

{
  "ok": true,
  "version": "v1",
  "resource": "orderboard",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "refresh": {
      "cadence": "CADENCE_STRING",
      "description": "ORDERBOARD_REFRESH_DESCRIPTION"
    },
    "status": "coming_soon",
    "message": "ORDERBOARD_STATUS_MESSAGE"
  }
}
bevq:read

BevQ Location Menu

GET /v1/GROUP_ID/bevq returns group availability metadata. GET /v1/GROUP_ID/LOCATION_ID/bevq returns location status and the menu endpoint. Fetch the complete /bevq/menu resource from a trusted customer backend and cache by the returned ETag. No widget ID or separate POS join is required.

{
  "ok": true,
  "version": "v1",
  "resource": "bevq/menu",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "generatedAt": "ISO_TIMESTAMP",
  "data": {
    "location": {
      "id": "LOCATION_ID",
      "name": "LOCATION_NAME",
      "timezone": "IANA_TIMEZONE"
    },
    "menu": {
      "updatedAt": "ISO_TIMESTAMP",
      "revision": "MENU_REVISION",
      "sourceHealth": { "pos": "current", "lastPosSyncAt": "ISO_TIMESTAMP" },
      "sectionCount": 1,
      "itemCount": 1,
      "sections": [{
        "id": "on-tap",
        "name": "On Tap",
        "description": "Draft beer",
        "sortOrder": 0,
        "enabled": true,
        "itemCount": 1,
        "updatedAt": "ISO_TIMESTAMP",
        "items": [{
          "id": "CANONICAL_BEVQ_ITEM_ID",
          "type": "beer",
          "name": "Example IPA",
          "displayName": "House IPA",
          "brand": { "id": "CANONICAL_BRAND_ID", "name": "Example Brewery", "type": "brewery", "imageUrl": "PUBLIC_BRAND_IMAGE_URL" },
          "style": "American IPA",
          "category": "beer",
          "abv": 7,
          "ibu": 55,
          "country": "USA",
          "region": "Michigan",
          "description": "Aromatic India pale ale.",
          "imageUrl": "PUBLIC_ITEM_IMAGE_URL",
          "posItemId": "POS_ITEM_ID",
          "posGroupId": "POS_GROUP_ID",
          "mapped": true,
          "available": true,
          "sizes": [{ "id": "pint", "name": "16 oz", "ounces": 16, "price": 6.5, "currency": "USD", "available": true }],
          "sortOrder": 0,
          "sectionId": "on-tap",
          "updatedAt": "ISO_TIMESTAMP"
        }]
      }]
    }
  }
}

The API preserves configured section and item order. Priced size rows use the location's authoritative ISO 4217 POS currency; currency is not guessed from locale or symbols and is not limited to USD. brand is optional, and its id, name, type, and imageUrl may be absent independently.

Store the response ETag and echo it exactly in If-None-Match. SmartQ also accepts the equivalent weak validator, a matching validator list, and * for an existing menu. Treat 304 Not Modified with its empty body as a successful unchanged-menu result.

sourceHealth.pos is current after a successful persisted POS reconciliation with no later failure, stale after a later failed attempt, and unknown before a successful timestamp exists. It is not based on an arbitrary age threshold, and lastPosSyncAt is not a universal per-price freshness clock.

Server-to-server menu update event

Configure an HTTPS destination for an active customer-managed client_credentials application with bevq:read in SmartQ Admin's Developer API Access area. Location applications cover their authorized location. Group applications may cover all authorized locations or an explicit selected set. Whole-group coverage automatically includes future locations authorized to that application; selected-location coverage never broadens silently. SmartQ Support-managed bearer credentials cannot own new destinations.

bevq.menu.updated is a small, location-specific signed prompt for the customer's backend to re-fetch this menu with its bearer and ETag; it never contains a combined group menu, the complete menu, or credentials. Keep a scheduled conditional reconciliation job as a fallback.

{
  "eventId": "STABLE_EVENT_ID",
  "eventType": "bevq.menu.updated",
  "occurredAt": "ISO_TIMESTAMP",
  "groupId": "GROUP_ID",
  "locationId": "LOCATION_ID",
  "revision": "MENU_REVISION",
  "resource": "/v1/GROUP_ID/LOCATION_ID/bevq/menu"
}

Verify X-SmartQ-Signature against the exact raw request body before parsing, validate X-SmartQ-Timestamp, and deduplicate by X-SmartQ-Event-Id. SmartQ retries eligible failures at most five attempts. See the complete BevQ webhook reference for the exact wire contract and Node.js, Python, and PHP examples.

ShiftQ Reviews

Reviews uses the canonical /shiftq/reviews route and shiftq:read. Google review-content redistribution is currently policy-gated (409) before review records are read.

Complete ShiftQ Reviews reference