Skip to main content

Overview

The metrics routes give the cost and usage data that the SELECT app shows, for Snowflake, BigQuery, Databricks and Tableau. Each route queries one semantic model:
All metrics routes use the same request body and the same response. When you know how to query one model, you can query all of them. Only the field names change from model to model. The reference page of each route lists its fields, and gives worked examples. This page uses the spend model for all examples. spend is the consolidated cost of all your platforms, for all services. Use it first for all questions about cost. Use a platform route (for example snowflake-workloads or bigquery-projects) to find which resource in the platform caused the cost. An API key must have the usage_data:read scope to use the metrics routes.

Your first query

This request gets the daily spend for each platform for the last 30 days:
The response has one row for each combination of day and connection_type:

Request body

Measures

A measure is a value that SELECT calculates across a group of rows, for example a sum or an average. The name of a measure usually tells you how SELECT calculates it: sum_spend is the sum of spend, and avg_daily_spend is the average spend per day. If a request has measures and no dimensions, the response has one row: the total for all rows that match the filters.
Measures that end in _annualized are projections, not spend. SELECT extends the spend of the filtered period to one year. For example, with a 7-day range, sum_spend_annualized is the spend of that week × 365 / 7. Do not show a projection as the spend of a period.

Dimensions

A dimension is a field that you group by. The response has one row for each unique combination of the values of the dimensions, and each row contains the value of each dimension. The measures in a row are calculated from only the data in that group. dimensions is equivalent to a SQL GROUP BY. More dimensions give more rows, and each row contains less data: A dimension that is not in dimensions does not split the rows. For example, ["connection_type"] with a 30-day filter gives the total of the 30 days for each platform, not a row for each day.

Time dimensions

To show a trend, add a time dimension to dimensions. The time dimension sets the size of each time bucket: All dates and hours are in UTC. Some rules apply to time buckets:
  • The first and last buckets can be partial. For example, a 30D range with week usually starts and stops in the middle of a week. The first and last rows then contain less data than the other rows.
  • Filter on day, and group by the larger bucket. To get monthly spend for the year, filter day with YTD and add month to dimensions. Do not filter on week, month or quarter.
  • Hour-level data comes from a different table. SELECT keeps spend in a daily table and in an hourly table. If your request uses hour, or another field that only the hourly table has, SELECT reads the hourly table. Otherwise, SELECT reads the daily table, which is faster. The totals are the same. You do not select the table.

Filters

filter_expression limits the rows that SELECT uses to calculate the measures. It is equivalent to a SQL WHERE. It is a tree: each node has an operator of and or or, and a list of filters. An item in filters can be a filter or another node. This request gets the spend on Snowflake compute or storage for the last 90 days:

Date ranges

Filter dates on the day field. To use fixed dates, use two filters. Both bounds are inclusive:
To use a range relative to today, use one in range filter:
Text values are case-sensitive. A value with incorrect case matches no rows, and SELECT does not return an error. For example, on spend, connection_type is Snowflake, Bigquery or Databricks. The value snowflake matches no rows.

Measure filters

measure_filters removes groups after SELECT calculates the measures. It is equivalent to a SQL HAVING. Use it to remove small groups from the response. This request gets the warehouses that cost more than $1,000 last month:
A filter in filter_expression changes the value of each measure. A filter in measure_filters does not change a value. It only removes rows.

Usage groups

A usage group set divides your cost into named groups, for example departments or teams. You define usage group sets in the SELECT app, or with the /v2/usage-group-sets routes. A model that has a usage_group dimension can group or filter by the groups of your sets. To group by the groups of one set, give the name of the set in path:
  • path[0] is the name of the set, not its ID.
  • A usage_group dimension with no path groups by all your sets at the same time.
  • To get the cost of one group, use the same form in a filter: {"field": {"field": "usage_group", "path": ["Department"]}, "operator": "=", "value": "Engineering"}.
  • To test a set before you save it, send its definition in usage_group_sets. SELECT then uses that definition in place of your saved sets.

Sort and limit

sort is a list of fields and directions. The first item sorts first. You can sort by a dimension or a measure:
limit is the maximum number of rows in the response. The metrics routes do not paginate: page_token is always null. If a query has more rows than limit, SELECT removes the rows after the limit, and does not return an error. Always set a limit. To get the top N groups, sort by a measure and set limit to N.

Period over period

Some models have measures that compare a period to the period before it: <measure>_previous_period, change_<measure> and percent_change_<measure>. The previous period has the same number of days, and stops on the day before your range starts. For these measures, the request must have one day range at the top level of filter_expression. Use one in range filter, or one >= filter and one <= filter.
For QTD on 2026-09-28, the range is 2026-07-01 to 2026-09-28 (90 days). The previous period is the 90 days from 2026-04-02 to 2026-06-30. It is not the previous calendar quarter.

Listing rows

To get rows with no grouping, set aggregate to false, and send only dimensions. For example, on snowflake-queries, this gives the individual queries. If the request also has measures or measure_filters, SELECT groups the rows, and does not return an error. Always set a limit when you list rows.

Teams

To query as one of your teams, send the X-Team-Id header. The response then contains only the data that the roles of the team give access to. This header may not be functional on all routes, reach out to the SELECT team if needed.