Skip to main content

Dashboards API

BI dashboards: CRUD, layout (tabs + cards), folders, trash + bookmarks.

This page lists 15 endpoints (OpenAPI tag dashboards). It is generated from openapi.json; see the REST API overview for authentication, CSRF and error conventions.

MethodPathOperation idNotes
GET/api/ws/{workspace}/dashboardsdb_list
POST/api/ws/{workspace}/dashboardsdb_create
GET/api/ws/{workspace}/dashboards/{id}db_get
PUT/api/ws/{workspace}/dashboards/{id}db_update
DELETE/api/ws/{workspace}/dashboards/{id}db_remove
POST/api/ws/{workspace}/dashboards/{id}/bookmarkdb_bookmark_add
DELETE/api/ws/{workspace}/dashboards/{id}/bookmarkdb_bookmark_remove
POST/api/ws/{workspace}/dashboards/{id}/cards/{card_id}/datadb_card_runObject-scoped on the DASHBOARD: a dashboard:read object grant TRANSITIVELY authorizes running the data of any card on that dashboard — NO per-chart grant i...
PUT/api/ws/{workspace}/dashboards/{id}/certificationdb_set_certification
POST/api/ws/{workspace}/dashboards/{id}/duplicatedb_duplicate
PATCH/api/ws/{workspace}/dashboards/{id}/folderdb_set_folder
POST/api/ws/{workspace}/dashboards/{id}/restoredb_restore
GET/api/ws/{workspace}/dashboards/{id}/revisionsdb_revisionsReading history needs only dashboard:read — it discloses who edited the dashboard and when, which anyone who can read the dashboard can already see in the ...
POST/api/ws/{workspace}/dashboards/{id}/revisions/{revision_id}/revertdb_revision_revertRestore an earlier revision by replaying it through the ordinary update path.
POST/api/ws/{workspace}/dashboards/{id}/trashdb_trash

GET /api/ws/{workspace}/dashboards​

Operation id: db_list. Auth: Session cookie. Forbidden (403): Missing dashboard:read permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
trashedquerybooleannoList only trashed dashboards when true

Response 200 (application/json): array of DashboardSummaryDto

FieldTypeRequiredDescription
idstringyes
namestringyes
descriptionstringyes
created_bystring, nullableno
folder_idstring, nullableno
card_countinteger (int64)yes
updated_atstring (date-time)yes
bookmarkedbooleanyes
certifiedbooleanyesA steward has vouched for this dashboard. Display only — the list carries no certified_by, since the badge here answers "is it trusted", and "by whom" is a question the detail page already answers.
can_managebooleanyesWhether this caller may run the list's mutating actions — duplicate, move, trash, delete.
StatusMeaning
200Dashboards in the workspace
401Not authenticated
403Missing dashboard:read permission
500Internal error

POST /api/ws/{workspace}/dashboards​

Operation id: db_create. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug

Request body (application/json): CreateDashboard

FieldTypeRequiredDescription
namestringyes
descriptionstringno

Response 200 (application/json): DashboardDetailDto

FieldTypeRequiredDescription
idstringyes
namestringyes
descriptionstringyes
parametersobjectyes
created_bystring, nullableno
created_by_namestring, nullablenoDisplay name for created_by — the profile name, else the email. Resolved server-side: the endpoints that can turn a user id into a name are admin-gated, so the browser cannot do it for an ordinary workspace editor. Same shape and same...
created_atstring (date-time), nullablenoNULL for dashboards predating migration 0106, which does not invent a creation date.
updated_bystring, nullableno
updated_by_namestring, nullablenoDisplay name for updated_by, resolved the same way as created_by_name.
updated_atstring (date-time)yes
folder_idstring, nullablenoThe folder this dashboard is filed under; NULL = Uncategorized. Present on DashboardSummaryDto since folders shipped, and absent here until now, which is why the info sidebar had no folder to name.
widthstringyes
certifiedbooleanyesMarked as trusted by a steward. Same three fields datasets and metrics have carried since 0098, so "is this certified" is one question across the product rather than three.
certified_bystringyesWho certified it, as their email — the string is read by whoever sees the badge, and a uuid would tell them nothing. Empty while certified is false.
certification_detailsstringyesWhy, in the certifier's words. Empty is allowed: a certification with no note is still a certification.
can_managebooleanyesMay the CALLER edit this dashboard? Workspace-scoped dashboard:manage, answered by the PDP — the session's permission list carries platform grants only and can never contain it.
deleted_atstring (date-time), nullableno
bookmarkedbooleanyes
tabsDashboardTabDto[]yes
cardsDashboardCardDto[]yes
StatusMeaning
200Dashboard created (empty layout)
401Not authenticated
403Missing dashboard:manage permission
500Internal error

