---
title: "Run Widget Query"
method: POST
path: "/api/v1/public/widgets/query"
tags: ["Widgets"]
---

# Run Widget Query

`POST /api/v1/public/widgets/query`

## Request

- Base URL: `https://app.traceroot.ai`
- URL: `https://app.traceroot.ai/api/v1/public/widgets/query`
- Auth: HTTP bearer

Run a widget spec for a window and return its rows with the window answered.

## Query parameters

- `project_id` string, nullable: Target project for the request. Required when authenticating with a user session token (a user credential is only meaningful scoped to a project); for an API key it is optional and, if given, must match the key's project.

## Request body

- WidgetQueryRequest: Envelope that pairs a WidgetSpec with the time window to answer it for. The window is either a ``range`` preset (the site picker's ids — how the agent and the CLI describe one) or explicit ``start_time``/``end_time`` (how the dashboard page and the card previews do). Neither means the site's default window; both, or one bound alone, is rejected. The rules live in ``rest.services.date_presets.resolve_window`` so every query surface applies the same ones.
  - `bucket_seconds` integer, nullable
  - `end_time` string, date-time, nullable
  - `range` '30m' | '1h' | '3h' | '6h' | '1d' | '7d' | '14d' | '30d' | '60d' | '90d', nullable: A preset window ending now, by the site picker's id. Give this or explicit start_time/end_time; neither means the site's 24-hour default.
  - `spec` WidgetSpec, required: Full declarative specification of a single dashboard widget. Mirrors the canonical zod ``WidgetSpecSchema`` (frontend/ui/src/features/dashboards/types.ts); the frontend widget-spec-parity test guards the two against structural drift.
    - `breakdown` string, nullable
    - `display` WidgetDisplay, required: Controls how the query result is rendered on the dashboard.
      - `type` 'line' | 'area' | 'bar' | 'pie' | 'number' | 'table' | 'histogram', required
    - `filters` WidgetFilter[]
      - `field` string, required
      - `key` string
      - `op` '=' | 'contains' | 'in' | '>' | '>=' | '<' | '<=', required
      - `value` union, required
        - string
        - number
        - string[]
    - `metric` WidgetMetric, required: The measure and aggregation function that define the widget's y-axis.
      - `agg` 'count' | 'sum' | 'avg' | 'min' | 'max' | 'p50' | 'p75' | 'p90' | 'p95' | 'p99' | 'uniq', required
      - `measure` string, required
    - `view` 'spans' | 'traces', required
  - `start_time` string, date-time, nullable

## Response `200`

Successful Response

- WidgetQueryResponse: Query result returned to the frontend; meta carries display hints (e.g. granularity for time-series displays).
  - `columns` string[], required
  - `meta` object
  - `rows` array[], required
    - unknown[]
      - unknown
  - `window` QueryWindow, required: The window a query was actually answered for. ``range`` is the preset id the caller gave (or the default's, when they gave nothing) and None for explicit bounds. ``clamped`` is True when the plan's retention pulled ``start_time`` forward — the honest reason a caller's window and the answered one differ.
    - `clamped` boolean, required
    - `end_time` string, date-time, required
    - `range` '30m' | '1h' | '3h' | '6h' | '1d' | '7d' | '14d' | '30d' | '60d' | '90d', nullable, required
    - `start_time` string, date-time, required

## Other responses

- `401`: Authentication failed
- `422`: Validation Error
- `503`: Authentication service unavailable

---

[API](https://skmtc.dev/traceroot/apis/traceroot-public-api.md) - [All operations](https://skmtc.dev/traceroot/apis/traceroot-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/traceroot/apis/traceroot-public-api/revisions/ce6aef96c0d6?raw)
