Vendasta Multi-Location Analytics API

Analytics service for multi-location brands and franchises, rolling product performance up across the locations under one partner.

OpenAPI Specification

vendasta-multi-location-analytics-openapi.json Raw ↑
{
  "components": {
    "schemas": {
      "AlignmentPeriodCalendar": {
        "default": "UNSPECIFIED",
        "description": "- UNSPECIFIED: No value has been specified.\n - CALENDAR_MINUTE: Align at minute boundaries\n - CALENDAR_HOUR: Align at hour boundaries\n - CALENDAR_DAY: Align at day boundaries\n - CALENDAR_WEEK: Align at week boundaries (where beginning of the week is monday)\n - CALENDAR_MONTH: Align at month boundaries\n - CALENDAR_QUARTER: Align at quarter boundaries\n - CALENDAR_YEAR: Align at year boundaries",
        "enum": [
          "UNSPECIFIED",
          "CALENDAR_MINUTE",
          "CALENDAR_HOUR",
          "CALENDAR_DAY",
          "CALENDAR_WEEK",
          "CALENDAR_MONTH",
          "CALENDAR_QUARTER",
          "CALENDAR_YEAR"
        ],
        "type": "string"
      },
      "FieldFilterOperatorFunction": {
        "default": "NONE",
        "description": "- NONE: No function will be applied to the values\n - ANY: Any value in the list must pass the filter\n - ALL: All values in the list must pass the filter",
        "enum": [
          "NONE",
          "ANY",
          "ALL"
        ],
        "type": "string"
      },
      "GroupByDimension": {
        "properties": {
          "dimension": {
            "type": "string"
          },
          "limitDimension": {
            "$ref": "#/components/schemas/GroupByLimit"
          }
        },
        "title": "Dimension specifies which column to group by",
        "type": "object"
      },
      "GroupByExcludeCombination": {
        "properties": {
          "dimensions": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "title": "ExcludeCombination allows a user using ROLLUP OR CUBE to exclude a combination from the result\nExample: CUBE (pid, agid) returns the combinations ((pid, agid), (pid), (agid), ()). Providing\nExcludeCombination{dimensions=[pid, agid]} would return the combinations ((pid), (agid), ())",
        "type": "object"
      },
      "GroupByLimit": {
        "properties": {
          "dimension": {
            "type": "string"
          },
          "limit": {
            "format": "int64",
            "type": "string"
          },
          "order": {
            "$ref": "#/components/schemas/v1Order"
          }
        },
        "title": "Limit reduces the number of dimensions to the specified amount",
        "type": "object"
      },
      "MeasureAggregate": {
        "description": "Aggregate applies a SQL aggregation function to a measure field.",
        "properties": {
          "aggOp": {
            "$ref": "#/components/schemas/MeasureAggregateOperator"
          },
          "alias": {
            "description": "Optional. An alias for the aggregated result in the response schema.\nUseful when you have multiple aggregates on the same measure with different filters.",
            "type": "string"
          },
          "filter": {
            "$ref": "#/components/schemas/v1Filter"
          },
          "measure": {
            "description": "The measure field to aggregate. Must be one of the metric's available measures.",
            "type": "string"
          }
        },
        "type": "object"
      },
      "MeasureAggregateOperator": {
        "default": "AVG",
        "description": " - AVG: Calculate the average value.\n - COUNT: Count the number of rows.\n - SUM: Sum all values.\n - MIN: Get the minimum value.\n - MAX: Get the maximum value.\n - COUNT_DISTINCT: Count unique values.\n - ARRAY_AGG: Collect all values into an array.",
        "enum": [
          "AVG",
          "COUNT",
          "SUM",
          "MIN",
          "MAX",
          "COUNT_DISTINCT",
          "ARRAY_AGG"
        ],
        "type": "string"
      },
      "OrderByOrderColumn": {
        "properties": {
          "column": {
            "title": "Either a dimension or a measure to order by",
            "type": "string"
          },
          "order": {
            "$ref": "#/components/schemas/v1Order"
          }
        },
        "type": "object"
      },
      "PropertyPIITag": {
        "default": "PROPERTY_PII_TAG_CLEAN",
        "description": "PIITag defines potential PII tags.\n\n - PROPERTY_PII_TAG_CLEAN: clean means the data is not PII or PD.\n - PROPERTY_PII_TAG_PII: PII means Personally Identifiable Information. It is information that can be used to retrieve personal data, such as IAM user ID.\n - PROPERTY_PII_TAG_PD: PD means personal data, such as name, email and address. They are sensitive data we need to protect in our system.",
        "enum": [
          "PROPERTY_PII_TAG_CLEAN",
          "PROPERTY_PII_TAG_PII",
          "PROPERTY_PII_TAG_PD"
        ],
        "type": "string"
      },
      "protobufAny": {
        "additionalProperties": {},
        "properties": {
          "@type": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "rpcStatus": {
        "properties": {
          "code": {
            "format": "int32",
            "type": "integer"
          },
          "details": {
            "items": {
              "$ref": "#/components/schemas/protobufAny"
            },
            "type": "array"
          },
          "message": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "v1Alignment": {
        "default": "ALIGN_NONE",
        "description": " - ALIGN_NONE: No alignment.\n - ALIGN_DELTA: Align and convert to delta metric type. This alignment is valid\nfor delta metrics. Aligning an existing delta metric to a delta metric\nrequires that the alignment period be increased. The value type of the\nresult is the same as the value type of the input.\n\nOne can think of this aligner as a rate but without time units; that\nis, the output is conceptually (second_point - first_point).\n - ALIGN_INTERPOLATE: Align by interpolating between adjacent points around the\nperiod boundary. This alignment is valid for gauge\nmetrics with numeric values. The value type of the result is the same\nas the value type of the input.\n - ALIGN_NEXT_OLDER: Align by shifting the oldest data point before the period\nboundary to the boundary. This alignment is valid for gauge\nmetrics. The value type of the result is the same as the\nvalue type of the input.\n - ALIGN_EXACT: Align by using data points that fall on the same UTC day of the period boundary.\nThis alignment is valid for daily gauge metrics.\nThe value type of the result is the same as the value type of the input.\n - ALIGN_CUSTOM: Allows the user to specify custom alignment logic, allowing the query to make more complex decisions on which\ntime/date bucket(s) a row should be placed in.\nThis is useful when your table has multiple columns that need to be considered when bucketing rows into time\nbuckets, such as a created and deleted date.\nThe custom aligner allows you to bucket these rows based on their status at one of the bucket boundaries or\nwithin the bucket.",
        "enum": [
          "ALIGN_NONE",
          "ALIGN_DELTA",
          "ALIGN_INTERPOLATE",
          "ALIGN_NEXT_OLDER",
          "ALIGN_EXACT",
          "ALIGN_CUSTOM"
        ],
        "type": "string"
      },
      "v1AlignmentPeriod": {
        "properties": {
          "calendar": {
            "$ref": "#/components/schemas/AlignmentPeriodCalendar"
          },
          "duration": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "v1BusinessResourceId": {
        "description": "A single business location identified by its account group ID.",
        "properties": {
          "businessId": {
            "description": "The account group ID of the business (e.g., \"AG-XXXXXXXX\").",
            "type": "string"
          }
        },
        "type": "object"
      },
      "v1CompositeFilter": {
        "description": "A filter that merges multiple other filters using the given operator.",
        "properties": {
          "filters": {
            "description": "The list of filters to combine.\nMust contain at least one filter.",
            "items": {
              "$ref": "#/components/schemas/v1Filter"
            },
            "type": "array"
          },
          "op": {
            "$ref": "#/components/schemas/v1CompositeFilterOperator"
          }
        },
        "type": "object"
      },
      "v1CompositeFilterOperator": {
        "default": "OPERATOR_UNSPECIFIED",
        "description": "A composite filter operator.\n\n - OPERATOR_UNSPECIFIED: Unspecified. This value must not be used.\n - AND: The results are required to satisfy each of the combined filters.\n - OR: The results are required to satisfy at least one of the combined filters.",
        "enum": [
          "OPERATOR_UNSPECIFIED",
          "AND",
          "OR"
        ],
        "type": "string"
      },
      "v1CustomAlignerConfig": {
        "properties": {
          "alignmentBucketFilter": {
            "$ref": "#/components/schemas/v1Filter"
          },
          "skipFilteringEntitiesToDateRange": {
            "title": "Whether to skip filtering entities by the time column on the table to the provided date_range.\nUsage: date_range is used for both filtering entities and defining the time period to aggregate over.\nIf true, date_range will only be used to define the aggregation time range (i.e. the last year)\nIf false, date_range will be used for BOTH filtering entities AND the aggregation time range",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "v1DateRange": {
        "properties": {
          "end": {
            "format": "date-time",
            "title": "`end` is implicitly inclusive",
            "type": "string"
          },
          "endExclusive": {
            "format": "date-time",
            "type": "string"
          },
          "start": {
            "format": "date-time",
            "title": "`start` is implicitly inclusive",
            "type": "string"
          },
          "startExclusive": {
            "format": "date-time",
            "type": "string"
          }
        },
        "title": "Specifies a range of time for analytics queries",
        "type": "object"
      },
      "v1FieldFilter": {
        "properties": {
          "comparisonField": {
            "title": "A field to compare the dimension to",
            "type": "string"
          },
          "dimension": {
            "description": "The field to filter by.",
            "type": "string"
          },
          "operator": {
            "$ref": "#/components/schemas/v1FieldFilterOperator"
          },
          "operatorFunction": {
            "$ref": "#/components/schemas/FieldFilterOperatorFunction"
          },
          "operatorFunctionOnField": {
            "title": "Whether to apply the specified operator function to the field, or the value involved in the filter",
            "type": "boolean"
          },
          "value": {
            "$ref": "#/components/schemas/v1TypedValue"
          }
        },
        "title": "A filter on a specific field",
        "type": "object"
      },
      "v1FieldFilterOperator": {
        "default": "OPERATOR_UNSPECIFIED",
        "description": " - OPERATOR_UNSPECIFIED: Unspecified. This value must not be used.\n - LESS_THAN: Less than. Requires that the field come first in `order_by`.\n - LESS_THAN_OR_EQUAL: Less than or equal. Requires that the field come first in `order_by`.\n - GREATER_THAN: Greater than. Requires that the field come first in `order_by`.\n - GREATER_THAN_OR_EQUAL: Greater than or equal. Requires that the field come first in\n`order_by`.\n - EQUAL: Equal.\n - OVERLAP: Overlap (have elements in common). Field and values must be lists.\n - NOT_EQUAL: Not Equal.",
        "enum": [
          "OPERATOR_UNSPECIFIED",
          "LESS_THAN",
          "LESS_THAN_OR_EQUAL",
          "GREATER_THAN",
          "GREATER_THAN_OR_EQUAL",
          "EQUAL",
          "OVERLAP",
          "NOT_EQUAL"
        ],
        "type": "string"
      },
      "v1Filter": {
        "properties": {
          "compositeFilter": {
            "$ref": "#/components/schemas/v1CompositeFilter"
          },
          "fieldFilter": {
            "$ref": "#/components/schemas/v1FieldFilter"
          },
          "unaryFilter": {
            "$ref": "#/components/schemas/v1UnaryFilter"
          }
        },
        "title": "A filter",
        "type": "object"
      },
      "v1GetAvailableMetricsRequest": {
        "description": "Request to retrieve the catalog of available analytics metrics for the given resources.",
        "properties": {
          "partnerId": {
            "description": "Required. The partner ID.",
            "type": "string"
          },
          "resourceIds": {
            "description": "Required. At least one resource ID.",
            "items": {
              "$ref": "#/components/schemas/v1ResourceId"
            },
            "type": "array"
          }
        },
        "required": [
          "resourceIds",
          "partnerId"
        ],
        "title": "GetAvailableMetricsRequest",
        "type": "object"
      },
      "v1GetAvailableMetricsResponse": {
        "description": "The catalog of available analytics metrics with their schemas.",
        "properties": {
          "metrics": {
            "description": "Output only. All available metrics with their schemas. Use this to discover valid metric names,\nmeasures, and dimensions for building QueryMetricsRequest messages.",
            "items": {
              "$ref": "#/components/schemas/v1MetricDescription"
            },
            "readOnly": true,
            "type": "array"
          }
        },
        "title": "GetAvailableMetricsResponse",
        "type": "object"
      },
      "v1GroupBy": {
        "properties": {
          "dimension": {
            "items": {
              "$ref": "#/components/schemas/GroupByDimension"
            },
            "title": "A list of dimensions to group by",
            "type": "array"
          },
          "excludeCombination": {
            "items": {
              "$ref": "#/components/schemas/GroupByExcludeCombination"
            },
            "title": "Supports excluding a list of combinations",
            "type": "array"
          },
          "groupByOperator": {
            "$ref": "#/components/schemas/v1GroupByOperator"
          }
        },
        "title": "Group By is a reducer for aggregating rows into the given dimensions",
        "type": "object"
      },
      "v1GroupByOperator": {
        "default": "OPERATOR_GROUP_BY",
        "enum": [
          "OPERATOR_GROUP_BY",
          "OPERATOR_ROLLUP",
          "OPERATOR_CUBE"
        ],
        "title": "A Group By Operator",
        "type": "string"
      },
      "v1GroupResourceId": {
        "description": "A group of businesses identified by a hierarchical path.\nGroups allow querying aggregate analytics across multiple business locations.",
        "properties": {
          "groupPathNodes": {
            "description": "The ordered list of group path nodes from root to leaf (e.g., [\"root-node\", \"child-node\"]).",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "v1JWTResourceId": {
        "description": "A JWT that encodes a specific user/business combination for authenticated end-user queries.",
        "properties": {
          "jwt": {
            "description": "A signed JWT containing partner_id and business_id claims.",
            "type": "string"
          }
        },
        "type": "object"
      },
      "v1MarketId": {
        "description": "One or more market IDs. Markets are geographic or logical groupings of businesses within a partner.\nWhen market_ids is empty, the query returns data across ALL markets for the partner (partner-wide query).",
        "properties": {
          "marketIds": {
            "description": "The list of market IDs to query. An empty list means all markets for the partner.",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "v1Measure": {
        "description": "Measure selects or aggregates a field from the metric's available measures.\nUse GetAvailableMetrics to discover which measure names are valid for each metric.\n\nExample: Select a raw measure\n{\"measure\": \"scaled_stars\"}\n\nExample: Aggregate a measure\n{\"aggregate\": {\"measure\": \"scaled_stars\", \"agg_op\": \"AVG\"}}\n\nExample: Count distinct values with an alias\n{\"aggregate\": {\"measure\": \"account_group_id\", \"agg_op\": \"COUNT_DISTINCT\", \"alias\": \"unique_businesses\"}}",
        "properties": {
          "aggregate": {
            "$ref": "#/components/schemas/MeasureAggregate"
          },
          "measure": {
            "title": "Select a measure field as-is without aggregation. Example: \"scaled_stars\"",
            "type": "string"
          }
        },
        "type": "object"
      },
      "v1MetricDescription": {
        "description": "Description of a queryable analytics metric, including its available measures, dimensions, and time field.",
        "properties": {
          "description": {
            "description": "Output only. A human-readable description of what this metric measures.",
            "readOnly": true,
            "type": "string"
          },
          "dimensions": {
            "items": {
              "type": "string"
            },
            "readOnly": true,
            "title": "Output only. The dimension fields available for this metric. These can be used in QueryMetricsRequest.group_by\nand QueryMetricsRequest.filter. Examples: \"source_id\", \"rating\", \"account_group_id\"",
            "type": "array"
          },
          "measures": {
            "items": {
              "type": "string"
            },
            "readOnly": true,
            "title": "Output only. The measure fields available for this metric. These can be used in QueryMetricsRequest.measures\nfor selection or aggregation. Examples: \"scaled_stars\", \"review_count\", \"likes\"",
            "type": "array"
          },
          "name": {
            "readOnly": true,
            "title": "Output only. The unique identifier for this metric. Pass this as QueryMetricsRequest.metric_name.\nExamples: \"reviews\", \"activation_counts\", \"facebook_post_stats\"",
            "type": "string"
          },
          "timeField": {
            "description": "Output only. The primary time field used for date range filtering and time alignment.\nThis is the field that alignment_period and time_range operate on.",
            "readOnly": true,
            "type": "string"
          }
        },
        "title": "MetricDescription",
        "type": "object"
      },
      "v1MetricResult": {
        "description": "A single row of metric data with dimension value, measure values, and optional nested results.",
        "properties": {
          "dimension": {
            "description": "Output only. The value of the dimension for this row (e.g., a date string, source ID, or rating value).\nWhen alignment is used, the outermost dimension is the time bucket start timestamp.",
            "readOnly": true
          },
          "measures": {
            "description": "Output only. The measure values for this row, in the same order as measures_schema.properties.\nEach value corresponds to the property at the same index in the schema.",
            "items": {
              "type": "object"
            },
            "readOnly": true,
            "type": "array"
          },
          "results": {
            "$ref": "#/components/schemas/v1Metrics"
          }
        },
        "title": "MetricResult",
        "type": "object"
      },
      "v1Metrics": {
        "description": "A list of metric result rows.",
        "properties": {
          "metrics": {
            "items": {
              "$ref": "#/components/schemas/v1MetricResult"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "v1Order": {
        "default": "ORDER_ASC",
        "enum": [
          "ORDER_ASC",
          "ORDER_DESC"
        ],
        "type": "string"
      },
      "v1OrderBy": {
        "properties": {
          "orderBy": {
            "items": {
              "$ref": "#/components/schemas/OrderByOrderColumn"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "v1QueryMetricsRequest": {
        "description": "Request to query analytics metrics for multi-location businesses with flexible measures, dimensions, time alignment, filtering, grouping, and pagination.",
        "properties": {
          "alignment": {
            "$ref": "#/components/schemas/v1Alignment"
          },
          "alignmentPeriod": {
            "$ref": "#/components/schemas/v1AlignmentPeriod"
          },
          "cursor": {
            "description": "Optional. Pagination cursor from a previous response's ResourceMetricResult.cursor.\nPass an empty string or omit to start from the beginning.",
            "type": "string"
          },
          "customAligner": {
            "$ref": "#/components/schemas/v1CustomAlignerConfig"
          },
          "dateRange": {
            "$ref": "#/components/schemas/v1DateRange"
          },
          "filter": {
            "$ref": "#/components/schemas/v1Filter"
          },
          "groupBy": {
            "$ref": "#/components/schemas/v1GroupBy"
          },
          "limit": {
            "description": "Optional. Maximum number of result rows to return. 0 means no limit.\nUse with order_by for \"top N\" queries (e.g., top 10 businesses by review count).",
            "format": "int64",
            "type": "string"
          },
          "measures": {
            "description": "Optional. The measures to select or aggregate from the metric.\nEach metric has a set of available measures (returned by GetAvailableMetrics).\nIf omitted, all default measures for the metric are returned.\nUse Measure.measure for raw selection (e.g., \"scaled_stars\") or\nMeasure.aggregate for aggregations (e.g., AVG of \"scaled_stars\").",
            "items": {
              "$ref": "#/components/schemas/v1Measure"
            },
            "type": "array"
          },
          "metricName": {
            "title": "Required. The name of the metric to query. Must be one of the names returned by GetAvailableMetrics.\nExamples: \"reviews\", \"activation_counts\", \"facebook_post_stats\", \"net_promoter_score\"",
            "type": "string"
          },
          "orderBy": {
            "$ref": "#/components/schemas/v1OrderBy"
          },
          "partnerId": {
            "description": "Required. The partner ID to scope the query to. All queries are scoped to a single partner.",
            "type": "string"
          },
          "resourceIds": {
            "description": "Required. At least one resource ID to scope the query to. Multiple resource IDs of the same type\ncan be provided to query across multiple businesses, groups, or markets in a single call.",
            "items": {
              "$ref": "#/components/schemas/v1ResourceId"
            },
            "type": "array"
          },
          "timeRange": {
            "$ref": "#/components/schemas/v1DateRange"
          }
        },
        "required": [
          "partnerId",
          "metricName",
          "resourceIds"
        ],
        "title": "QueryMetricsRequest",
        "type": "object"
      },
      "v1QueryMetricsResponse": {
        "description": "Response containing analytics metric results for each requested resource.",
        "properties": {
          "metricResults": {
            "description": "Output only. Results for each requested resource, in the same order as the request's resource_ids.",
            "items": {
              "$ref": "#/components/schemas/v1ResourceMetricResult"
            },
            "readOnly": true,
            "type": "array"
          }
        },
        "title": "QueryMetricsResponse",
        "type": "object"
      },
      "v1ResourceId": {
        "description": "ResourceId identifies the scope of a query. Exactly one resource type must be set.\nEach resource type determines what data is returned and how it is aggregated.",
        "properties": {
          "businessId": {
            "$ref": "#/components/schemas/v1BusinessResourceId"
          },
          "groupId": {
            "$ref": "#/components/schemas/v1GroupResourceId"
          },
          "jwtId": {
            "$ref": "#/components/schemas/v1JWTResourceId"
          },
          "marketId": {
            "$ref": "#/components/schemas/v1MarketId"
          },
          "salesTeam": {
            "$ref": "#/components/schemas/v1SalesTeam"
          }
        },
        "type": "object"
      },
      "v1ResourceMetricResult": {
        "description": "Analytics result for a single resource, including data, schemas, and pagination cursor.",
        "properties": {
          "cursor": {
            "description": "Output only. Pagination cursor. Pass this value as QueryMetricsRequest.cursor to fetch the next page.\nEmpty when there are no more results.",
            "readOnly": true,
            "type": "string"
          },
          "dimensionsSchema": {
            "$ref": "#/components/schemas/vendastatypesSchema"
          },
          "explodedMetrics": {
            "$ref": "#/components/schemas/v1QueryMetricsResponse"
          },
          "measuresSchema": {
            "$ref": "#/components/schemas/vendastatypesSchema"
          },
          "metrics": {
            "$ref": "#/components/schemas/v1Metrics"
          },
          "resourceId": {
            "$ref": "#/components/schemas/v1ResourceId"
          }
        },
        "title": "ResourceMetricResult",
        "type": "object"
      },
      "v1SalesTeam": {
        "description": "One or more sales team IDs for querying analytics scoped to sales team assignments.",
        "properties": {
          "salesTeamIds": {
            "description": "The list of sales team IDs to query.",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "v1TypedValue": {
        "description": "A message that can hold any of the supported value types.",
        "properties": {
          "value": {
            "title": "the value of the field"
          },
          "valueType": {
            "$ref": "#/components/schemas/vendastatypesPropertyType"
          }
        },
        "type": "object"
      },
      "v1UnaryFilter": {
        "properties": {
          "dimension": {
            "description": "The field to which to apply the operator.",
            "type": "string"
          },
          "op": {
            "$ref": "#/components/schemas/v1UnaryFilterOperator"
          }
        },
        "title": "A filter with a single operand",
        "type": "object"
      },
      "v1UnaryFilterOperator": {
        "default": "OPERATOR_UNSPECIFIED",
        "description": "A unary operator.\n\n - OPERATOR_UNSPECIFIED: Unspecified. This value must not be used.\n - IS_NAN: Test if a field is equal to NaN.\n - IS_NULL: Test if an expression evaluates to Null.\n - IS_NOT_NULL: Test if an expression evaluates to Not Null.",
        "enum": [
          "OPERATOR_UNSPECIFIED",
          "IS_NAN",
          "IS_NULL",
          "IS_NOT_NULL"
        ],
        "type": "string"
      },
      "vendastatypesProperty": {
        "properties": {
          "description": {
            "title": "Description of this property",
            "type": "string"
          },
          "name": {
            "title": "Unique identifier for this property. Must be in snake case format.\nExample(s): account_group_id, listing_id, company_name",
            "type": "string"
          },
          "piiTag": {
            "$ref": "#/components/schemas/PropertyPIITag"
          },
          "properties": {
            "description": "Can only be specified if the Type supplied is a STRUCT.\nIs the schema of the structured property.",
            "items": {
              "$ref": "#/components/schemas/vendastatypesProperty"
            },
            "type": "array"
          },
          "repeated": {
            "description": "Indicates if the field is repeated.",
            "type": "boolean"
          },
          "type": {
            "$ref": "#/components/schemas/vendastatypesPropertyType"
          }
        },
        "title": "Property defines a single property for a schema",
        "type": "object"
      },
      "vendastatypesPropertyType": {
        "default": "PROPERTY_TYPE_STRING",
        "enum": [
          "PROPERTY_TYPE_STRING",
          "PROPERTY_TYPE_INT64",
          "PROPERTY_TYPE_DOUBLE",
          "PROPERTY_TYPE_BOOL",
          "PROPERTY_TYPE_TIMESTAMP",
          "PROPERTY_TYPE_GEOPOINT",
          "PROPERTY_TYPE_STRUCT",
          "PROPERTY_TYPE_BYTES"
        ],
        "type": "string"
      },
      "vendastatypesSchema": {
        "properties": {
          "properties": {
            "items": {
              "$ref": "#/components/schemas/vendastatypesProperty"
            },
            "type": "array"
          }
        },
        "title": "Schema describes the structure of data in a storage-agnostic way",
        "type": "object"
      }
    },
    "securitySchemes": {
      "OAuth2": {
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://sso-api-prod.apigateway.co/oauth2/auth",
            "scopes": {
              "business-app": "Allows the application to manage all features of Business App"
            },
            "tokenUrl": "https://sso-api-prod.apigateway.co/oauth2/token"
          }
        },
        "type": "oauth2"
      }
    }
  },
  "info": {
    "title": "Multi-Location Analytics",
    "version": "1.16.1"
  },
  "openapi": "3.0.0",
  "paths": {
    "/v1/multi-location-analytics/available-metrics": {
      "post": {
        "description": "The catalog is filtered by audience tier derived from the resource shape:\n  - BusinessResourceId or JWTResourceId -\u003e SMB-tier only\n  - GroupResourceId, MarketId, or SalesTeam -\u003e SMB + Partner tiers\n\nMixing Business with Market/Group/SalesTeam in one request returns InvalidArgument.",
        "operationId": "AnalyticsService_GetAvailableMetrics",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/v1GetAvailableMetricsRequest"
              }
            }
          },
          "description": "Request to retrieve the catalog of available analytics metrics for the given resources.",
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/v1GetAvailableMetricsResponse"
                }
              }
            },
            "description": "A successful response."
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/rpcStatus"
                }
              }
            },
            "description": "An unexpected error response."
          }
        },
        "security": [
          {
            "OAuth2": [
              "business-app"
            ]
          }
        ],
        "summary": "Get Available Metrics",
        "tags": [
          "AnalyticsService"
        ]
      }
    },
    "/v1/multi-location-analytics/query": {
      "post": {
        "description": "This is the primary analytics endpoint. It supports flexible querying of any available metric\nwith full control over measures, dimensions, time alignment, filtering, grouping, and pagination.\n\nIMPORTANT: Call GetAvailableMetrics first to discover valid metric names and their schemas.\n\n## Quick start\n\n1. Call GetAvailableMetrics to get the list of metric names, measures, and dimensions.\n2. Pick a metric_name (e.g., \"reviews\", \"activation_counts\").\n3. Set partner_id and at least one resource_id (typically a business_id).\n4. Set time_range with start and end_exclusive timestamps.\n5. Set alignment (usually ALIGN_DE

# --- truncated at 32 KB (33 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/vendasta/refs/heads/main/openapi/vendasta-multi-location-analytics-openapi.json