## Add Widget to Dashboard

**post** `/v5/evaluation-dashboards/{dashboard_id}/widgets`

Create a new widget, append it to the dashboard, and compute its result in one call.

The widget is persisted as its own entity, its ID is appended to the dashboard's
`widget_order`, and — unless it is a `markdown` or `heading` widget — its result is
computed synchronously against the dashboard's evaluation (or evaluation-group) data
before the response returns. Validation is type-specific: `markdown` requires
`config.content`, `bar`/`histogram`/`donut`/`scatter` require exactly one of
`config.x_column` or `config.x_column_group`, `table` configs with conditional
formatting are schema-validated, and all other chart types require a `query`. The
dashboard must exist and not be archived. A computation failure does not fail the
request: the widget is still created and returned with a result whose
`computation_status` is `failed` and an `error_message` set, while `markdown` and
`heading` widgets return a null result.

### Path Parameters

- `dashboard_id: string`

### Body Parameters

- `title: string`

  Widget title

- `type: EvaluationWidgetTypeEnum`

  Widget type

  - `"bar"`

  - `"histogram"`

  - `"donut"`

  - `"scatter"`

  - `"metric"`

  - `"table"`

  - `"markdown"`

  - `"heading"`

  - `"timeseries"`

- `config: optional map[unknown]`

  Chart-specific display configuration

