Query

Query Analytics data with selected fields, time bounds and filters.

Ternary's Analytics API puts you in control of your data and lets you make queries against the billing dataset you have ingested to Ternary. This endpoint is the primary endpoint for doing so.

Select FOCUS_BILLING, the data source exposed by Fetch Metadata, and the fields to query. start_time and end_time are optional bounds: the start is inclusive and the end is exclusive. Set precision to group results by time; without it, the query adds no timestamp grouping. With precision, each row includes timestamp, the UTC bucket start, and defaults to ascending timestamp order unless order_by explicitly orders that key. ROLLUP subtotal rows can omit it. Dimensions group the selected measures, and filters narrow the matching data.

To view a list of available measures and dimensions for filtering, use the Fetch Metadata endpoint first, then use the string values in the response as the values inside this request.

Here's an example query payload for Billed Cost per day from April 30 through May 30, 2025, inclusive in UTC, grouped by Service Category.

{
  "data_source": "FOCUS_BILLING",
  "dimensions": [
    "FOCUS_SPEC_FIELD/ServiceCategory"
  ],
  "measures": [
    "FOCUS_SPEC_FIELD/BilledCost"
  ],
  "precision": "DAY",
  "start_time": "2025-04-30T00:00:00.000Z",
  "end_time": "2025-05-31T00:00:00.000Z"
}

Filters use their fields directly. A single filter has schema_field_name, operator and any operator-specific values; do not wrap it in singleFilter:

{
  "schema_field_name": "FOCUS_SPEC_FIELD/ServiceCategory",
  "operator": "equals",
  "values": ["Compute"]
}

Dimension filters support equality, comparisons and set checks; contains/notContains apply only to STRING dimensions. Measure filters support gt/gte/lt/lte/set/notSet. Time-dimension filters support gt/gte/lt/lte with one timestamp value. Value-count validation is inconsistent, so malformed counts may return a server error.

For a group, supply boolean_logical_operator (and, or, nand or nor) and a nonempty filters array. Groups can contain other groups; do not wrap them in compositeFilter:

{
  "boolean_logical_operator": "or",
  "filters": [
    {
      "schema_field_name": "FOCUS_SPEC_FIELD/ServiceCategory",
      "operator": "equals",
      "values": ["Compute", "Storage"]
    },
    {
      "boolean_logical_operator": "and",
      "filters": [
        {
          "schema_field_name": "FOCUS_SPEC_FIELD/ServiceCategory",
          "operator": "equals",
          "values": ["Networking"]
        }
      ]
    }
  ]
}

These rules apply to the Analytics Query endpoint. Core API custom-measure variable filters have a narrower contract: groups accept and or or, and values must be strings within the Core schema limits.

Use these objects inside pre_agg_filters or post_agg_filters in the query. The JSON examples show the recursive shape even when an interactive form cannot expand every nesting level.

Query Params
string
required

A unique identifier for an organization

string

JSON-encoded Query; a nonempty value overrides the body

Body Params

Query payload; required when the query URL parameter is absent or empty

Query payload; required when the query URL parameter is absent or empty

Response currency for supported measures.

string
enum
required

Required schemaName from Fetch Metadata; this public contract covers FOCUS_BILLING.

Allowed:
array | null

Data attributes for grouping and filtering.

Exclusive end of the time range, as an RFC 3339 timestamp.

boolean

Legacy compatibility field; this endpoint does not use it to bypass row ceilings.

≥ 0

Maximum rows selected by the query; results still obey page and total row ceilings.

array | null

Data measures to be aggregated.

Continuation token from the previous response; keep the original query unchanged. Tokens retain the original result expiration.

integer
≥ 0

Rows to skip; applied only when limit is supplied.

array | null

Data ordering by field and direction.

array | null

Apply filters after aggregation using the same unwrapped, recursive filter format.

array | null

Apply filters before aggregation. Supply single-filter fields directly, or boolean_logical_operator and filters; never singleFilter/compositeFilter wrappers.

^([Ss][Ee][Cc][Oo][Nn][Dd]|[Mm][Ii][Nn][Uu][Tt][Ee]|[Hh][Oo][Uu][Rr]|[Dd][Aa][Yy]|[Ww][Ee][Ee][Kk]|[Mm][Oo][Nn][Tt][Hh]|[Qq][Uu][Aa][Rr][Tt][Ee][Rr]|[Yy][Ee][Aa][Rr])$

Optional time grouping granularity, case-insensitive; uppercase is canonical. Omitted or null adds no timestamp grouping.

string

Legacy compatibility field; this endpoint returns row objects regardless of this value.

boolean

Include subtotal and grand-total rows using ROLLUP. Subtotal rows omit keys for aggregated dimensions and can omit timestamp; genuine null dimension values remain JSON null.

Inclusive start of the time range, as an RFC 3339 timestamp.

Headers
string
enum
Defaults to application/json

Generated from available response content types

Allowed:
Responses

Language
Credentials
Header
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json
text/plain