---
title: "Widget Audit Contributors"
method: POST
path: "/api/v1/dashboards/widget-audit/contributors"
tags: ["dashboards"]
---

# Widget Audit Contributors

`POST /api/v1/dashboards/widget-audit/contributors`

## Request body

- ContributorExpansionRequest — The signed observation token + the executed spec to re-run. The server recomputes the query hash from ``spec`` and rejects any mismatch with the token.
  - `token` string, required
  - `spec` WidgetQuerySpecInput, required — 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

- ContributorExpansion
  - `observation` ObservationAddress, required — What identifies one observation: a metric, where it sits, and which node. ``coordinates`` place the observation inside the widget — ``{"label": "2026-05-01"}`` for a series point, ``{"row": ..., "column": ...}`` for a matrix cell, ``{"interaction_id": ...}`` for a record row, ``{}`` for a lone scalar. ``node_path`` addresses a node inside a composed expression (``/numerator``), or is the whole result otherwise.
    - `metric_ref` string, required
    - `coordinates` object
    - `node_path` string, nullable
  - `is_rerun` boolean
  - `disclaimer` string
  - `sets` ContributorSet[]
    - `metric_ref` string, required
    - `node_path` string, nullable
    - `role` string
    - `drill_kind` string, nullable
    - `records` ContributorRecord[]
      - `record_id` string, required
      - `label` string, nullable
      - `contribution` string, nullable
      - `identifier` string, nullable
      - `effective_override_revision` string, uuid, nullable
    - `total_records` integer, nullable
    - `reconciliation` ReconciliationResult, required — How the rerun's value compares to what the token recorded, and (when the contributor detail is available) how the per-record contributions sum against it.
      - `reconciled` boolean, required
      - `expected_value_hash` string, required
      - `actual_value` string, nullable
      - `actual_value_hash` string, nullable
      - `contribution_sum` string, nullable
      - `divergence` 'definition_version_moved' | 'implementation_digest_moved' | 'source_rows_changed' | 'value_unavailable', nullable
      - `warning` string, nullable
    - `detail_available` boolean
    - `note` string, nullable
  - `advisories` string[]

## Other responses

- `401` — Tenant not identified
- `403` — Invalid/expired token, spec mismatch, or missing 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)
