---
title: "Query Widget Data"
method: POST
path: "/api/v1/dashboards/widget-data"
tags: ["dashboards"]
---

# Query Widget Data

`POST /api/v1/dashboards/widget-data`

## Request body

- WidgetQuerySpecInput — Input spec for run_widget_query. ACL context (PR3, all optional/additive — the "then required" tightening is a later frontend migration): ``dashboard_id`` + ``widget_id`` identify a placed widget so the endpoint authorizes ``can_view`` against that dashboard's category; ``category_id`` is the target tab for a live preview, authorized against ``can_edit``. When none are set the spec is a free-form query with no category ACL (documented limitation — see access.py).
  - `dashboard_id` string, uuid, nullable
  - `widget_id` string, uuid, nullable
  - `category_id` string, uuid, nullable
  - `metric_refs` MetricRef[], required
    - `key` string, required
    - `category` 'standard' | 'custom' | 'formula', required
    - `outcome` 'pass' | 'fail', nullable
    - `label` string, nullable
    - `is_after_hours` boolean, nullable
    - `population_filters` string[], nullable
    - `buckets` AttributionBucket[], nullable
  - `aggregation` AggregationSpec — How to aggregate the metric values.
    - `type` 'count' | 'sum' | 'avg' | 'pass_rate' | 'breakdown'
    - `period` 'minute' | 'hour' | 'day' | 'week' | 'month' | 'total' | 'auto'
  - `group_by` string[]
  - `filters` WidgetFilters, required — Filter vocabulary — mirrors useLogsFilters PARAM_MAP exactly. The drill output uses the same snake_case keys so the frontend can deep-link to the logs page with these as URL search params.
    - `start_date` string, date, required
    - `end_date` string, date, required
    - `start_datetime` string, date-time, nullable
    - `end_datetime` string, date-time, nullable
    - `agent_id` string, nullable
    - `outcome_agent_ref` string, nullable
    - `outcome_agent_refs` string[], nullable
    - `matrix_agent_refs` string[], nullable
    - `outcome_agent_kind` 'ai_voice' | 'ai_text' | 'human', nullable
    - `interaction_types` string[], nullable
    - `booking_sources` string[], nullable
    - `property_ids_exclude` string[], nullable
    - `outcome_agent_refs_exclude` string[], nullable
    - `interaction_types_exclude` string[], nullable
    - `booking_sources_exclude` string[], nullable
    - `buckets` AttributionBucket[], nullable
    - `dispositions` string[], nullable
    - `was_transferred` boolean, nullable
    - `transfer_failed` boolean, nullable
    - `was_missed` boolean, nullable
    - `was_answered` boolean, nullable
    - `is_after_hours` boolean, nullable
    - `population_filters` string[], nullable
    - `is_voicemail` boolean, nullable
    - `has_first_response` boolean, nullable
    - `has_ended` boolean, nullable
    - `transfer_destination` string, nullable
    - `country` string, nullable
    - `outcome` string, nullable
    - `has_booking_intent` boolean, nullable
    - `has_booking` boolean, nullable
    - `booking_made` boolean, nullable
    - `local_hour_of_day` integer, nullable
    - `local_day_of_week` integer, nullable
    - `tag_ids` string[], nullable
    - `property_ids` string[], nullable
    - `include_considered_hotels` boolean, nullable
    - `attribution_tiers` string[], nullable
    - `metric_filters` MetricFilter[], nullable
      - `metric_id` string, required
      - `outcome` 'pass' | 'fail' | 'any' | 'na', nullable
      - `categorical_value` string, nullable
    - `standard_filters` StandardColumnFilter[], nullable
      - `field` string, required
      - `value` string, required
  - `filter_clauses` FilterClause[], nullable
    - `field` string, required
    - `value` unknown, required
    - `mode` 'include' | 'exclude'
    - `origin` 'global' | 'widget' | 'metric' | 'drill' | 'component', required
  - `result_shape` 'scalar' | 'timeseries' | 'breakdown' | 'pivot' | 'matrix' | 'records', nullable
  - `comparison` 'previous_period' | 'previous_week' | 'previous_month' | 'previous_year', nullable
  - `records_subject` 'voice' | 'text' | 'email' | 'booking', nullable
  - `column_rollups` ColumnRollup[], nullable
    - `label` string, required
    - `buckets` AttributionBucket[], required

