---
title: "Restore an element to a prior version."
method: POST
path: "/v1/dashboards/{id}/pages/{pageId}/elements/{elementId}/restore"
tags: ["dashboards"]
---

# Restore an element to a prior version.

`POST /v1/dashboards/{id}/pages/{pageId}/elements/{elementId}/restore`

## Request

- Base URL: `http://localhost:8080`
- URL: `http://localhost:8080/v1/dashboards/{id}/pages/{pageId}/elements/{elementId}/restore`
- Auth: one of:
  - API key in cookie `dvt_session`
  - HTTP bearer

Reverts the element's content (type, title, data, spec, overrides) to the chosen
revision. Restore is a forward edit — a new revision is written and the element's
version increments — so history stays append-only. Grid coordinates are page-owned
and are not changed by an element restore. A new dashboard revision is written so
GET /v1/dashboards/{id} stays consistent.

Provenance (DVT-1792): a required `reason` explains why the element was rolled back; it is
propagated into the dashboard revision's change summary so the Versions tab shows why.

## Request body

- ElementRestoreRequest: Element restore request. Unlike the shared RestoreRequest, `reason` is required (DVT-1792): every element write must carry a "why" that is propagated into the dashboard revision's change summary. The reason may also be supplied via the `X-Dvt-Change-Reason` header.
  - `version` integer, required: The prior element version to restore (from GET .../revisions).
  - `reason` string, required: Required provenance note (the "why") explaining the rollback; recorded on the new element revision (DVT-1658) and propagated into the dashboard revision's change summary (DVT-1792). 1–280 characters.

## Response `200`

Element restored; returns the new element + themeContext.

- ElementEnvelope
  - `data` Element, required: A single dashboard element, fetched or patched without the rest of the spec. `themeContext`/`dvtRefs` are present on responses to let an agent interpret the element in isolation.
    - `elementId` string, uuid, required: Durable UUID primary key.
    - `slug` string, required: Readable, dashboard-scoped reference (the authored panel id), e.g. "panel-revenue".
    - `pageId` string, uuid, required
    - `dashboardId` string, uuid, required
    - `type` string, required
    - `title` string
    - `subtitle` string: Optional panel subtitle (POLISH-16).
    - `x` integer, required
    - `y` integer, required
    - `w` integer, required
    - `h` integer, required
    - `zIndex` integer
    - `data` object: Panel data binding (sourceId, query/metricRef, params, optional baked rows).
    - `spec` object: The element body (near-passthrough to ECharts); token references stay unresolved.
    - `overrides` object: Per-element token overrides.
    - `drill` object: Legacy drill-down block (POLISH-16).
    - `contextMenu` object: Right-click context menu binding (POLISH-16).
    - `brush` object: Brush-select interaction binding (POLISH-16).
    - `onClick` object: Single bare click-action binding — filter, drill, or openOverlay (POLISH-16).
    - `themeContext` object: Resolved values of every theme token this element references.
    - `resolvedTokens` object: The FULL resolved theme token map for this element — every key the tier stack (org baseline / preset / dashboard / page / element overrides) declares, i.e. the renderer's own ResolvedTokens (web/src/tokens.ts), not the referenced-token subset in `themeContext`. Present on GET-single-element responses only, and only when the caller opts in via `?include=themeTokens` (DVT-4298). A consumer that must reproduce what the browser PAINTED needs it: a table's header row is styled from `panel.background` and `text.secondary`, which no panel spec references, so `themeContext` cannot carry them and a formatted export built from it would fall back to default header colors.
    - `dvtRefs` string[]: Named $dvtRef registry keys the element uses (e.g. "formatter:pie-label").
    - `version` integer, required: Optimistic-concurrency version. Pass this back on PATCH.
    - `provenance` ElementProvenance: Bounded creation/last-edit summary for a single element (DVT-1665). `createdBy` is the version=1 revision's actor; `lastEdit` is the newest revision's actor. `revisionCount` is the total number of revisions (versions are sequential 1..N).
      - `createdBy` ElementProvenanceActor, required: Actor attribution for one point in an element's history (creation or most recent edit). `reason` and `version` are only meaningful on the `lastEdit` position — absent on `createdBy`.
        - `actorType` 'user' | 'agent' | 'system', required
        - `actorName` string: Resolved display name (display_name, else email). Absent for a system write with no actor.
        - `actorLabel` string: "via {key}" credential label (API-key name / MCP client id). Absent for first-party UI edits.
        - `createdAt` string, date-time, required
        - `reason` string: Optional user/agent-authored "why" for this revision. Only set on `lastEdit`.
        - `version` integer: The revision version this actor corresponds to. Only set on `lastEdit`.
      - `lastEdit` ElementProvenanceActor, required: Actor attribution for one point in an element's history (creation or most recent edit). `reason` and `version` are only meaningful on the `lastEdit` position — absent on `createdBy`.
        - `actorType` 'user' | 'agent' | 'system', required
        - `actorName` string: Resolved display name (display_name, else email). Absent for a system write with no actor.
        - `actorLabel` string: "via {key}" credential label (API-key name / MCP client id). Absent for first-party UI edits.
        - `createdAt` string, date-time, required
        - `reason` string: Optional user/agent-authored "why" for this revision. Only set on `lastEdit`.
        - `version` integer: The revision version this actor corresponds to. Only set on `lastEdit`.
      - `revisionCount` integer, required
  - `meta` Meta, required: Response metadata.
    - `requestId` string, required: Correlates with the X-Request-Id header.
    - `total` integer: Item count, present on collection responses.
    - `nextCursor` string, nullable: Opaque keyset-pagination cursor, present on paginated responses (e.g. GET /v1/dashboards) when more rows exist beyond this page. Pass it back as the `cursor` query param to fetch the next page; absent or null on the last page.
    - `roleResolveDegraded` boolean: Snowflake mode only (DVT-2260), on GET /v1/dashboards: present and true when the caller's live Snowflake role resolution failed or was unavailable — role-shared dashboards may be missing from this page. Omitted (not merely false) whenever resolution succeeded or the role-share arm does not apply (off snowflake mode, an org admin/owner, or off the ingress listener).