- `query: optional SeriesQuery or MetricQuery`

  Structured query AST for metric computation (SeriesQuery or MetricQuery)

  - `SeriesQuery object { select, evaluation_ids, filter, 4 more }`

    Query that returns a series of records (used for table/bar/histogram/donut/scatter widgets).

    Used for widget types: table, bar, histogram, donut, scatter.
    Returns: {"type": "series", "data": [...]}

    Example SQL equivalent:
    SELECT category, AVG(score) as avg_score, COUNT(*) as count
    FROM evaluation_items
    WHERE score > 0.5 AND category = 'test'
    GROUP BY category
    ORDER BY avg_score DESC
    LIMIT 100

    - `select: array of SelectItem`

      - `expression: object { column, source, type }  or object { column, function, evaluation_ids, 3 more }`

        Reference to a column from evaluation_items.data

        Example:
        {"type": "COLUMN", "column": "category"}

        - `Column object { column, source, type }`

          Reference to a column from evaluation_items.data

          Example:
          {"type": "COLUMN", "column": "category"}

          - `column: string`

            Column name from evaluation_items.data

          - `source: optional string`

            Column source: 'data' or 'task_result_cache'

          - `type: optional "COLUMN"`

            - `"COLUMN"`

        - `Aggregation object { column, function, evaluation_ids, 3 more }`

          Aggregation function to apply

          Examples:
          {"type": "AGGREGATION", "function": "AVG", "column": "score"}
          {"type": "AGGREGATION", "function": "COUNT", "column": "*"}
          {"type": "AGGREGATION", "function": "PERCENTILE", "column": "score", "params": {"percentile": 95}}

          - `column: string`

            Column to aggregate, or '*' for COUNT(*)

          - `function: "COUNT" or "SUM" or "AVG" or 7 more`

            Supported aggregation functions

            - `"COUNT"`

            - `"SUM"`

            - `"AVG"`

            - `"MIN"`

            - `"MAX"`

            - `"STDDEV"`

            - `"VARIANCE"`

            - `"PERCENTILE"`

            - `"COUNT_DISTINCT"`

            - `"PERCENTAGE"`

          - `evaluation_ids: optional array of string`

            Optional subset of evaluation IDs for per-aggregation filtering in evaluation group dashboards.

          - `params: optional map[unknown]`

            Function parameters (e.g., {'percentile': 95} for PERCENTILE, {'percentage_filters': Filter} for PERCENTAGE)

          - `source: optional string`

            Column source: 'data' or 'task_result_cache'

          - `type: optional "AGGREGATION"`

            - `"AGGREGATION"`

      - `alias: optional string`

        Optional alias for the selected item

    - `evaluation_ids: optional array of string`

      Optional subset of evaluation IDs to compute on. Only applicable for evaluation group dashboards. If omitted, computes on all evaluations in the group.

    - `filter: optional Filter`

      Filter conditions (WHERE clause)

      - `conditions: array of object { column, operator, source, value }`

        - `column: string`

          Column name to filter on

        - `operator: "=" or "!=" or ">" or 9 more`

          Comparison operator

          - `"="`

          - `"!="`

          - `">"`

          - `"<"`

          - `">="`

          - `"<="`

          - `"IN"`

          - `"NOT IN"`

          - `"LIKE"`

          - `"NOT LIKE"`

          - `"IS NULL"`

          - `"IS NOT NULL"`

        - `source: optional string`

          Column source: 'data' or 'task_result_cache'

        - `value: optional string or number or boolean or array of unknown`

          Value to compare against. Not required for IS NULL / IS NOT NULL operators.

          - `string`

          - `number`

          - `boolean`

          - `array of unknown`

      - `logicalOperators: optional array of "AND" or "OR"`

        Logical operators connecting conditions. Length must be len(conditions) - 1

        - `"AND"`

        - `"OR"`

    - `groupBy: optional array of string`

      Columns to group by

    - `latest_only: optional boolean`

      When True, the widget computes against rows from only the most recent active evaluation in the group (by EvaluationORM.created_at). Only applicable for evaluation group dashboards. Composes with evaluation_ids (latest within the subset). Cannot be combined with per-aggregation evaluation_ids; the use case enforces these rules.

    - `limit: optional number`

      Max rows to return

    - `orderBy: optional array of object { column, direction, source }`

      Sort order

      - `column: string`

        Column name to sort by

      - `direction: optional "ASC" or "DESC"`

        Sort direction

        - `"ASC"`

        - `"DESC"`

      - `source: optional string`

        Column source: 'data' or 'task_result_cache'

  - `MetricQuery object { select, evaluation_ids, filter, latest_only }`

    Query that returns a single metric value (used for metric widgets).

    Used for widget type: metric.
    Enforces exactly 1 aggregation in select.
    Returns: {"type": "metric", "data": ...}

    Example SQL equivalent:
    SELECT AVG(score) as average_score
    FROM evaluation_items

    - `select: array of SelectItem`

      - `expression: object { column, source, type }  or object { column, function, evaluation_ids, 3 more }`

        Reference to a column from evaluation_items.data

        Example:
        {"type": "COLUMN", "column": "category"}

      - `alias: optional string`

        Optional alias for the selected item

    - `evaluation_ids: optional array of string`

      Optional subset of evaluation IDs to compute on. Only applicable for evaluation group dashboards. If omitted, computes on all evaluations in the group.

    - `filter: optional Filter`

      Filter conditions (WHERE clause)

    - `latest_only: optional boolean`

      When True, the widget computes against rows from only the most recent active evaluation in the group (by EvaluationORM.created_at). Only applicable for evaluation group dashboards. Composes with evaluation_ids (latest within the subset). Cannot be combined with per-aggregation evaluation_ids; the use case enforces these rules.

### Returns