GET /api/ws/{workspace}/dashboards/{id}​

Operation id: db_get. Auth: Session cookie. Forbidden (403): Missing dashboard:read permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Response 200 (application/json): DashboardDetailDto

FieldTypeRequiredDescription
idstringyes
namestringyes
descriptionstringyes
parametersobjectyes
created_bystring, nullableno
created_by_namestring, nullablenoDisplay name for created_by — the profile name, else the email. Resolved server-side: the endpoints that can turn a user id into a name are admin-gated, so the browser cannot do it for an ordinary workspace editor. Same shape and same...
created_atstring (date-time), nullablenoNULL for dashboards predating migration 0106, which does not invent a creation date.
updated_bystring, nullableno
updated_by_namestring, nullablenoDisplay name for updated_by, resolved the same way as created_by_name.
updated_atstring (date-time)yes
folder_idstring, nullablenoThe folder this dashboard is filed under; NULL = Uncategorized. Present on DashboardSummaryDto since folders shipped, and absent here until now, which is why the info sidebar had no folder to name.
widthstringyes
certifiedbooleanyesMarked as trusted by a steward. Same three fields datasets and metrics have carried since 0098, so "is this certified" is one question across the product rather than three.
certified_bystringyesWho certified it, as their email — the string is read by whoever sees the badge, and a uuid would tell them nothing. Empty while certified is false.
certification_detailsstringyesWhy, in the certifier's words. Empty is allowed: a certification with no note is still a certification.
can_managebooleanyesMay the CALLER edit this dashboard? Workspace-scoped dashboard:manage, answered by the PDP — the session's permission list carries platform grants only and can never contain it.
deleted_atstring (date-time), nullableno
bookmarkedbooleanyes
tabsDashboardTabDto[]yes
cardsDashboardCardDto[]yes
StatusMeaning
200Dashboard detail (tabs + cards)
401Not authenticated
403Missing dashboard:read permission
404No such dashboard in this workspace
500Internal error

PUT /api/ws/{workspace}/dashboards/{id}​

Operation id: db_update. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Request body (application/json): UpdateDashboard

FieldTypeRequiredDescription
namestringyes
descriptionstringno
parametersobjectno
widthstringno
tabsNewTabInput[]no
cardsCardInput[]no

Response 200 (application/json): DashboardDetailDto

FieldTypeRequiredDescription
idstringyes
namestringyes
descriptionstringyes
parametersobjectyes
created_bystring, nullableno
created_by_namestring, nullablenoDisplay name for created_by — the profile name, else the email. Resolved server-side: the endpoints that can turn a user id into a name are admin-gated, so the browser cannot do it for an ordinary workspace editor. Same shape and same...
created_atstring (date-time), nullablenoNULL for dashboards predating migration 0106, which does not invent a creation date.
updated_bystring, nullableno
updated_by_namestring, nullablenoDisplay name for updated_by, resolved the same way as created_by_name.
updated_atstring (date-time)yes
folder_idstring, nullablenoThe folder this dashboard is filed under; NULL = Uncategorized. Present on DashboardSummaryDto since folders shipped, and absent here until now, which is why the info sidebar had no folder to name.
widthstringyes
certifiedbooleanyesMarked as trusted by a steward. Same three fields datasets and metrics have carried since 0098, so "is this certified" is one question across the product rather than three.
certified_bystringyesWho certified it, as their email — the string is read by whoever sees the badge, and a uuid would tell them nothing. Empty while certified is false.
certification_detailsstringyesWhy, in the certifier's words. Empty is allowed: a certification with no note is still a certification.
can_managebooleanyesMay the CALLER edit this dashboard? Workspace-scoped dashboard:manage, answered by the PDP — the session's permission list carries platform grants only and can never contain it.
deleted_atstring (date-time), nullableno
bookmarkedbooleanyes
tabsDashboardTabDto[]yes
cardsDashboardCardDto[]yes
StatusMeaning
200Dashboard metadata + layout replaced
400Invalid layout (tab/card mismatch) or width not 'fixed'/'full'
401Not authenticated
403Missing dashboard:manage permission
404No such dashboard, or a referenced chart not in this workspace
500Internal error

