# Dashboards · REST API

> Dashboards turn a workflow's data into shareable visual summaries.

HTML version: https://developers.sheetgo.com/api/dashboards/

[Developers](/index.md) › [REST API](/api.md) › [Workflows & Automations](/api.md#api-endpoints)

REST API · 5 endpoints

## Dashboards

**Complete for this group.** Each operation below lists its parameters, request body, responses and errors. Every model they use is documented under [Models used on this page](#models), so you do not need another page to build a request. Base URL `https://api.sheetgo.com`; paths are complete, version included (`/rest/beta/…`): append them to the base URL exactly as shown; send `Authorization: Bearer sg_…`. Also in the API's own docs: <https://api.sheetgo.com/rest/reference/dashboards> ([Markdown](https://api.sheetgo.com/rest/reference/dashboards.md)).

**Conventions for every endpoint.** Lists take `page` (from 1) and `per_page` (1-100, default 50), and `total` counts **pages**, not items. Collection URLs end with `/`. `POST …/run` returns `200` when the run is *queued*; poll `GET …/run`. Google Sheets use `provider: "drive"`; column fields take letters (`"E"`). Error bodies and status codes: [REST API › Errors](/api.md#api-errors).

**Python recipes.** [API client helper](/examples.md#recipe-sheetgo-api).

**Dashboards** turn a workflow's data into shareable visual summaries. Each workflow has a single dashboard; add indicator, table and chart-reference elements to it, read an element's live values, and publish the dashboard to get a viewer URL.

Elements point at a spreadsheet's tabs and charts by id — get those from `GET /rest/beta/files/{provider}/{file_id}/structure`. Google Sheets on Google Drive only.

## Operations

#### GET `/rest/beta/workflows/{id}/dashboard` — Get a workflow's dashboard

Elements and publish state in one call. Two Mongo reads, no Sheets access.

`elements[].error` is usually null even for a broken element: render errors
are written during a build and not persisted
(workflow/controller.py:759). Read an element's `/data` to be certain it
renders.

##### Parameters

| Name | In | Type |  | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | required | Workflow identification |

##### Responses

| Status | Meaning | Body |
| --- | --- | --- |
| 200 | Elements and publish state | [`DashboardOut`](#model-DashboardOut) |
| 401 | Authentication failed or token is invalid | — |
| 403 | Not a member of the workflow | — |
| 404 | Not found | — |
| 422 | Validation Error | [`HTTPValidationError`](#model-HTTPValidationError) |

##### Example request

```
curl -s -X GET "https://api.sheetgo.com/rest/beta/workflows/ID/dashboard" \
  -H "Authorization: Bearer $SHEETGO_API_KEY"
```

In the API's own docs: <https://api.sheetgo.com/rest/reference/dashboards#get-rest-beta-workflows-id-dashboard>

#### POST `/rest/beta/workflows/{id}/dashboard/elements` — Add elements to a workflow's dashboard

Create one or more dashboard elements, atomically.

The dashboard itself needs no creating — `add_charts` brings it into being
with the first element (workflow/models.py:1806).

Every element is validated against the real spreadsheet before anything is
written, and a single failure rejects the whole batch: a partial write would
leave the caller diffing what landed. Validation uses the workflow owner's
credentials, since those are what render the dashboard later.

##### Parameters

| Name | In | Type |  | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | required | Workflow identification |

##### Request body (required)

`application/json` · array of object

##### Responses

| Status | Meaning | Body |
| --- | --- | --- |
| 201 | The created elements | array of [`ElementOut`](#model-ElementOut) |
| 400 | Malformed element | — |
| 401 | Authentication failed or token is invalid | — |
| 403 | Requires manager or owner | — |
| 404 | Not found | — |
| 409 | Chart limit reached | — |
| 422 | Source could not be validated | — |

##### Example request

```
curl -s -X POST "https://api.sheetgo.com/rest/beta/workflows/ID/dashboard/elements" \
  -H "Authorization: Bearer $SHEETGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json
```

In the API's own docs: <https://api.sheetgo.com/rest/reference/dashboards#post-rest-beta-workflows-id-dashboard-elements>

#### DELETE `/rest/beta/workflows/{id}/dashboard/elements/{element_id}` — Delete one dashboard element

Remove one element.

Deleting the LAST element removes the dashboard and takes it offline:
`remove_chart` sets `workflow.dashboard = None` and marks the publishing
record deleted (workflow/models.py:1920, :1932). Adding an element later
revives it with the same `public_id`, so the viewer URL survives.

##### Parameters

| Name | In | Type |  | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | required | Workflow identification |
| `element_id` | path | string | required | Element identification |

##### Responses

| Status | Meaning | Body |
| --- | --- | --- |
| 204 | Deleted | — |
| 401 | Authentication failed or token is invalid | — |
| 403 | Requires manager or owner | — |
| 404 | Not found | — |
| 422 | Validation Error | [`HTTPValidationError`](#model-HTTPValidationError) |

##### Example request

```
curl -s -X DELETE "https://api.sheetgo.com/rest/beta/workflows/ID/dashboard/elements/ELEMENT_ID" \
  -H "Authorization: Bearer $SHEETGO_API_KEY"
```

In the API's own docs: <https://api.sheetgo.com/rest/reference/dashboards#delete-rest-beta-workflows-id-dashboard-elements-element-id>

#### GET `/rest/beta/workflows/{id}/dashboard/elements/{element_id}/data` — Read one dashboard element's current values

Build and return one element's values.

Bounded to a single element: `get_workflow_dashboard` filters
`dashboard['data']` down to the requested id, so this is one or two Sheets
calls regardless of dashboard size. The element's `controlKey` is read from
storage, never taken from the caller — `get_chart_instance` matches on it
(workflow/dashboard/utils.py:20) and would find nothing without it.

`page`/`per_page` apply to `table` elements only.

##### Parameters

| Name | In | Type |  | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | required | Workflow identification |
| `element_id` | path | string | required | Element identification |
| `page` | query | integer | optional | Table elements only Default: `1` · Min: `1` |
| `per_page` | query | integer | optional | Table elements only Default: `50` · Min: `1` · Max: `500` |

##### Responses

| Status | Meaning | Body |
| --- | --- | --- |
| 200 | The element's current values | [`ElementDataOut`](#model-ElementDataOut) |
| 401 | Authentication failed or token is invalid | — |
| 403 | Not a member of the workflow | — |
| 404 | Not found | — |
| 422 | Validation Error | [`HTTPValidationError`](#model-HTTPValidationError) |
| 502 | The values could not be read | — |

##### Example request

```
curl -s -X GET "https://api.sheetgo.com/rest/beta/workflows/ID/dashboard/elements/ELEMENT_ID/data" \
  -H "Authorization: Bearer $SHEETGO_API_KEY"
```

In the API's own docs: <https://api.sheetgo.com/rest/reference/dashboards#get-rest-beta-workflows-id-dashboard-elements-element-id-data>

#### PUT `/rest/beta/workflows/{id}/dashboard/publish` — Publish or unpublish a workflow's dashboard

Set `shared`, `require_auth` and `auth_config.domain`.

`specific_users` and `visual_schema` are rejected. The internal PUT emails
every address in `authConfig.specificUsers` via SendGrid
(dashboard/models.py:190); refusing the field is what keeps an API key from
mailing arbitrary recipients. Both remain editable in the Sheetgo UI.

Stricter than the internal route, which requires only workflow access
(workflow/views.py:936) and so lets a collaborator publish publicly.

##### Parameters

| Name | In | Type |  | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | required | Workflow identification |

##### Request body (required)

`application/json` · object

##### Responses

| Status | Meaning | Body |
| --- | --- | --- |
| 200 | Publish state | [`PublishOut`](#model-PublishOut) |
| 400 | Malformed or unsupported field | — |
| 401 | Authentication failed or token is invalid | — |
| 403 | Requires manager or owner, or plan upgrade | — |
| 404 | Not found | — |
| 422 | Validation Error | [`HTTPValidationError`](#model-HTTPValidationError) |

##### Example request

```
curl -s -X PUT "https://api.sheetgo.com/rest/beta/workflows/ID/dashboard/publish" \
  -H "Authorization: Bearer $SHEETGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json
```

In the API's own docs: <https://api.sheetgo.com/rest/reference/dashboards#put-rest-beta-workflows-id-dashboard-publish>

## Models used on this page

Every request and response model referenced above, including nested ones (8). The full catalogue is on the [Models](/api/models.md) page.

#### `AuthConfigIn`

Access restriction. Only domain restriction is exposed.

`specificUsers` is deliberately absent: the internal PUT emails every
address in it via SendGrid (dashboard/models.py:190), which would let an
API key mail arbitrary recipients.

| Field | Type |  | Description |
| --- | --- | --- | --- |
| `domain` | boolean | required | Restrict to the workflow owner's email domain |

Used by: [PUT /rest/beta/workflows/{id}/dashboard/publish](/api/dashboards.md#put-rest-beta-workflows-id-dashboard-publish)

#### `DashboardOut`

A workflow's single dashboard: its elements and its publication state.

| Field | Type |  | Description |
| --- | --- | --- | --- |
| `elements` | array of [`ElementOut`](#model-ElementOut) | optional | Every element on the dashboard, in stored order. Empty for a workflow whose dashboard has not been built yet. |
| `publish` | [`PublishOut`](#model-PublishOut) | required | Whether the dashboard is published, and under what access restrictions. |

Used by: [GET /rest/beta/workflows/{id}/dashboard](/api/dashboards.md#get-rest-beta-workflows-id-dashboard)

#### `ElementDataOut`

One element's current values.

`page`/`per_page`/`total` are populated for `table` only; the other types
have nothing to paginate.

| Field | Type |  | Description |
| --- | --- | --- | --- |
| `data` | any | optional | The element's current values, read live from the spreadsheet. A single value for `indicator`, a list of rows for `table`, and the chart's image or reference for `chart`. |
| `id` | string | required | Id of the element these values belong to. |
| `page` | integer | nullable | Current page of rows, 1-based. Populated for `table` only. |
| `per_page` | integer | nullable | Rows per page in this response. Populated for `table` only. |
| `total` | integer | nullable | Total rows, for table elements |
| `type` | [`ElementType`](#model-ElementType) | required | The element's kind, which determines the shape of `data`. |

Used by: [GET /rest/beta/workflows/{id}/dashboard/elements/{element\_id}/data](/api/dashboards.md#get-rest-beta-workflows-id-dashboard-elements-element-id-data)

#### `ElementOut`

One stored element, in public vocabulary.

| Field | Type |  | Description |
| --- | --- | --- | --- |
| `added_by` | string | nullable | Email of the user who added the element. |
| `added_on` | string | nullable | When the element was added, ISO 8601. |
| `chart_id` | integer | nullable | Numeric id of the referenced chart. Set for `chart` elements only; get it from `GET /rest/beta/files/{provider}/{file_id}/structure`. |
| `error` | string | nullable | Stored render error, when one was persisted. Usually null even for a broken element: errors are written during a build and not saved (workflow/controller.py:759). Read the element's /data to be sure. |
| `file_id` | string | nullable | Id of the Google Sheets file the element reads from. |
| `id` | string | required | Element id. Use it for delete and data reads. |
| `range` | string | nullable | A1 range the element reads, without the tab name (for example `B2:D50`). Set for `indicator` and `table`; null for `chart`. |
| `stored_role` | string | nullable | Internal role, echoed when `type` is `other` |
| `stored_type` | string | nullable | Internal type, echoed when `type` is `other` |
| `tab_id` | integer | nullable | Numeric id of the tab the element reads from. Null for `chart` elements, which point at a chart rather than a tab. |
| `tab_name` | string | nullable | Name of that tab at the time the element was stored. Null for `chart` elements. Renaming the tab does not update this. |
| `title` | string | nullable | Label shown above the element on the dashboard. |
| `type` | [`ElementType`](#model-ElementType) | required | Element kind: `indicator` (a single value), `table` (a range of rows) or `chart` (a reference to a chart already in the spreadsheet). `other` means an element the web app created that this API does not model — see `stored_type`. |

Used by: [POST /rest/beta/workflows/{id}/dashboard/elements](/api/dashboards.md#post-rest-beta-workflows-id-dashboard-elements)

#### `ElementType`

**Type:** one of `"indicator"`, `"table"`, `"chart"`, `"other"`

Used by: [POST /rest/beta/workflows/{id}/dashboard/elements](/api/dashboards.md#post-rest-beta-workflows-id-dashboard-elements)

#### `HTTPValidationError`

| Field | Type |  | Description |
| --- | --- | --- | --- |
| `detail` | array of [`ValidationError`](#model-ValidationError) | optional |  |

Used by: [GET /rest/beta/workflows/](/api/workflows.md#get-rest-beta-workflows), [POST /rest/beta/workflows/](/api/workflows.md#post-rest-beta-workflows), [POST /rest/beta/workflows/run/{id}](/api/workflows.md#post-rest-beta-workflows-run-id), [GET /rest/beta/workflows/{id}](/api/workflows.md#get-rest-beta-workflows-id), [PATCH /rest/beta/workflows/{id}](/api/workflows.md#patch-rest-beta-workflows-id), [DELETE /rest/beta/workflows/{id}](/api/workflows.md#delete-rest-beta-workflows-id), [GET /rest/beta/workflows/{id}/collaborators](/api/workflows.md#get-rest-beta-workflows-id-collaborators), [POST /rest/beta/workflows/{id}/collaborators](/api/workflows.md#post-rest-beta-workflows-id-collaborators), [DELETE /rest/beta/workflows/{id}/collaborators](/api/workflows.md#delete-rest-beta-workflows-id-collaborators), [PATCH /rest/beta/workflows/{id}/collaborators/{email}](/api/workflows.md#patch-rest-beta-workflows-id-collaborators-email), [DELETE /rest/beta/workflows/{id}/collaborators/{email}](/api/workflows.md#delete-rest-beta-workflows-id-collaborators-email), [GET /rest/beta/workflows/{id}/destinations](/api/workflows.md#get-rest-beta-workflows-id-destinations), [GET /rest/beta/workflows/{id}/files](/api/workflows.md#get-rest-beta-workflows-id-files), [GET /rest/beta/workflows/{id}/general-access](/api/workflows.md#get-rest-beta-workflows-id-general-access), [PUT /rest/beta/workflows/{id}/general-access](/api/workflows.md#put-rest-beta-workflows-id-general-access), [DELETE /rest/beta/workflows/{id}/general-access](/api/workflows.md#delete-rest-beta-workflows-id-general-access), [POST /rest/beta/workflows/{id}/leave](/api/workflows.md#post-rest-beta-workflows-id-leave), [POST /rest/beta/workflows/{id}/request-access](/api/workflows.md#post-rest-beta-workflows-id-request-access), [GET /rest/beta/workflows/{id}/run](/api/workflows.md#get-rest-beta-workflows-id-run), [POST /rest/beta/workflows/{id}/run](/api/workflows.md#post-rest-beta-workflows-id-run), [GET /rest/beta/workflows/{id}/sources](/api/workflows.md#get-rest-beta-workflows-id-sources), [GET /rest/beta/automations/](/api/automations.md#get-rest-beta-automations), [POST /rest/beta/automations/run/{id}](/api/automations.md#post-rest-beta-automations-run-id), [GET /rest/beta/automations/{id}](/api/automations.md#get-rest-beta-automations-id), [DELETE /rest/beta/automations/{id}](/api/automations.md#delete-rest-beta-automations-id), [GET /rest/beta/automations/{id}/destinations](/api/automations.md#get-rest-beta-automations-id-destinations), [GET /rest/beta/automations/{id}/files](/api/automations.md#get-rest-beta-automations-id-files), [GET /rest/beta/automations/{id}/run](/api/automations.md#get-rest-beta-automations-id-run), [POST /rest/beta/automations/{id}/run](/api/automations.md#post-rest-beta-automations-id-run), [GET /rest/beta/automations/{id}/sources](/api/automations.md#get-rest-beta-automations-id-sources), [GET /rest/beta/workflows/{id}/trigger](/api/triggers.md#get-rest-beta-workflows-id-trigger), [DELETE /rest/beta/workflows/{id}/trigger](/api/triggers.md#delete-rest-beta-workflows-id-trigger), [GET /rest/beta/workflows/{id}/dashboard](/api/dashboards.md#get-rest-beta-workflows-id-dashboard), [DELETE /rest/beta/workflows/{id}/dashboard/elements/{element\_id}](/api/dashboards.md#delete-rest-beta-workflows-id-dashboard-elements-element-id), [GET /rest/beta/workflows/{id}/dashboard/elements/{element\_id}/data](/api/dashboards.md#get-rest-beta-workflows-id-dashboard-elements-element-id-data), [PUT /rest/beta/workflows/{id}/dashboard/publish](/api/dashboards.md#put-rest-beta-workflows-id-dashboard-publish), [GET /rest/beta/workflows/{workflow\_id}/forms/](/api/forms.md#get-rest-beta-workflows-workflow-id-forms), [POST /rest/beta/workflows/{workflow\_id}/forms/](/api/forms.md#post-rest-beta-workflows-workflow-id-forms), [GET /rest/beta/workflows/{workflow\_id}/forms/{form\_id}](/api/forms.md#get-rest-beta-workflows-workflow-id-forms-form-id), [PATCH /rest/beta/workflows/{workflow\_id}/forms/{form\_id}](/api/forms.md#patch-rest-beta-workflows-workflow-id-forms-form-id), [DELETE /rest/beta/workflows/{workflow\_id}/forms/{form\_id}](/api/forms.md#delete-rest-beta-workflows-workflow-id-forms-form-id), [GET /rest/beta/workflows/{workflow\_id}/forms/{form\_id}/responses](/api/forms.md#get-rest-beta-workflows-workflow-id-forms-form-id-responses), [HEAD /rest/beta/workflows/{workflow\_id}/forms/{form\_id}/responses](/api/forms.md#head-rest-beta-workflows-workflow-id-forms-form-id-responses), [GET /rest/beta/automations/{automation\_id}/webhook](/api/webhook.md#get-rest-beta-automations-automation-id-webhook), [GET /rest/beta/workflows/{workflow\_id}/webhooks](/api/webhook.md#get-rest-beta-workflows-workflow-id-webhooks), [GET /rest/beta/api-destination/{public\_id}](/api/api-destination.md#get-rest-beta-api-destination-public-id), [HEAD /rest/beta/api-destination/{public\_id}](/api/api-destination.md#head-rest-beta-api-destination-public-id), [GET /rest/beta/integrations/{provider}/options](/api/integrations.md#get-rest-beta-integrations-provider-options), [GET /rest/beta/outlook/messages](/api/outlook.md#get-rest-beta-outlook-messages), [POST /rest/beta/outlook/messages/batch](/api/outlook.md#post-rest-beta-outlook-messages-batch), [GET /rest/beta/outlook/messages/{message\_id}](/api/outlook.md#get-rest-beta-outlook-messages-message-id), [GET /rest/beta/outlook/messages/{message\_id}/attachments/{attachment\_id}](/api/outlook.md#get-rest-beta-outlook-messages-message-id-attachments-attachment-id), [POST /rest/beta/outlook/send](/api/outlook.md#post-rest-beta-outlook-send), [GET /rest/beta/gmail/messages](/api/gmail.md#get-rest-beta-gmail-messages), [POST /rest/beta/gmail/messages/batch](/api/gmail.md#post-rest-beta-gmail-messages-batch), [GET /rest/beta/gmail/messages/{message\_id}](/api/gmail.md#get-rest-beta-gmail-messages-message-id), [GET /rest/beta/gmail/messages/{message\_id}/attachments/{attachment\_id}](/api/gmail.md#get-rest-beta-gmail-messages-message-id-attachments-attachment-id), [POST /rest/beta/gmail/send](/api/gmail.md#post-rest-beta-gmail-send), [GET /rest/beta/files/{provider}](/api/files.md#get-rest-beta-files-provider), [GET /rest/beta/files/{provider}/roots](/api/files.md#get-rest-beta-files-provider-roots), [GET /rest/beta/files/{provider}/search](/api/files.md#get-rest-beta-files-provider-search), [GET /rest/beta/files/{provider}/{file\_id}](/api/files.md#get-rest-beta-files-provider-file-id), [GET /rest/beta/bigquery/projects](/api/bigquery.md#get-rest-beta-bigquery-projects), [GET /rest/beta/bigquery/projects/{project}/datasets](/api/bigquery.md#get-rest-beta-bigquery-projects-project-datasets), [GET /rest/beta/bigquery/projects/{project}/datasets/{dataset}/tables](/api/bigquery.md#get-rest-beta-bigquery-projects-project-datasets-dataset-tables), [GET /rest/beta/bigquery/projects/{project}/datasets/{dataset}/tables/{table}](/api/bigquery.md#get-rest-beta-bigquery-projects-project-datasets-dataset-tables-table), [POST /rest/beta/bigquery/projects/{project}/validate-query](/api/bigquery.md#post-rest-beta-bigquery-projects-project-validate-query), [POST /rest/auth/refresh](/api/auth.md#post-rest-auth-refresh), [POST /rest/auth/token](/api/auth.md#post-rest-auth-token)

#### `PublishOut`

The dashboard's current publication state.

| Field | Type |  | Description |
| --- | --- | --- | --- |
| `auth_config` | object | nullable | The access restriction applied when `require_auth` is true — `{"domain": true}` limits viewers to the owner's email domain. Null when unrestricted. |
| `public_id` | string | nullable | Stable public identifier minted at first publish; it forms the `url`. Null until the dashboard has been published once. |
| `require_auth` | boolean | optional | Whether a viewer must be signed in to open the dashboard. Only meaningful while `shared` is `public`. Default: `false` |
| `shared` | string | required | `public` if the dashboard is published and reachable at `url`, `private` if it is not. |
| `url` | string | nullable | Viewer URL; null while private and never published |

Used by: [PUT /rest/beta/workflows/{id}/dashboard/publish](/api/dashboards.md#put-rest-beta-workflows-id-dashboard-publish)

#### `ValidationError`

| Field | Type |  | Description |
| --- | --- | --- | --- |
| `loc` | array of string or integer | required |  |
| `msg` | string | required |  |
| `type` | string | required |  |