- `EvaluationDashboardWidgetWithResult object { id, account_id, created_at, 6 more }`

  Response model for widget creation - includes widget and computed result

  - `id: string`

    Unique identifier of the widget

  - `account_id: string`

    Account that owns this widget

  - `created_at: string`

    When the widget was created

  - `title: string`

    Widget title

  - `type: EvaluationWidgetTypeEnum`

    Widget type

    - `"bar"`

    - `"histogram"`

    - `"donut"`

    - `"scatter"`

    - `"metric"`

    - `"table"`

    - `"markdown"`

    - `"heading"`

    - `"timeseries"`

  - `config: optional map[unknown]`

    Display configuration

  - `object: optional "evaluation_widget"`

    - `"evaluation_widget"`

  - `query: optional SeriesQuery or MetricQuery`

    Structured query AST for computation (SeriesQuery or MetricQuery)

    - `SeriesQuery object { select, evaluation_ids, filter, 4 more }`

      Query that returns a series of records (used for table/bar/histogram/donut/scatter widgets).

      Used for widget types: table, bar, histogram, donut, scatter.
      Returns: {"type": "series", "data": [...]}

      Example SQL equivalent:
      SELECT category, AVG(score) as avg_score, COUNT(*) as count
      FROM evaluation_items
      WHERE score > 0.5 AND category = 'test'
      GROUP BY category
      ORDER BY avg_score DESC
      LIMIT 100

      - `select: array of SelectItem`

        - `expression: object { column, source, type }  or object { column, function, evaluation_ids, 3 more }`

          Reference to a column from evaluation_items.data

          Example:
          {"type": "COLUMN", "column": "category"}

          - `Column object { column, source, type }`

            Reference to a column from evaluation_items.data

            Example:
            {"type": "COLUMN", "column": "category"}

            - `column: string`

              Column name from evaluation_items.data

            - `source: optional string`

              Column source: 'data' or 'task_result_cache'

            - `type: optional "COLUMN"`

              - `"COLUMN"`

          - `Aggregation object { column, function, evaluation_ids, 3 more }`

            Aggregation function to apply

            Examples:
            {"type": "AGGREGATION", "function": "AVG", "column": "score"}
            {"type": "AGGREGATION", "function": "COUNT", "column": "*"}
            {"type": "AGGREGATION", "function": "PERCENTILE", "column": "score", "params": {"percentile": 95}}

            - `column: string`

              Column to aggregate, or '*' for COUNT(*)

            - `function: "COUNT" or "SUM" or "AVG" or 7 more`

              Supported aggregation functions

              - `"COUNT"`

              - `"SUM"`

              - `"AVG"`

              - `"MIN"`

              - `"MAX"`

              - `"STDDEV"`

              - `"VARIANCE"`

              - `"PERCENTILE"`

              - `"COUNT_DISTINCT"`

              - `"PERCENTAGE"`

            - `evaluation_ids: optional array of string`

              Optional subset of evaluation IDs for per-aggregation filtering in evaluation group dashboards.

            - `params: optional map[unknown]`

              Function parameters (e.g., {'percentile': 95} for PERCENTILE, {'percentage_filters': Filter} for PERCENTAGE)

            - `source: optional string`

              Column source: 'data' or 'task_result_cache'

            - `type: optional "AGGREGATION"`

              - `"AGGREGATION"`

        - `alias: optional string`

          Optional alias for the selected item

      - `evaluation_ids: optional array of string`

        Optional subset of evaluation IDs to compute on. Only applicable for evaluation group dashboards. If omitted, computes on all evaluations in the group.

      - `filter: optional Filter`

        Filter conditions (WHERE clause)

        - `conditions: array of object { column, operator, source, value }`

          - `column: string`

            Column name to filter on

          - `operator: "=" or "!=" or ">" or 9 more`

            Comparison operator

            - `"="`

            - `"!="`

            - `">"`

            - `"<"`

            - `">="`

            - `"<="`

            - `"IN"`

            - `"NOT IN"`

            - `"LIKE"`

            - `"NOT LIKE"`

            - `"IS NULL"`

            - `"IS NOT NULL"`

          - `source: optional string`

            Column source: 'data' or 'task_result_cache'

          - `value: optional string or number or boolean or array of unknown`

            Value to compare against. Not required for IS NULL / IS NOT NULL operators.

            - `string`

            - `number`

            - `boolean`

            - `array of unknown`

        - `logicalOperators: optional array of "AND" or "OR"`

          Logical operators connecting conditions. Length must be len(conditions) - 1

          - `"AND"`

          - `"OR"`

      - `groupBy: optional array of string`

        Columns to group by

      - `latest_only: optional boolean`

        When True, the widget computes against rows from only the most recent active evaluation in the group (by EvaluationORM.created_at). Only applicable for evaluation group dashboards. Composes with evaluation_ids (latest within the subset). Cannot be combined with per-aggregation evaluation_ids; the use case enforces these rules.

      - `limit: optional number`

        Max rows to return

      - `orderBy: optional array of object { column, direction, source }`

        Sort order

        - `column: string`

          Column name to sort by

        - `direction: optional "ASC" or "DESC"`

          Sort direction

          - `"ASC"`

          - `"DESC"`

        - `source: optional string`

          Column source: 'data' or 'task_result_cache'

    - `MetricQuery object { select, evaluation_ids, filter, latest_only }`

      Query that returns a single metric value (used for metric widgets).

      Used for widget type: metric.
      Enforces exactly 1 aggregation in select.
      Returns: {"type": "metric", "data": ...}

      Example SQL equivalent:
      SELECT AVG(score) as average_score
      FROM evaluation_items

      - `select: array of SelectItem`

        - `expression: object { column, source, type }  or object { column, function, evaluation_ids, 3 more }`

          Reference to a column from evaluation_items.data

          Example:
          {"type": "COLUMN", "column": "category"}

        - `alias: optional string`

          Optional alias for the selected item

      - `evaluation_ids: optional array of string`

        Optional subset of evaluation IDs to compute on. Only applicable for evaluation group dashboards. If omitted, computes on all evaluations in the group.

      - `filter: optional Filter`

        Filter conditions (WHERE clause)

      - `latest_only: optional boolean`

        When True, the widget computes against rows from only the most recent active evaluation in the group (by EvaluationORM.created_at). Only applicable for evaluation group dashboards. Composes with evaluation_ids (latest within the subset). Cannot be combined with per-aggregation evaluation_ids; the use case enforces these rules.

  - `result: optional EvaluationDashboardWidgetResultResponse`

    Computed result for this widget

    - `id: string`

      Unique identifier of the widget result

    - `computation_status: string`

      Status: pending, completed, or failed

    - `widget_id: string`

      Widget ID this result belongs to

    - `computed_at: optional string`

      When computation completed

    - `computed_result: optional map[unknown]`

      Computed result data. Metric: {type: 'metric', data: 42}, Series: {type: 'series', data: [{x: 'A', y: 10}, ...]}

    - `error_message: optional string`

      Error message if computation failed