## Other responses

- `400`: Malformed request, or a `python` panel this write seam refused (ADR-0084 D2/I7). Distinguished by the Problem `type`; every python refusal also echoes its slug in the `X-Dvt-Error-Code` response header: - `https://docs.dvt.dev/errors/bad-request` (the default) — a malformed or otherwise invalid request body. - `https://docs.dvt.dev/errors/python-source-unknown` — a python panel's `data.sourceId` names no live connection in this organization. A connection in ANOTHER organization reads identically, by design. List the ones you can use with `GET /v1/connections`. - `https://docs.dvt.dev/errors/python-source-not-snowflake` — the panel's source resolves but is not a Snowflake connection. A python panel executes as an anonymous procedure inside Snowflake and has nowhere else to run; express the panel as SQL against the current source instead. - `https://docs.dvt.dev/errors/python-source-not-pushdown` — the source is Snowflake but a `writeback`-kind connection (a Sheets flush target, not a queryable source). Point `data.sourceId` at a pushdown connection. Only a write that ADDS or CHANGES a python panel is checked: a title-, layout-, or geometry-only edit of one already stored is an ordinary dashboard write, and deleting one is never an authoring act.
- `401`: Missing, invalid, or expired session.
- `403`: The caller's role does not permit this action, or a `python` panel this write seam refused on identity grounds (ADR-0084 D2/I7). Distinguished by the Problem `type`: - `https://docs.dvt.dev/errors/forbidden` — the caller's role does not permit this action; for a python panel, it lacks the `python:author` capability (the editor floor), or an API key's scopes exclude it. - `https://docs.dvt.dev/errors/not-in-edition` — python panels are not available on this deployment at all (`editionCapabilities.pythonPanels` is false). **The 1.0.20 Snowflake native app ships `PYTHON_PANELS_ENABLED="true"` as of DVT-4453** (risk accepted 2026-09-19; ADR-0084 H5 remains a hard gate for the next cut, not a closed item), so this response is no longer expected there by default. On the native app the literal is baked into the package at build time, so it would fire again only after a provider-side package patch from dvt turns it back off — a consumer install cannot flip it itself; the in-account lever is the `python:author` editor floor via the app roles. On Gallery and Enterprise it fires whenever the operator's own env literal is off. Same shape as the linked-Sheet cell gate's refusal. Use a SQL-backed panel, or ask your dvt operator. - `https://docs.dvt.dev/errors/python-author-requires-admin` — the panel's source is a SHARED-credential connection (any `service_*` auth method, the internal `platform_managed` one, or `cloud_iam`, which is the server's own ambient workload identity), so the authored code would run under a credential no viewer holds: authoring it requires the admin/owner rank, over and above `python:author`. Also echoed in `X-Dvt-Error-Code`. Only the two caller's-rights methods keep the editor floor — `oauth_passthrough` and `spcs_token`, each of which opens the warehouse session as the acting user.
- `404`: Resource does not exist.
- `422`: The spec failed JSON Schema validation. `fields` lists each violation.

---

[API](https://skmtc.dev/dvt/apis/dvt-rest-api.md) · [All operations](https://skmtc.dev/dvt/apis/dvt-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dvt/apis/dvt-rest-api/revisions/00016f504165?raw)