## Response `200`

Successful Response

- WidgetQueryResult — Response from the query engine.
  - `data` DataPoint[], required
    - `label` string, nullable
    - `sublabel` string, nullable
    - `value` number, nullable
    - `breakdown` object, nullable
    - `drill` DrillFilter — Typed drill-through filter spec — same keys as useLogsFilters PARAM_MAP. Exposes a concrete schema so the generated TS SDK produces typed access (not Record<string, unknown>).
      - `start_date` string, required
      - `end_date` string, required
      - `agent_id` string, nullable
      - `outcome_agent_ref` string, nullable
      - `outcome_agent_refs` string[], nullable
      - `outcome_agent_kind` string, nullable
      - `channels` string[], nullable
      - `buckets` string[], nullable
      - `dispositions` string[], nullable
      - `property_ids_exclude` string[], nullable
      - `outcome_agent_refs_exclude` string[], nullable
      - `standard_filters` StandardColumnFilter[], nullable
        - `field` string, required
        - `value` string, required
      - `was_transferred` string, nullable
      - `transfer_failed` string, nullable
      - `was_missed` string, nullable
      - `was_answered` string, nullable
      - `is_after_hours` string, nullable
      - `population_filters` string[], nullable
      - `is_voicemail` string, nullable
      - `has_first_response` string, nullable
      - `has_ended` string, nullable
      - `transfer_destination` string, nullable
      - `transfer_failure_reason` string, nullable
      - `country` string, nullable
      - `contact_source` string, nullable
      - `outcome` string, nullable
      - `has_booking_intent` string, nullable
      - `has_booking` string, nullable
      - `booking_made` string, nullable
      - `local_hour_of_day` string, nullable
      - `local_day_of_week` string, nullable
      - `tag_ids` string[], nullable
      - `property_ids` string[], nullable
      - `include_considered_hotels` boolean, nullable
      - `failed_transfer_destination` string, nullable
      - `failed_transfer_tool_name` string, nullable
      - `attempted_transfer_destination` string, nullable
      - `attempted_transfer_tool_name` string, nullable
      - `succeeded_transfer_destination` string, nullable
      - `succeeded_transfer_tool_name` string, nullable
      - `unresolved_transfer_destination` string, nullable
      - `unresolved_transfer_tool_name` string, nullable
      - `metric_filters` MetricFilter[], nullable
        - `metric_id` string, required
        - `outcome` 'pass' | 'fail' | 'any' | 'na', nullable
        - `categorical_value` string, nullable
    - `cell_drills` object, nullable
    - `booking_drill` BookingDrillScope — Drill envelope for canonical booking measures (Direct Bookings PR 9). The filter fields mirror the ``GET /bookings`` query params VERBATIM (pinned by test against the route signature), so a widget cell deep-links to exactly the bookings it aggregated — the same ``apply_booking_list_filters`` predicate serves both sides. The scope fields disclose the full metric definition (date axis + semantics, tz, status and attribution rules, currency, snapshot time) so the /bookings scoped drill mode can label precisely what was measured.
      - `property` string[], nullable
      - `originating_channel` string[], nullable
      - `property_exclude` string[], nullable
      - `originating_channel_exclude` string[], nullable
      - `outcome_agent_refs` string[], nullable
      - `outcome_agent_refs_exclude` string[], nullable
      - `outcome_agent_kind` string, nullable
      - `attribution_tier` string[], nullable
      - `status_code` string[], nullable
      - `booked_from` string, nullable
      - `booked_to` string, nullable
      - `stay_from` string, nullable
      - `stay_to` string, nullable
      - `cancelled_from` string, nullable
      - `cancelled_to` string, nullable
      - `wh_source_id` string, nullable
      - `unknown_commission` boolean, nullable
      - `measure` string, required
      - `date_axis` 'booked' | 'stay' | 'cancelled', required
      - `date_axis_timezone` string
      - `status_rule` string
      - `attribution_rule` string
      - `currency` string, nullable
      - `snapshot_at` string, required
    - `booking_cell_drills` object, nullable
    - `provenance` string, nullable
    - `cell_provenance` object, nullable
    - `comparison_value` number, nullable
    - `delta` number, nullable
    - `delta_pct` number, nullable
  - `records` WidgetRecordRow[], nullable
    - `interaction_id` string, required
    - `subject` 'voice' | 'text' | 'email' | 'booking', required
    - `started_at` string, date-time, nullable
    - `guest` string, nullable
    - `country` string, nullable
    - `value_cents` integer, nullable
    - `value_amount` string, nullable
    - `currency` string, nullable
    - `provenance` string, nullable
  - `records_total` integer, nullable
  - `filter_applicability` object, nullable
  - `empty` EmptyState — Why a widget has nothing to show (design §5a R4). ``None`` on the result means the widget has data; set means the frontend renders a typed empty state (KPI → 0, ratio → —, chart/table → frame kept) with the right caption. - ``intrinsic_conflict``: a specific predicate PROVABLY contradicts the measure's own domain (e.g. a text-sessions measure under ``channel=voice``). ``predicate`` names the conflicting dimension (e.g. ``"channel"``). Derived from the spec, never by a counterfactual query. - ``no_matching_rows``: the active filter set matched nothing and no single filter is provably responsible — generic, with the active filter chips + Clear/Broaden on the frontend. No counterfactual guessing of a culprit. - ``no_tenant_data``: nothing is shown and no narrowing filter is active — the warm fresh-account onboarding state.
    - `kind` 'intrinsic_conflict' | 'no_matching_rows' | 'no_tenant_data', required
    - `predicate` string, nullable
  - `drill` DrillFilter, required — Typed drill-through filter spec — same keys as useLogsFilters PARAM_MAP. Exposes a concrete schema so the generated TS SDK produces typed access (not Record<string, unknown>).
    - `start_date` string, required
    - `end_date` string, required
    - `agent_id` string, nullable
    - `outcome_agent_ref` string, nullable
    - `outcome_agent_refs` string[], nullable
    - `outcome_agent_kind` string, nullable
    - `channels` string[], nullable
    - `buckets` string[], nullable
    - `dispositions` string[], nullable
    - `property_ids_exclude` string[], nullable
    - `outcome_agent_refs_exclude` string[], nullable
    - `standard_filters` StandardColumnFilter[], nullable
      - `field` string, required
      - `value` string, required
    - `was_transferred` string, nullable
    - `transfer_failed` string, nullable
    - `was_missed` string, nullable
    - `was_answered` string, nullable
    - `is_after_hours` string, nullable
    - `population_filters` string[], nullable
    - `is_voicemail` string, nullable
    - `has_first_response` string, nullable
    - `has_ended` string, nullable
    - `transfer_destination` string, nullable
    - `transfer_failure_reason` string, nullable
    - `country` string, nullable
    - `contact_source` string, nullable
    - `outcome` string, nullable
    - `has_booking_intent` string, nullable
    - `has_booking` string, nullable
    - `booking_made` string, nullable
    - `local_hour_of_day` string, nullable
    - `local_day_of_week` string, nullable
    - `tag_ids` string[], nullable
    - `property_ids` string[], nullable
    - `include_considered_hotels` boolean, nullable
    - `failed_transfer_destination` string, nullable
    - `failed_transfer_tool_name` string, nullable
    - `attempted_transfer_destination` string, nullable
    - `attempted_transfer_tool_name` string, nullable
    - `succeeded_transfer_destination` string, nullable
    - `succeeded_transfer_tool_name` string, nullable
    - `unresolved_transfer_destination` string, nullable
    - `unresolved_transfer_tool_name` string, nullable
    - `metric_filters` MetricFilter[], nullable
      - `metric_id` string, required
      - `outcome` 'pass' | 'fail' | 'any' | 'na', nullable
      - `categorical_value` string, nullable
  - `booking_drill` BookingDrillScope — Drill envelope for canonical booking measures (Direct Bookings PR 9). The filter fields mirror the ``GET /bookings`` query params VERBATIM (pinned by test against the route signature), so a widget cell deep-links to exactly the bookings it aggregated — the same ``apply_booking_list_filters`` predicate serves both sides. The scope fields disclose the full metric definition (date axis + semantics, tz, status and attribution rules, currency, snapshot time) so the /bookings scoped drill mode can label precisely what was measured.
    - `property` string[], nullable
    - `originating_channel` string[], nullable
    - `property_exclude` string[], nullable
    - `originating_channel_exclude` string[], nullable
    - `outcome_agent_refs` string[], nullable
    - `outcome_agent_refs_exclude` string[], nullable
    - `outcome_agent_kind` string, nullable
    - `attribution_tier` string[], nullable
    - `status_code` string[], nullable
    - `booked_from` string, nullable
    - `booked_to` string, nullable
    - `stay_from` string, nullable
    - `stay_to` string, nullable
    - `cancelled_from` string, nullable
    - `cancelled_to` string, nullable
    - `wh_source_id` string, nullable
    - `unknown_commission` boolean, nullable
    - `measure` string, required
    - `date_axis` 'booked' | 'stay' | 'cancelled', required
    - `date_axis_timezone` string
    - `status_rule` string
    - `attribution_rule` string
    - `currency` string, nullable
    - `snapshot_at` string, required
  - `bucket_labels` object, nullable
  - `currency` string, nullable
  - `execution` QueryExecution — The per-request provenance header, serialized from the accumulated traces. ``executed_spec`` is the normalized specification that actually executed and ``canonical_query_hash`` is the SHA-256 over it (decision 8) — together the authoritative identity of this execution. ``time_axes`` maps each resolved metric/component to the timestamp column it ranged over, since a ratio may mix axes (PR 23).
    - `executed_at` string, date-time, required
    - `app_release` string, required
    - `schema_version` integer
    - `executed_spec` object
    - `canonical_query_hash` string, required
    - `filter_clauses` FilterClause[]
      - `field` string, required
      - `value` unknown, required
      - `mode` 'include' | 'exclude'
      - `origin` 'global' | 'widget' | 'metric' | 'drill' | 'component', required
    - `time_resolution` TimeResolution — How one execution's local date range resolved to an absolute UTC window. ``workspace_timezone`` is the IANA identifier and the ONLY timezone fact ever stored, traced or compared (an abbreviation like EET/EEST is presentation-only and derived per range). ``tz_rules_version`` names the DST ruleset in effect so a later reader can tell whether a historical rule has since moved.
      - `workspace_timezone` string, required
      - `local_start_date` string, date, required
      - `local_end_date` string, date, required
      - `resolved_start_utc` string, date-time, required
      - `resolved_end_utc_exclusive` string, date-time, required
      - `tz_rules_version` string, required
    - `comparison_time_resolution` TimeResolution — How one execution's local date range resolved to an absolute UTC window. ``workspace_timezone`` is the IANA identifier and the ONLY timezone fact ever stored, traced or compared (an abbreviation like EET/EEST is presentation-only and derived per range). ``tz_rules_version`` names the DST ruleset in effect so a later reader can tell whether a historical rule has since moved.
      - `workspace_timezone` string, required
      - `local_start_date` string, date, required
      - `local_end_date` string, date, required
      - `resolved_start_utc` string, date-time, required
      - `resolved_end_utc_exclusive` string, date-time, required
      - `tz_rules_version` string, required
    - `time_axes` object
    - `widget_ref` WidgetRef — Which widget this execution ran for, and a fingerprint of its config. ``config_fingerprint`` is the sha256 of the widget's canonical-JSON config, so a later audit reader can tell whether the widget definition moved without adding a version column to the ``Widget`` row. All fields are ``None`` for an ad-hoc query (a preview or a spec with no ``widget_id``).
      - `id` string, nullable
      - `source_ref` string, nullable
      - `config_fingerprint` string, nullable
      - `updated_at` string, date-time, nullable
    - `template_provenance` TemplateProvenance — Optional: which library template a system widget was instantiated from. **Not execution truth.** A widget's numbers come from its own config and the metric definitions, not from the template it started as — this only records the lineage and whether the widget still matches that template (``matches_template`` = the shared "Customized" test). Absent for user/ad-hoc widgets.
      - `report_query_key` string, required
      - `report_query_version` integer, required
      - `matches_template` boolean, required
    - `metrics` MetricExecutionInfo[]
      - `ref` string, required
      - `definition_version` integer, nullable
      - `implementation_digest` string, nullable
      - `calculation_kind` string, nullable
      - `executor_key` string, nullable
      - `unit` UnitSpecOutput — A unit as a ``dimension → exponent`` vector plus an optional currency code. ``currency_code`` is meaningful only when a ``currency`` dimension is present. Two DIFFERENT codes are incompatible, and ``currency_code=None`` (unknown / resolved per query scope) is incompatible with EVERY coded currency — the mechanism that blocks summing an unknown-currency value into a known one (PR 14 leans on it).
        - `dimensions` object
        - `currency_code` string, nullable
        - `display_label` string, required — ``to_display_label()``, serialized (Agent-Native PR 12). Every surface that shows a raw value needs to say what unit it is IN — the audit panel prints an exact ``12,150`` directly beneath a formatted ``3.4 h``, and unlabelled that reads as hours and is wrong by a factor of 3,600. The renderer already exists here; exposing it means the client, the agent tools and the disclosures all say ``conversations · seconds`` rather than each inventing a name for the same vector from raw dimension keys.
      - `entity` string, nullable
      - `drill_kind` string, nullable
      - `component_observations` ComponentObservation[]
        - `node_path` string, required
        - `role` 'result' | 'numerator' | 'denominator' | 'component', required
        - `metric_ref` string, nullable
        - `value` string, nullable
        - `canonical_value` string, nullable
        - `unit` UnitSpecOutput — A unit as a ``dimension → exponent`` vector plus an optional currency code. ``currency_code`` is meaningful only when a ``currency`` dimension is present. Two DIFFERENT codes are incompatible, and ``currency_code=None`` (unknown / resolved per query scope) is incompatible with EVERY coded currency — the mechanism that blocks summing an unknown-currency value into a known one (PR 14 leans on it).
          - `dimensions` object
          - `currency_code` string, nullable
          - `display_label` string, required — ``to_display_label()``, serialized (Agent-Native PR 12). Every surface that shows a raw value needs to say what unit it is IN — the audit panel prints an exact ``12,150`` directly beneath a formatted ``3.4 h``, and unlabelled that reads as hours and is wrong by a factor of 3,600. The renderer already exists here; exposing it means the client, the agent tools and the disclosures all say ``conversations · seconds`` rather than each inventing a name for the same vector from raw dimension keys.
        - `provenance` string, nullable
      - `change_lineage` ChangeLineage — PR 29 — which definition version + author produced an evaluated/calculated metric. ``prompt_ref`` is an IDENTIFIER, never the prompt text (the text is fetched by reference behind the metric's own gate). ``override_count`` and ``expansion_ref`` are population-scoped audit facts surfaced lazily by the audit panel / contributor expansion (PR 28/30), not on the hot widget-data path — they stay ``None`` here.
        - `revision_id` string, uuid, nullable
        - `revision_number` integer, nullable
        - `model_used` string, nullable
        - `prompt_ref` string, nullable
        - `override_count` integer, nullable
        - `expansion_ref` string, nullable
        - `authored_by_conversation_id` string, uuid, nullable
    - `source_consistency` 'snapshot' | 'single_statement' | 'best_effort', nullable
    - `source_as_of` string, date-time, nullable
    - `advisories` string[]

## Other responses

- `403` — No access to the tab, or missing report permission
- `404` — Dashboard not found
- `422` — Validation Error

---

[API](https://skmtc.dev/getanana/apis/cleon-api.md) · [All operations](https://skmtc.dev/getanana/apis/cleon-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/getanana/cleon-api/revisions/c0f54348e251/schema)