### Example

```http
curl https://api.egp.scale.com/v5/evaluation-dashboards/$DASHBOARD_ID/widgets \
    -H 'Content-Type: application/json' \
    -H "x-api-key: $SGP_API_KEY" \
    -d '{
          "title": "x",
          "type": "bar"
        }'
```

#### Response

```json
{
  "id": "id",
  "account_id": "account_id",
  "created_at": "2019-12-27T18:11:19.117Z",
  "title": "title",
  "type": "bar",
  "config": {
    "foo": "bar"
  },
  "object": "evaluation_widget",
  "query": {
    "select": [
      {
        "expression": {
          "column": "column",
          "source": "source",
          "type": "COLUMN"
        },
        "alias": "alias"
      }
    ],
    "evaluation_ids": [
      "string"
    ],
    "filter": {
      "conditions": [
        {
          "column": "column",
          "operator": "=",
          "source": "source",
          "value": "string"
        }
      ],
      "logicalOperators": [
        "AND"
      ]
    },
    "groupBy": [
      "string"
    ],
    "latest_only": true,
    "limit": 1,
    "orderBy": [
      {
        "column": "column",
        "direction": "ASC",
        "source": "source"
      }
    ]
  },
  "result": {
    "id": "id",
    "computation_status": "computation_status",
    "widget_id": "widget_id",
    "computed_at": "2019-12-27T18:11:19.117Z",
    "computed_result": {
      "foo": "bar"
    },
    "error_message": "error_message"
  }
}
```
