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).
How to aggregate the metric values.
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.
Successful Response
Response from the query engine.
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.
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>).
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.
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).