DELETE /api/ws/{workspace}/dashboards/{id}​

Operation id: db_remove. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Response 200 (application/json): Ack

FieldTypeRequiredDescription
okbooleanyes
StatusMeaning
200Dashboard deleted
401Not authenticated
403Missing dashboard:manage permission
404No such dashboard in this workspace
500Internal error

POST /api/ws/{workspace}/dashboards/{id}/bookmark​

Operation id: db_bookmark_add. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:read permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Response 200 (application/json): Ack

FieldTypeRequiredDescription
okbooleanyes
StatusMeaning
200Dashboard bookmarked for the caller
401Not authenticated
403Missing dashboard:read permission
404No such dashboard in this workspace
500Internal error

DELETE /api/ws/{workspace}/dashboards/{id}/bookmark​

Operation id: db_bookmark_remove. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:read permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Response 200 (application/json): Ack

FieldTypeRequiredDescription
okbooleanyes
StatusMeaning
200Dashboard bookmark removed for the caller
401Not authenticated
403Missing dashboard:read permission
404No such dashboard in this workspace
500Internal error

POST /api/ws/{workspace}/dashboards/{id}/cards/{card_id}/data​

Operation id: db_card_run. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): No dashboard:read grant on this dashboard.

Object-scoped on the DASHBOARD: a dashboard:read object grant TRANSITIVELY authorizes running the data of any card on that dashboard — NO per-chart grant is needed. The card must belong to the path dashboard (else 404). Runs the card chart's persisted query, optionally merged with resolved dashboard-parameter filters from the request body, so a shared viewer can view the card's (filtered) data without any query:run permission.

The body is OPTIONAL (a body-less call runs the saved query unfiltered). Incoming filters are appended to the persisted spec.filters and validated by compile_chart_sql → chartquery::build, which resolves every filter col against the dataset's real columns (an unknown column → 400) and renders the values/operators through the injection-safe sql_literal/FilterOp path. The client cannot inject a predicate on an arbitrary column.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
card_idpathstring (uuid)yesCard id (must belong to the dashboard)
workspacepathstringyes

Request body (application/json): CardRunBody

FieldTypeRequiredDescription
filtersFilter[]noResolved, dashboard-param-derived filters to AND onto the card's saved query.
temporal_unitsobjectnoResolved temporal_unit dashboard-param overrides: dimension column name -> temporal unit token (e.g. "month"). Each token is validated against the TemporalUnit enum by chartquery::build (an unknown token → 400) and rendered as an...

Response 200 (application/json): ChartRunResponse

FieldTypeRequiredDescription
columnsColumnMeta[]yes
rowsobject[][]yesRow-major cell values; each inner vec is one row aligned to columns.
StatusMeaning
200The card's chart SAVED query (with dashboard filters), executed: columns + rows
400Card has no chart, its saved spec is invalid, or a filter references an unknown column
401Not authenticated
403No dashboard:read grant on this dashboard
404No such dashboard, or the card is not on this dashboard
500Internal error
502Query engine error

PUT /api/ws/{workspace}/dashboards/{id}/certification​

Operation id: db_set_certification. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:certify permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Request body (application/json): SetDashboardCertification

FieldTypeRequiredDescription
certifiedbooleanyes
detailsstringnoFree text explaining the certification. Ignored when certified is false — withdrawing clears the note rather than leaving a stale justification attached.

Response 200 (application/json): DashboardDetailDto

