REST API Reference

This reference is grounded in the analytics service's source-owned OpenAPI 3.1.1 documents. The portal vendors the aggregate document and serves it at /openapi.json; it covers the latest 20260709 contract, the deprecated /v1 compatibility contract, and shared MCP/OAuth paths.

Authentication

REST callers can authenticate with:

Authorization: Bearer <token>

Authorization is preferred. The portal's own live tools call server-side BFF routes so bearer tokens do not live in browser localStorage.

REST Query Flow

Production REST path: build or receive a trusted structured analytics query, optionally validate it, then call POST /api/20260709/queries/run. The run endpoint validates again before execution, so backend integrations should treat this as the primary REST execution call.

1Discover IDsUse Catalog Explorer or API endpoints.2Build queryUse Query Builder or application code to assemble analytics_query.
3Validate(optional) Use builder/local checks; agent flows compile via question endpoints.
4Run queryCall POST endpoint with query payload.
5Inspect resultRead execution.status, execution.result, and table_preview when available.

Endpoints

MethodPathPurpose
GET/healthService liveness check.
GET/openapi.jsonAggregate machine-readable contract for every supported public version.
GET/api/20260709/openapi.jsonLatest-version OpenAPI document.
GET/api/20260709/catalogNormalized metric, dimension, and client catalog.
GET/api/20260709/clientsPaginated active clients available to the caller token.
GET/api/20260709/clients/{client_id}/freshnessLatest successful regular DBT attribution update and vendor pull for one token-authorized client.
POST/api/20260709/catalog/searchSearch metrics, dimensions, clients, and indexed dimension values.
POST/api/20260709/questions/compileCompile and validate natural-language questions without execution.
POST/api/20260709/questions/enqueueCompile, validate, and enqueue async execution.
POST/api/20260709/questions/runCompile, validate, enqueue, poll, and fetch a result.
POST/api/20260709/queries/runValidate and run a trusted structured analytics query directly.
POST/api/20260709/queries/explainExplain validation or result metadata.
GET/api/20260709/mcp/toolsInspect advertised MCP tools.
POST/api/20260709/mcp/tools/callCall an MCP tool over REST for inspection.

Question endpoints are documented for agent and MCP-style workflows. Backend REST integrations should prefer direct structured-query execution through POST /api/20260709/queries/run.

Client Listing

Use GET /api/20260709/clients when an integration only needs accessible client IDs and names. It is lighter than fetching the full catalog and is the preferred backing endpoint for searchable client pickers.

Query parameterNotes
qOptional substring filter across client ID, display name, external name, parent/child IDs, and stack name.
limitDefaults to 100 and is capped at 500.
offsetPagination offset. Continue with next_offset until it is null.

The response includes client_count, returned_count, next_offset, and clients. Each client contains id, client_id, optional display/external names, optional stack metadata, parent client ID, and child client IDs.

Data Freshness

Use GET /api/20260709/clients/{client_id}/freshness before interpreting results that cover today or yesterday, or whenever ingestion lag could affect an answer.

curl -sS "https://api.admetrics.io/api/20260709/clients/2938354/freshness" \
-H "Authorization: Bearer ${AQL_BEARER_TOKEN}"
{
  "client_id": "2938354",
  "observed_at": "2026-08-03T10:00:00Z",
  "dbt": { "last_success_at": "2026-08-03T08:00:00Z" },
  "vendor_pull": {
    "last_success_at": "2026-08-03T09:00:00Z",
    "vendors": ["google"]
  }
}

All timestamps are UTC completion times. Both checkpoints include only regular successful runs; backfills are excluded. A token-authorized client with no successful history returns null for the relevant timestamp. Missing or invalid credentials return 401, and a valid token without access to the requested client returns 403.

Common Natural-Language Request Fields

