---
type: api
title: Dashboards
description: A [dashboard](https://www.elastic.co/docs/explore-analyze/dashboards) is a collection of panels arranged on a grid. Each panel can contain a visualization, a Discover session, an image, markdown text, or an interactive filter control. Use this API to create and manage dashboards programmatically.
url: https://www.elastic.co/elastic/docs-builder/docs/4371/api/doc/kibana/v0/group/endpoint-dashboards
resource: https://www.elastic.co/elastic/docs-builder/docs/4371/api/doc/kibana/v0/group/endpoint-dashboards
products:
  - Kibana
---

# Dashboards

A [dashboard](https://www.elastic.co/docs/explore-analyze/dashboards) is a collection of panels arranged on a grid. Each panel can contain a visualization, a Discover session, an image, markdown text, or an interactive filter control. Use this API to create and manage dashboards programmatically.

## When to use this API

- Use this API to define a complete, self-contained dashboard in a single payload, including inline visualizations (both data view and ES|QL based), controls, and filters.
- Use the [Visualizations API](visualizations#tag/Visualizations/operation/create-visualization) to create reusable charts saved to your [visualization library](https://www.elastic.co/docs/explore-analyze/visualize/visualize-library). You can then embed them in dashboards as linked panels using their ID.

## Get started

Before you begin:

- **Authentication**: Refer to [Authentication](https://www.elastic.co/docs/api/doc/kibana#authentication) in the Kibana API documentation.
- **CSRF protection**: Write operations (`POST`, `PUT`, `DELETE`) require the `kbn-xsrf: true` header.
- **Spaces**: If you use non-default [Kibana spaces](https://www.elastic.co/docs/deploy-manage/manage-spaces), prepend `s/{space_id}/` to the path.

### Try it now

Create your first dashboard right now. The following example creates a dashboard with an ES|QL line chart showing log entries over time. You can run it as-is once you have the [Kibana sample logs dataset](https://www.elastic.co/docs/manage-data/ingest/sample-data) installed:

```bash
curl -X POST "${KIBANA_URL}/api/dashboards" \
  -H "Authorization: ApiKey ${API_KEY}" \
  -H "kbn-xsrf: true" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My first API dashboard",
    "panels": [
      {
        "grid": {
          "x": 0,
          "y": 0,
          "w": 24,
          "h": 10
        },
        "type": "vis",
        "config": {
          "type": "xy",
          "title": "Total log entries over time",
          "layers": [
            {
              "type": "line",
              "data_source": {
                "type": "esql",
                "query": "FROM kibana_sample_data_logs | STATS count = COUNT() BY BUCKET(@timestamp, 75, ?_tstart, ?_tend)"
              },
              "x": {
                "column": "BUCKET(@timestamp, 75, ?_tstart, ?_tend)"
              },
              "y": [
                {
                  "column": "count"
                }
              ]
            }
          ],
          "axis": {
            "x": {
              "title": {
                "visible": false
              }
            }
          }
        }
      }
    ]
  }'
```

All examples on this page use [Kibana sample datasets](https://www.elastic.co/docs/manage-data/ingest/sample-data) (`kibana_sample_data_logs`, `kibana_sample_data_ecommerce`, `kibana_sample_data_flights`). To use your own data, replace the `FROM` pattern and field references.

### Dashboard structure

A [dashboard](https://www.elastic.co/docs/explore-analyze/dashboards) is structured as follows:

- **`title`** (required): the display name of the dashboard.
- **`panels`**: array of items placed on a 48-column grid. Each item has a `type`, a `grid` position (`x`, `y`, `w`, `h`), and a `config`. Two item shapes are supported:
  - **Panel**: any content type, including visualizations, Discover sessions, images, markdown, and filter controls. The `type` field determines the panel's content and the structure of its `config`.
  - **Section**: a collapsible group of panels. Use sections to organize a large dashboard into logical groups. A section has a `grid.y` position and its own nested `panels` array.

  The grid is 48 columns wide. Use `w: 48` for a full-width panel, `w: 24` for half-width, and so on. Height (`h`) and vertical position (`y`) are in grid rows with no fixed maximum.
- **`pinned_panels`**: filter controls pinned at the top of the dashboard that apply to all panels. Filter controls placed in `panels` apply only to panels in the same section.
- **`filters`**, **`query`**, **`time_range`**: filter the data displayed across all panels.

### Panel types

The `type` field in each panel determines what it contains and the structure of its `config`:

| Type | Description |
|------|-------------|
| `vis` | Visualization (bar, line, metric, and so on), supports both data view and ES&#124;QL queries |
| `discover_session` | Discover session |
| `image` | Image |
| `markdown` | Markdown text |
| `links` | Navigation links to dashboards and external URLs |
| `esql_control` | ES&#124;QL variable control |
| `options_list_control` | Dropdown filter by field value |
| `range_slider_control` | Slider filter by numeric range |
| `time_slider_control` | Time range slider |

Additional panel types for observability use cases:

| Type | Description |
|------|-------------|
| `slo_alerts` | SLO alerts |
| `slo_burn_rate` | SLO burn rate |
| `slo_error_budget` | SLO error budget |
| `slo_overview` | SLO overview |
| `synthetics_monitors` | Synthetics monitors |
| `synthetics_stats_overview` | Synthetics stats overview |
| `apm_service_map` | APM service map |

Additional panel types for machine learning use cases:

| Type | Description |
|------|-------------|
| `ml_single_metric_viewer` | Single metric viewer |
| `ml_anomaly_swimlane` | Anomaly swim lane |
| `ml_anomaly_charts` | Anomaly charts |
| `aiops_change_point_chart` | Change point detection chart |
| `aiops_log_rate_analysis` | Log rate analysis |
| `aiops_pattern_analysis` | Pattern analysis |
| `field_stats_table` | Field statistics table |

> info
> The following panel types are supported in the Kibana UI but not yet by the REST API: `map`, `legacy_vis`, `alerts_table`. Write operations (`POST`, `PUT`) return a `400` error when these panel types are included. Read operations (`GET`) strip these panels from the response and include them in a list of warnings.

### Embedding library items

`vis`, `discover_session`, `markdown`, and `links` panels can be embedded **inline** (full config stored in the dashboard) or **linked from library** (references a library item by ID).

For the full `config` schema for visualization panels, including chart types, metric operations, and breakdowns, refer to the [Visualizations API](visualizations#tag/Visualizations/operation/create-visualization).

- **Inline**: use when the panel is specific to this dashboard or must work across Kibana spaces. The panel configuration goes directly inside `config`:

  ```json
  {
    "grid": {
      "x": 0,
      "y": 0,
      "w": 12,
      "h": 8
    },
    "type": "vis",
    "config": {
      "type": "metric",
      "title": "Average bytes",
      "data_source": {
        "type": "data_view_spec",
        "index_pattern": "kibana_sample_data_logs",
        "time_field": "timestamp"
      },
      "metrics": [
        {
          "type": "primary",
          "operation": "average",
          "field": "bytes"
        }
      ]
    }
  }
  ```

- **Linked from library**: references an item in your library by its ID. Use `ref_id` with any supported panel type (`vis`, `discover_session`, `markdown`, `links`). Use the [Visualizations API](visualizations#tag/Visualizations/operation/create-visualization) to create and retrieve IDs for visualization items.

  ```json
  {
    "grid": {
      "x": 0,
      "y": 0,
      "w": 12,
      "h": 8
    },
    "type": "vis",
    "config": {
      "ref_id": "1e4f0a30-b3c5-11ef-bd7a-2b6b1a8c0f3d"
    }
  }
  ```

### ES|QL visualizations

To create ES|QL-based charts, embed them inline as `vis` panels and set `data_source.type` to `"esql"`.

- **`metric` charts**: reference query result columns in `metrics` using `column`:

  ```json
  {
    "grid": {
      "x": 0,
      "y": 0,
      "w": 12,
      "h": 6
    },
    "type": "vis",
    "config": {
      "type": "metric",
      "title": "Total requests",
      "data_source": {
        "type": "esql",
        "query": "FROM logs-* | STATS count = COUNT()"
      },
      "metrics": [
        {
          "type": "primary",
          "column": "count"
        }
      ]
    }
  }
  ```

- **`xy` charts**: `data_source` goes inside each layer. Use `BUCKET(@timestamp, 75, ?_tstart, ?_tend)` to align time-series buckets with the dashboard's selected time range. For a complete xy chart example, see the [Create a dashboard](#operation/create-dashboard) endpoint.

[Dashboards documentation](https://www.elastic.co/docs/explore-analyze/dashboards)

- [Search dashboards](https://www.elastic.co/elastic/docs-builder/docs/4371/api/doc/kibana/v0/operation/operation-search-dashboards): `GET` `/api/dashboards`
- [Create a dashboard](https://www.elastic.co/elastic/docs-builder/docs/4371/api/doc/kibana/v0/operation/operation-create-dashboard): `POST` `/api/dashboards`
- [Delete a dashboard](https://www.elastic.co/elastic/docs-builder/docs/4371/api/doc/kibana/v0/operation/operation-delete-dashboard): `DELETE` `/api/dashboards/{id}`
- [Get a dashboard](https://www.elastic.co/elastic/docs-builder/docs/4371/api/doc/kibana/v0/operation/operation-get-dashboard): `GET` `/api/dashboards/{id}`
- [Upsert a dashboard](https://www.elastic.co/elastic/docs-builder/docs/4371/api/doc/kibana/v0/operation/operation-upsert-dashboard): `PUT` `/api/dashboards/{id}`