FieldTypeRequiredDescription
idstringyes
namestringyes
descriptionstringyes
parametersobjectyes
created_bystring, nullableno
created_by_namestring, nullablenoDisplay name for created_by — the profile name, else the email. Resolved server-side: the endpoints that can turn a user id into a name are admin-gated, so the browser cannot do it for an ordinary workspace editor. Same shape and same...
created_atstring (date-time), nullablenoNULL for dashboards predating migration 0106, which does not invent a creation date.
updated_bystring, nullableno
updated_by_namestring, nullablenoDisplay name for updated_by, resolved the same way as created_by_name.
updated_atstring (date-time)yes
folder_idstring, nullablenoThe folder this dashboard is filed under; NULL = Uncategorized. Present on DashboardSummaryDto since folders shipped, and absent here until now, which is why the info sidebar had no folder to name.
widthstringyes
certifiedbooleanyesMarked as trusted by a steward. Same three fields datasets and metrics have carried since 0098, so "is this certified" is one question across the product rather than three.
certified_bystringyesWho certified it, as their email — the string is read by whoever sees the badge, and a uuid would tell them nothing. Empty while certified is false.
certification_detailsstringyesWhy, in the certifier's words. Empty is allowed: a certification with no note is still a certification.
can_managebooleanyesMay the CALLER edit this dashboard? Workspace-scoped dashboard:manage, answered by the PDP — the session's permission list carries platform grants only and can never contain it.
deleted_atstring (date-time), nullableno
bookmarkedbooleanyes
tabsDashboardTabDto[]yes
cardsDashboardCardDto[]yes
StatusMeaning
200Updated dashboard
401Not authenticated
403Missing dashboard:certify permission
404No such dashboard in this workspace
500Internal error

POST /api/ws/{workspace}/dashboards/{id}/duplicate​

Operation id: db_duplicate. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id to duplicate
workspacepathstringyes

Response 200 (application/json): DashboardDetailDto

FieldTypeRequiredDescription
idstringyes
namestringyes
descriptionstringyes
parametersobjectyes
created_bystring, nullableno
created_by_namestring, nullablenoDisplay name for created_by — the profile name, else the email. Resolved server-side: the endpoints that can turn a user id into a name are admin-gated, so the browser cannot do it for an ordinary workspace editor. Same shape and same...
created_atstring (date-time), nullablenoNULL for dashboards predating migration 0106, which does not invent a creation date.
updated_bystring, nullableno
updated_by_namestring, nullablenoDisplay name for updated_by, resolved the same way as created_by_name.
updated_atstring (date-time)yes
folder_idstring, nullablenoThe folder this dashboard is filed under; NULL = Uncategorized. Present on DashboardSummaryDto since folders shipped, and absent here until now, which is why the info sidebar had no folder to name.
widthstringyes
certifiedbooleanyesMarked as trusted by a steward. Same three fields datasets and metrics have carried since 0098, so "is this certified" is one question across the product rather than three.
certified_bystringyesWho certified it, as their email — the string is read by whoever sees the badge, and a uuid would tell them nothing. Empty while certified is false.
certification_detailsstringyesWhy, in the certifier's words. Empty is allowed: a certification with no note is still a certification.
can_managebooleanyesMay the CALLER edit this dashboard? Workspace-scoped dashboard:manage, answered by the PDP — the session's permission list carries platform grants only and can never contain it.
deleted_atstring (date-time), nullableno
bookmarkedbooleanyes
tabsDashboardTabDto[]yes
cardsDashboardCardDto[]yes
StatusMeaning
200Dashboard duplicated (layout copied)
401Not authenticated
403Missing dashboard:manage permission
404No such dashboard in this workspace
500Internal error

PATCH /api/ws/{workspace}/dashboards/{id}/folder​

Operation id: db_set_folder. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Request body (application/json): SetFolder

FieldTypeRequiredDescription
folder_idstring (uuid), nullableno

Response 200 (application/json): Ack

FieldTypeRequiredDescription
okbooleanyes
StatusMeaning
200Dashboard moved to folder
401Not authenticated
403Missing dashboard:manage permission
404No such dashboard or target folder in this workspace
500Internal error

POST /api/ws/{workspace}/dashboards/{id}/restore​

Operation id: db_restore. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Response 200 (application/json): Ack

FieldTypeRequiredDescription
okbooleanyes
StatusMeaning
200Dashboard restored from trash
401Not authenticated
403Missing dashboard:manage permission
404No such dashboard in this workspace
500Internal error