FieldNotes
questionRequired for /api/20260709/questions/*. Ask for one atomic analytics query.
client_id, client_idsOptional but recommended.
date_contextOptional YYYY-MM-DD base date for relative phrases.
metric_ids, dimension_ids, sort_id, sort_directionExact catalog overrides.
attribution_model, attribution_window, metric_paramsOptional attribution parameters validated against the live catalog.
limitOptional row limit.
format, result_formatrecords, rows, columnar, csv, txt, xlsx, dataframe, or arrow.
wait_for_resultOptional async behavior.
timeout_ms, poll_interval_msOptional polling controls.

Structured Analytics Query Run Fields

FieldNotes
analytics_queryRequired non-empty object. Use the structured query shape with options, shape, select, and filters.
query_sourceRequired. Use user_provided_query for Query Builder or backend-provided JSON, or compiled_question for compiler output.
format, result_formatOptional output format override. result_format is preferred when both are supplied.
timeout_ms, poll_interval_msOptional polling controls for run-and-wait flows.

Metadata-Aware Filters

The Query Builder can add any token-visible metric or dimension as an additional filter. Client and date scope stay in their dedicated controls, filter-only fields do not need to be selected as outputs, and additional rows are combined with AND.

Builder selections and filter editor values are restored when you navigate away and return in the same browser tab. This session-scoped workspace stores query configuration only; authentication credentials and query results are not persisted there.

Field classBuilder operatorsAQL operators
Numericequals, comparisons, between, in/not in, exists/not exists$eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $notexists
Dateon, before/after, between, in/not in, exists/not exists$eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $notexists
Textequals, in/not in, contains/not contains, regex/not regex, exists/not exists$eq, $ne, $in, $nin, $regex, $notregex, $exists, $notexists
Identifierequals, in/not in, exists/not exists$eq, $ne, $in, $nin, $exists, $notexists
Booleanis/is not, exists/not exists$eq, $ne, $exists, $notexists

Contains filters escape the typed value and emit a case-insensitive regex. Explicit regex operators preserve the raw pattern for expert use. Indexed dimensions offer client-scoped value suggestions through /api/20260709/catalog/search, but typed values remain valid:

{
  "dimension": "campaign_name",
  "value_query": "brand",
  "client_ids": [2617401],
  "value_limit": 12
}

A query can repeat a field; AQL merges the constraints. A range and a case-insensitive contains filter serialize as:

"filters": [
  { "id": "client_id", "filter": { "$in": [2617401] } },
  { "id": "date", "filter": { "$gte": "2026-06-01", "$lte": "2026-06-30" } },
  { "id": "attributed_events.visits", "filter": { "$gte": 1000, "$lte": 5000 } },
  { "id": "campaign_name", "filter": { "$regex": "(?i).*brand.*" } }
]

Return Formats

FormatNotes
recordsJSON-style row objects.
rowsRow-oriented output.
columnarColumn-oriented output.
csvComma-separated text payload.
txtText payload.
xlsxSpreadsheet payload.
dataframeDataFrame-oriented payload for connector workflows.
arrowArrow binary payload. This is the Query Builder default; responses may include execution.result.table_preview for UI inspection.
jsonAlias for records.
textAlias for txt.

Return Format Examples

These examples show the shape a run response might expose under execution.result. Exact wrappers and metadata can vary by endpoint, timeout behavior, and format.

records or json

{
  "format": "records",
  "content_type": "application/json",
  "data": [
    {
      "date": "2026-06-01",
      "campaign_name": "Brand Search",
      "spend": 1284.5,
      "revenue": 8120.2,
      "roas": 6.32
    }
  ]
}

rows

{
  "format": "rows",
  "columns": ["date", "campaign_name", "spend", "revenue", "roas"],
  "data": [
    ["2026-06-01", "Brand Search", 1284.5, 8120.2, 6.32]
  ]
}

columnar

{
  "format": "columnar",
  "data": {
    "date": ["2026-06-01"],
    "campaign_name": ["Brand Search"],
    "spend": [1284.5],
    "revenue": [8120.2],
    "roas": [6.32]
  }
}

csv or txt

date,campaign_name,spend,revenue,roas
2026-06-01,Brand Search,1284.50,8120.20,6.32

arrow, xlsx, or dataframe

{
  "format": "arrow",
  "content_type": "application/vnd.apache.arrow.stream",
  "byte_length": 1024,
  "base64": "<encoded binary payload>",
  "table_preview": {
    "columns": ["date", "campaign_name", "spend", "revenue", "roas"],
    "rows": [
      {
        "date": "2026-06-01",
        "campaign_name": "Brand Search",
        "spend": 1284.5,
        "revenue": 8120.2,
        "roas": 6.32
      }
    ],
    "row_count": 1,
    "truncated": false
  }
}

Binary-oriented formats usually include content metadata and may include table_preview so portal users can inspect rows without decoding the full payload in the browser.

Troubleshooting Failed Requests

Most failures mean the request needs a more precise analytics contract. Treat these as recoverable integration states rather than generic server errors.

What you seeWhat it meansWhat to do
The response asks for clarification.AQL could not infer enough scope to build one clear query.Add an explicit client, date range, metric, and grouping. For REST integrations, prefer exact catalog IDs over labels.
Validation failed.The generated or supplied structured query contains an unsupported field, filter, parameter, or field combination.Read validation.errors, replace guessed fields with IDs from Catalog Explorer or /api/20260709/catalog/search, then retry.
The run timed out.The portal or API stopped waiting for the result before upstream execution finished.Use a larger timeout_ms for bounded queries, or use the enqueue/poll flow when a query can run longer.
The request returns 401.The bearer token is missing, expired, or not authorized for the requested client/resource.Refresh the caller token, complete OAuth again, and confirm the token can access the requested client.
The response says the output format is unsupported.The requested format or result_format is not available for this endpoint.Use one of the supported formats listed above, such as records, csv, xlsx, or arrow.