GET /api/ws/{workspace}/dashboards/{id}/revisions​

Operation id: db_revisions. Auth: Session cookie. Forbidden (403): Missing dashboard:read permission.

Reading history needs only dashboard:read — it discloses who edited the dashboard and when, which anyone who can read the dashboard can already see in the info sidebar. Reverting needs dashboard:manage, because it writes.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Response 200 (application/json): array of DashboardRevisionDto

FieldTypeRequiredDescription
idstringyes
kindstringyesbaseline | edit | revert — see migration 0107.
created_atstring (date-time)yes
created_bystring, nullableno
created_by_namestring, nullablenoDisplay name for created_by, resolved server-side for the same reason DashboardDetailDto.created_by_name is.
is_currentbooleanyesTrue for the revision that matches the dashboard's live state — the newest one. The client suppresses the revert action on it rather than deriving "newest" from the array order, which would silently become wrong the day the endpoint gains a...
StatusMeaning
200Revision history, newest first (at most 20 — see migration 0107)
401Not authenticated
403Missing dashboard:read permission
404No such dashboard in this workspace
500Internal error

POST /api/ws/{workspace}/dashboards/{id}/revisions/{revision_id}/revert​

Operation id: db_revision_revert. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

Restore an earlier revision by replaying it through the ordinary update path.

The snapshot CARRIES the card and tab ids it was taken with, so a revert keeps the id of every card that still exists instead of renumbering the whole dashboard. Nothing is remapped here: replace_layout decides what an id means, and it honours one only when this dashboard already owns it — a card deleted since the revision comes back with a fresh id, and an id that never belonged here cannot be adopted. (This is still NOT DashboardRepo::duplicate, which needs a tab_map because it copies rows into a DIFFERENT dashboard.)

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
revision_idpathstring (uuid)yesRevision to restore (must belong to this dashboard)
workspacepathstringyes

Response 200 (application/json): DashboardDetailDto

FieldTypeRequiredDescription
idstringyes
namestringyes
descriptionstringyes
parametersobjectyes
created_bystring, nullableno
created_by_namestring, nullablenoDisplay name for created_by — the profile name, else the email. Resolved server-side: the endpoints that can turn a user id into a name are admin-gated, so the browser cannot do it for an ordinary workspace editor. Same shape and same...
created_atstring (date-time), nullablenoNULL for dashboards predating migration 0106, which does not invent a creation date.
updated_bystring, nullableno
updated_by_namestring, nullablenoDisplay name for updated_by, resolved the same way as created_by_name.
updated_atstring (date-time)yes
folder_idstring, nullablenoThe folder this dashboard is filed under; NULL = Uncategorized. Present on DashboardSummaryDto since folders shipped, and absent here until now, which is why the info sidebar had no folder to name.
widthstringyes
certifiedbooleanyesMarked as trusted by a steward. Same three fields datasets and metrics have carried since 0098, so "is this certified" is one question across the product rather than three.
certified_bystringyesWho certified it, as their email — the string is read by whoever sees the badge, and a uuid would tell them nothing. Empty while certified is false.
certification_detailsstringyesWhy, in the certifier's words. Empty is allowed: a certification with no note is still a certification.
can_managebooleanyesMay the CALLER edit this dashboard? Workspace-scoped dashboard:manage, answered by the PDP — the session's permission list carries platform grants only and can never contain it.
deleted_atstring (date-time), nullableno
bookmarkedbooleanyes
tabsDashboardTabDto[]yes
cardsDashboardCardDto[]yes
StatusMeaning
200Dashboard restored to the revision; the restored state is itself recorded as a new revision
400The stored snapshot is not a valid dashboard layout
401Not authenticated
403Missing dashboard:manage permission
404No such dashboard or revision, or a chart the revision references no longer exists in this workspace
500Internal error

POST /api/ws/{workspace}/dashboards/{id}/trash​

Operation id: db_trash. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing dashboard:manage permission.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesDashboard id
workspacepathstringyes

Response 200 (application/json): Ack

FieldTypeRequiredDescription
okbooleanyes
StatusMeaning
200Dashboard moved to trash
401Not authenticated
403Missing dashboard:manage permission
404No such dashboard in this workspace
500Internal error