---
title: "The authenticated principal."
method: GET
path: "/v1/me"
tags: ["auth"]
---

# The authenticated principal.

`GET /v1/me`

## Request

- Base URL: `http://localhost:8080`
- URL: `http://localhost:8080/v1/me`
- Auth: one of:
  - API key in cookie `dvt_session`
  - HTTP bearer

Returns the current user, their organization, and their org-level role.

## Response `200`

The current principal.

- object
  - `data` Me: The authenticated principal — user, organization, org-level role, and capabilities.
    - `user` object, required
      - `id` string, uuid, required
      - `email` string, required
      - `displayName` string, required: Presentation label, not an identifier — machine logins (e.g. raw Snowflake usernames) are humanized for display (DVT-2298). Compare against id or email, never this.
      - `firstName` string: First-name-only presentation label for the opening-page greeting (DVT-3170) — separate from displayName (used by the sidebar identity block) so the client never derives one by splitting the other. Same humanization/never-guessed rules as displayName; can be empty when no name is known at all.
      - `snowflakeUser` string: The caller's own Snowflake login (DVT-3195) — the citext key the snowflake-mode header-auth path resolves on, and the value that still names a real Snowflake user after a display-name change. Distinct from displayName, which is humanized for presentation and must never be put in SQL. Present only in snowflake edition, and only for an identity with a Snowflake login behind it (omitted for gallery/enterprise, the system actor, and on any read error); for an agent actor it names the owning human. The Getting-started page prefills the PAT form's login field from it — a client must render correctly without it.
      - `type` string, required: Principal type: user or system.
      - `verifiedEmail` string, nullable: The address the caller proved in dvt via POST /v1/me/email-verification (DVT-5182). Null when unverified, when the proof is older than 180 days, outside the snowflake edition, or on a read error.
      - `verifiedEmailAt` string, date-time, nullable: When verifiedEmail was proved; null exactly when verifiedEmail is null.
    - `org` object, required
      - `id` string, uuid, required
      - `role` 'viewer' | 'editor' | 'admin' | 'owner', required
      - `slug` string, required: URL segment for path-based org routes (/o/{slug}, DVT-923/DVT-927). Stable once assigned (org renames do not re-slug). Best-effort: empty string on a read error or for a pre-backfill org not yet healed — clients fall back to the org UUID.
      - `allowMemberApiKeys` boolean, required: Org policy (DVT-342): when true, members may create their own API keys without the admin or owner role. Admins/owners always have full key management regardless of this flag.
      - `linkedSheetsEnabled` boolean: Admin kill switch for native linked sheets (ADR-0078 R1, DVT-2935/DVT-3220): when true, the org may use the native snowflake-mode linked-sheets flow (replaces the per-connection linkedBaseOptIn ack). Unset defaults to true (DVT-5637); a read error or an explicit false is false. Intentionally NOT in `required` above — additive/optional so an older client/fixture predating the field still typechecks (same rollout-symmetry convention as firstName).
      - `claudeOauthClientId` string, nullable: The org's company Claude connector OAuth client ID (DVT-5116), set via `PATCH /v1/orgs/{orgId}/settings`. Visible to every org member. Null when unset or on a read error. Not in `required` (rollout symmetry, same as linkedSheetsEnabled); the server always emits it.
      - `isSandbox` boolean, required: True for ephemeral demo sandbox orgs (ADR-0042). Clients branch onboarding to a sample-data tour (no "connect a source") on this (DVT-759).
      - `trialEndsAt` string, date-time, nullable: UTC timestamp when the trial expires (ADR-0052 D1, DVT-748). Null for non-trial orgs and for trial orgs whose clock has not yet started (trial_ends_at IS NULL until the first query against an org-owned connection, or the first CSV upload, activates the trial — DVT-1789, DVT-4655). Best-effort: absent/null when the read fails — /v1/me never fails on this.
      - `branding` object: Org branding for first-paint chrome (ADR-0037). Omitted when no branding row exists. logoLightUrl / logoDarkUrl are resolved URLs; DVT-328 owns resolution (always null here).
        - `appName` string, nullable
        - `accentColor` string, nullable
        - `logoLightUrl` string, nullable
        - `logoDarkUrl` string, nullable
        - `themeTokens` object, nullable
        - `defaultAppearance` 'light', nullable: Org-level default appearance. Light only (the dark app shell was removed, DVT-5272); null means light.
        - `logoScale` number, float, nullable: Header-logo size multiplier (1.0 = default). Null means "use dvt default" (1.0).
        - `accentGradient` AccentGradient: N-stop gradient accent (ADR-0037 / DVT-332). A single angle applies to the whole gradient; 2–8 stops each carry a color and a 0–100 position. Structure + per-stop color safety are validated server-side (spec.ValidateAccentGradient reuses the solid accent's ColorTokenValue gate, so url()/image-set() sinks are rejected). Render-time legibility (white text on the lightest stop) is a client-side gate, not stored here.
          - `angle` number, required: Gradient angle in degrees (CSS linear-gradient convention).
          - `stops` object[], required: Color stops, 2–8 entries.
            - `color` string, required: Stop color — hex/rgb()/hsl() literal, CSS named color, or {token.ref}; CSS resource functions (url(), image-set()) are rejected (ADR-0032 §2).
            - `at` number, required: Stop position as a percentage (0–100).
        - `chromeTextColor` string, nullable: Manual override for the header/sidebar foreground text (DVT-332). Null = auto (the shell picks white or near-black by the accent's luminance).
        - `showAppName` boolean, nullable: Whether the product name renders in the header alongside a logo (DVT-332). Null = default (true).
    - `capabilities` string[], required: The `resource:action` capabilities the caller's role holds (ADR-0025). Clients should gate UI on these rather than hardcoding role names, so per-org custom roles work without client changes. Always present (never null). The set is a versioned contract — renaming/removing a value is a breaking change.
    - `plan` string: The org's current entitlement tier (DVT-117), resolved per request. Clients render tier-aware UI (trial banners, locked state) from this; capability gating still uses `capabilities`. Current values: "default"/"gallery" (full), "free" (floor), "read_only_grace"/"locked" (post-expiry trial tiers, ADR-0052 D5), or "" when the tier could not be resolved (fail-closed — capabilities will be empty). Deliberately not enum-constrained so new tiers don't break the contract.
    - `onboarding` object: The caller's Getting Started engagement state (DVT-743). Each flag flips true when the user engages that step on the Getting Started page (engaged, not necessarily completed). The client auto-retires the onboarding nav item + landing card once all three are true, or 7 days after `firstLoginAt`.
      - `explored` boolean, required
      - `connected` boolean, required
      - `asked` boolean, required
      - `warehouse` boolean: Getting Started step, and the ONE onboarding flag whose meaning is edition-dependent (DVT-3197): in gallery/enterprise it means "engaged the warehouse-connection education surface" (DVT-1620); in snowflake edition there is no warehouse to connect (the host account is the only source, ADR-0066 r3.4) and the flag instead means "engaged the step that grants dvt access to your data". Same flag, same wire shape, different step — clients rendering a label for it must branch on `edition`. See docs/editions.md. Intentionally NOT in `required` — additive rollout field, same convention as onboarding/firstLoginAt/plan on `Me` — so older clients that don't know about it are unaffected.
      - `welcomed` boolean: Getting Started step: engaged the welcome/intro surface (DVT-1620). Intentionally NOT in `required` — additive rollout field, same convention as onboarding/firstLoginAt/plan on `Me`.
    - `firstLoginAt` string, date-time, nullable: Timestamp of the caller's first successful login — the 7-day anchor for the onboarding auto-retire (DVT-743). Null only when unknown (e.g. a transient read error).
    - `snowflakeAppName` string: The Native App's own application name (DVT-3194) — a Snowflake object name, captured from CURRENT_DATABASE() when the setup script runs. The snowflake-mode Getting-started page splices it into the GRANT statements it hands the reader, so they copy SQL naming their real app instead of an `<APP>` placeholder they have to fill in themselves. NOT org branding: that is `org.branding.appName`, a customer-set display label; this is never user-editable. Intentionally NOT in `required` — additive rollout field, same convention as onboarding/firstLoginAt/plan. Omitted on every non-Native-App deployment and on any install whose value fails the identifier guard; absent means "keep showing the placeholder" and is never an error state, so the page it feeds must render correctly without it.
    - `agentDefaultFqn` string: The deployment's default Cortex agent FQN (`database.schema.agent`) for the app-chrome agent popup (DVT-3692). Read from the api container's own `DVT_AGENT_ALLOWLIST` — the value DVT-3691 renders onto both containers (the dvt-api copy was pulled for patch 6 / 1.0.18 by DVT-4153 and restored by DVT-3962), `<APP_DB>.APP_SPCS.DVT_AGENT` where `register_agent()` registered — so it is by construction a member of the engine's allowlist, the only thing that admits an FQN. First non-blank entry of that list; the popup prefills (or skips) its agent form from it, keeping a per-viewer localStorage override on top. Intentionally NOT in `required` — additive rollout field, same convention as `snowflakeAppName`. Emitted only when `editionCapabilities.agentPopup` is true and the value passes the server's identifier guard; omitted everywhere else (gallery/enterprise, a snowflake install whose registration soft-failed, older servers). Absent means "show the agent form", never an error.
    - `agentLastSeenAt` string, date-time, nullable: Last time a request authenticated as an agent on the caller's behalf, by EITHER credential path (DVT-1927): a dvt_live_ API key, or the MCP OAuth JWT path (ADR-0062). Both stamp one throttled per-user column, so the signal is auth-method-agnostic. Scoped to the USER, not the org — it answers "has this person ever connected an assistant", which is a per-person question; a user who connected an agent in one of their orgs reads as connected in all of them. This is a HISTORICAL last-seen, not a liveness check: the write is forward-only and is never cleared when the credential that produced it is revoked or expires (revocation on the MCP OAuth side happens at the identity provider, which this column cannot observe at all — a value that is liveness-checked for one credential path and historical for the other would be worse than one that is uniformly historical). A non-null value does NOT by itself mean a working credential exists today; consumers that need a "connected right now" signal must apply their own recency window rather than treat non-null as "connected" — but a window only answers "was there recent agent activity", not "does a working credential exist"; no dvt API lets a client that does not hold the credential check whether an MCP OAuth grant is still valid. Null means no agent has ever been observed for this user, OR the read was unavailable (a DB error) — indistinguishable on the wire, so null is NOT by itself a definitive "not connected" and clients must not render one from it alone (see DVT-2943 for the three-state rule). Lags real activity by up to ~60s (the write is throttled to once a minute).
    - `lastSeenWhatsNew` string: Id of the latest What's New announcement the caller has dismissed/finished ("" = never seen one). Clients compare it to their bundled announcement config to decide whether to show the What's New modal. Not required for rollout symmetry (same convention as onboarding/firstLoginAt).
    - `assistantSetup` object: The caller's AI-assistant chooser state (DVT-5116), written via `PATCH /v1/me/assistant-setup`. The server always emits it; defaults are `{tool: null, isSnowflakeAdmin: null, popupDismissed: false}`. Not required for rollout symmetry (same convention as onboarding/firstLoginAt).
      - `tool` string, nullable, required: The chosen assistant — one of snowflake_intelligence, cortex_code, claude_desktop, claude_code (the PATCH body's `tool` enum); null = never answered.
      - `isSnowflakeAdmin` boolean, nullable, required: The user's own admin answer; null = never answered.
      - `popupDismissed` boolean, required: True once the chooser pop-up was skipped, closed, or completed.
    - `edition` 'gallery' | 'enterprise' | 'snowflake': The deployment mode (DVT-1389), mirrored from the server's DVT_MODE config. Snowflake mode has no dvt-side memberships/invitations (access is a Snowflake grant) and no connection/credential management (the host account is the only source, ADR-0066 r3.4), so clients hide the Members, Connections, and API-keys surfaces there. Always present. Unlike `GET /auth/config`'s `headerAuth` (fetched once at `/`), this is available on every authenticated page via the already-fetched `/v1/me`.
    - `editionCapabilities` object: The edition capability matrix row (ADR-0068 D2, DVT-1568): the declarative per-subsystem behavior of this deployment's edition, derived once at boot from DVT_MODE. Clients gate per-subsystem UI on these cells (e.g. hide Members when membersCrud is false) so client gating matches the server's own edition gates, instead of re-deriving behavior from `edition`. Always present in production; additive — new subsystem cells may appear without notice. The human-readable registry is docs/editions.md.
      - `edition` 'gallery' | 'enterprise' | 'snowflake', required: The deployment mode this row was derived from (same value as `edition`).
      - `authSource` 'workos' | 'snowflake_ingress_header', required: Where request identity comes from.
      - `membersCrud` boolean, required: dvt-side org membership/invitation management exists (UI + mutating REST). False in snowflake mode — access is a Snowflake grant; the routes 403.
      - `connectionsCrud` boolean, required: User-declared warehouse connections with dvt-sealed credentials (create/update/delete/test/OAuth/CSV upload). False in snowflake mode.
      - `apiKeysCrud` boolean, required: dvt API-key minting/revocation. False in snowflake mode.
      - `spcsTokenConnections` boolean, required: The secretless spcs_token connection auth method is available. True only in snowflake mode.
      - `mediaBackend` 'r2' | 'filesystem', required: Media/render-artifact storage backend.
      - `mediaUploads` boolean, required: Element image uploads are available. False in snowflake mode.
      - `spaDelivery` 'cdn' | 'embedded', required: How the web SPA reaches the browser.
      - `telemetrySink` 'dvt' | 'none', required: Where product telemetry / dvt.dev callbacks go.
      - `logFormat` 'json' | 'spcs_event_table', required: The structured-log line shape the server emits on stdout. `spcs_event_table` (snowflake edition, DVT-1311): the SPCS event-table shape (severity_text/body/attributes) with PII scrubbed at the emit site — usernames hashed, query text never logged — so the consumer's admins can filter their own event table by severity. Nothing is shared with the provider. Operational only; clients don't gate UI on it.
      - `exportDelivery` 'object_storage' | 'unavailable' | 'render_inline_only' | 'render_app_stage', required: How export/render artifacts are delivered. `render_inline_only` (DVT-2634): a render service is configured but no artifact storage is reachable — synchronous inline renders work (agent screenshots, MCP dvt_dashboard_render_inline); async render artifacts, thumbnails, and scheduled exports stay off. `render_app_stage` (snowflake edition, DVT-1364): async renders and version thumbnails are stored on the app-owned stage `@app_spcs.renders` and served app-authenticated (no signed URL); inline renders work; scheduled exports stay off.
      - `billing` 'plans' | 'license' | 'marketplace', required: The billing / entitlement mechanism. `marketplace` (snowflake edition, ADR-0071): the Snowflake Marketplace listing bills the consumer account and Snowflake enforces entitlement platform-side — no dvt-side license gate.
      - `licenseEnforced` boolean, required: The license middleware is constructed and enforced.
      - `sharing` 'dvt_membership' | 'snowflake_grants', required: How access to dvt resources is granted.
      - `seedExampleDashboards` boolean, required: The server boot-seeds the org-visible Examples folder over the app-bundled app_data sample schema (DVT-2190). True only in snowflake mode; gallery seeds examples at sandbox/trial provision time via a different path. Informational — no client UI gates on it today.
      - `roleShare` boolean, required: The Snowflake role-based sharing + query-role pin surfaces exist (share-to-role, GET /v1/me/snowflake-roles, dashboard queryRole pins — DVT-1387/1388/1738). True only when snowflake mode AND the ingress auth opt-in (DVT_SNOWFLAKE_INGRESS_AUTH) are both on — it reflects real feature enablement, the same predicate the runtime surfaces gate on. UI-gating only: clients gate the share-dialog role sections and the query-role pin picker on this cell instead of re-deriving from `edition`.
      - `accessRoster` boolean: The snowflake-mode access roster exists (the /admin Roles tab and GET /v1/orgs/{orgId}/snowflake/app-role-grantees): which account roles hold each dvt application role, read under the app's owner's-rights identity. True only when snowflake mode AND the ingress auth opt-in (DVT_SNOWFLAKE_INGRESS_AUTH) are both on — the same predicate as roleShare, and the same predicate the route's construction gates on (off-cell the route is not registered at all and 404s). Admin-gated (audit:read + own-org) server-side; clients gate the Roles nav tab and route on this cell instead of re-deriving from `edition`. Not in `required` above (additive, pr-review round-2 fix): older servers omit this cell; web falls back to `edition === 'snowflake'` (see web's `accessRosterCapable`).
      - `mirrorDurability` boolean: The postgres->Snowflake mirror's durability component exists on the admin Health payload (`OrgAnalyticsPerformance.mirror`, DVT-3495, child of DVT-3481). True in snowflake mode only — the mirror is a native-app construct and no other edition runs one, so "off" means the field is never populated. Derived from MODE ALONE, unlike roleShare/accessRoster: this cell registers no route, and clients gate on the response FIELD's presence rather than on the cell, so there is no enablement window in which it could advertise a dead surface. A snowflake install whose service spec has no mirror container yet keeps the cell true and simply omits the field. Not in `required` above (additive): older servers omit this cell.
      - `emailReport` boolean: `POST /v1/dashboards/{id}/email` ("Email me this report now") exists (DVT-4201). Snowflake-native email via the consumer's own NOTIFICATION INTEGRATION, sent by `CALL SYSTEM$SEND_EMAIL(...)` on the CALLER's own Snowflake session — only meaningful where a caller's-rights session exists at all, so true in snowflake mode only. False in gallery/enterprise, which already have a different mechanism (Resend-based scheduled export email delivery). True here does not mean the consumer has configured an integration yet — a per-request 409 handles that; this cell is edition capability, not live readiness. Not in `required` above (additive): older servers omit this cell.
      - `emailSchedule` boolean: `/v1/dashboards/{id}/email-schedules` exists (DVT-4266): a user can store a cadence, timezone and recipient list for a dashboard page and send it on demand with "Run now". True wherever `emailReport` is true and only there — run-now delegates to that exact send handler, so the schedule surface is meaningless without it and the server builds neither outside snowflake mode. **This cell does NOT by itself mean schedules fire automatically.** No ticker runs, in any edition: a scheduled send has no live user and therefore no Snowflake caller token to send as (ADR-0069) — a CONSUMER-OWNED Snowflake task is what actually fires one, once activated. **Nor is this cell sufficient on its own to call any of those routes.** The whole surface is additionally ANDed with `unattendedSchedules` below, which DVT-4490 ships true wherever this cell is true — the normal Snowflake native-app case — so a shipped install's every verb under `/v1/dashboards/{id}/email-schedules` answers normally, not `404`, once both cells agree. It can still answer `404 feature-disabled` with this cell true: an operator's `DVT_UNATTENDED_SCHEDULES_ENABLED=false`, or a server build too old to have shipped `unattendedSchedules` at all. Read this cell as "this edition HAS email schedules", never as "this build EXPOSES them" — check `unattendedSchedules` too. Not in `required` above (additive): older servers omit this cell.
      - `unattendedSchedules` boolean: THE ENTIRE email-schedule surface is exposed: all seven `/v1/dashboards/{id}/email-schedules` verbs (create, list, get, patch, delete, run, setup) plus `.../activation`, `.../activate` and `.../deactivate` (DVT-4490), the SPA's Schedule tab, and the `dvt_email_schedule_*` MCP tools. **TRUE WHEREVER `emailSchedule` IS TRUE, AS SHIPPED SINCE DVT-4490** — the normal Snowflake native-app case. `false` on a given deployment means one of two operator-facing things: `DVT_UNATTENDED_SCHEDULES_ENABLED=false` set on BOTH dvt-api (this cell + every route above) and dvt-engine (the MCP tool listing) — an explicit opt-out, checked for agreement by `check-service-env-parity.py` — or an edition where `emailSchedule` itself is false. With it false every route in the group answers `404 feature-disabled`, the tab is not rendered, and the tools are not registered; stored rows are untouched either way. The name is narrower than the cell, for history. It first gated only the UNATTENDED half — a schedule still saved and sent on "Run now" — and that shape was withdrawn on the founder's call: a standing report that never stands is not worth shipping, whatever the copy says. The cell now gates the surface end to end; it was not renamed because a client already reading it must keep working. The machinery is a consumer-owned Snowflake task calling in through the report hop (DVT-4300/DVT-4348/DVT-4440). What used to gate this cell off by default was the way a customer had to turn it on: a wall of grant SQL and a generated `CREATE TASK` with placeholders to hand-edit. DVT-4490 is the one-click activation that replaced it (`GET/POST .../activation`, `.../activate`, `.../deactivate`) and is what ships this cell true. `POST /v1/dashboards/{id}/email` ("Email me this report now") is unaffected by this cell either way — it is gated on `emailReport` only. Gate every schedule affordance on this cell (see web's `unattendedSchedulesCapable`); a client must not read `emailSchedule` for it. Not in `required` above (additive): older servers omit this cell, and clients must treat the schedule surface as hidden in that case — no edition-string fallback.
      - `reportIssue` boolean: The end-user "Report an issue…" surface (`POST /v1/support-issues`, DVT-1104/DVT-1156) is offered on this deployment. True in gallery/enterprise, where a filed report lands in the cloud `support_issues` table dvt's support triage actually reads. FALSE in snowflake mode (POLISH-61): a report from a native-app install lands in the app's own Postgres inside the consumer's account and is mirrored to their `mirror_restricted` schema — nothing notifies dvt and there is no in-app inbox, so the user would be told their report was filed while nobody at dvt ever sees it. Both SPA entry points (the panel ⋯ menu item and the dashboard toolbar overflow item) are hidden and `POST /v1/support-issues` returns the `not-in-edition` 403 there; flip this cell when DVT-4354 routes native-app submissions back to dvt. Gates ONLY the end-user CREATE path — the admin-only triage routes (`GET`/`PATCH /v1/support-issues[/{id}]`, `support_issue:manage`) stay available in every edition. Gate the menu items on this cell (see web's `reportIssueCapable`). Not in `required` above (additive): older servers omit this cell, and clients must treat the surface as hidden in that case — no edition-string fallback.
      - `renderDelete` boolean: Stored-render deletion (DVT-4925) is available: self-delete of one's own renders, admin delete, thumbnail hide/restore, the admin metadata listing and bulk offboarding delete. True only in snowflake mode while the render app-stage is configured (`exportDelivery` is `render_app_stage`); the routes 404 otherwise. Not in `required` above (additive): older servers omit this cell, and clients must treat the surface as hidden in that case.
      - `spcsWritebackConnection` boolean: The boot-provisioned "Host Snowflake Writeback" connection (auth_method='spcs_token', kind='writeback') exists, so in-account Sheets writeback (DVT-2905, ADR-0077 r2 D4r) has a connection to auto-bind against with no customer declaration step. True only in snowflake mode. Not in `required` above (additive, review fix): older servers omit this cell entirely; clients fall back to `edition === 'snowflake'` (see web's `auth.sheetWritebackCapable`). Gates CreateSheet's writeback auto-bind and the rows-write paths' snowflake-mode-specific error copy (writeback-not-provisioned / no-warehouse / sealing-unavailable — see the Problem-type notes on `POST /v1/sheets/{id}/rows` and `POST /v1/sheets/{id}/rows/query` below).
      - `sheetLinkedCreate` boolean: Creating a kind='linked' Sheet (DVT-2932, ADR-0078 D1) is available (pr-review round-1 fix, H1; wording corrected round-2, A-HIGH-1). Gallery ✅; self-host frozen (unverified — DVT-2025); true in snowflake mode since DVT-3220 built the ADR-0078 D5 Native-app path (app-identity appends, caller's-rights base reads). There the live gate is per-org, not per-edition: linked sheets are on by default; an admin can turn them off with {"linkedSheetsEnabled":false} (PATCH /v1/orgs/{orgId}/settings), after which create returns 400 `linked-base-org-disabled`; without the Snowflake ingress caller token, 400 `linked-base-caller-token-missing`. Gate the create-modal's linked-kind option on this cell. Not in `required` above (additive, same convention as `spcsWritebackConnection`): older servers omit this cell entirely; clients fall back to `edition !== 'snowflake'`.
      - `pythonPanels` boolean: The `python` panel type (ADR-0084 D2, DVT-4258/DVT-4259) is deployment-available. **TRUE ON THE 1.0.20 SNOWFLAKE NATIVE APP as of DVT-4453** (risk accepted 2026-09-19): every edition row grants this cell, and the shipped native-app service spec renders `PYTHON_PANELS_ENABLED="true"` on dvt-api from this patch onward (ADR-0084 H5 remains a hard gate for the next cut after Monday 2026-09-22, not a closed item). Before this patch the native app shipped with the literal `"false"`, and while the cell is off a `python` panel still VALIDATES (the rows are forward-compatible and are never stripped) while the write seam refuses a new or changed one with `403 not-in-edition` and `/v1/data/query` refuses to run one with `400 python-not-available` — nothing was removed. On the native app the literal is baked into the package at build time, so a consumer install cannot flip it: rollback is a provider-side package patch from dvt, and the in-account lever is the `python:author` editor floor via the app roles (`dvt_editor` / `dvt_admin`). On Gallery and Enterprise the operator owns the env literal directly (granted and on throughout). Granted by every edition row from DVT-4259 on; the operator kill switch stays — this cell is enforced at the dashboard write seam AND at `/v1/data/query` dispatch independently of the caller's `python:author` capability, so an operator flipping it off sends an already-persisted python panel dark (query dispatch rejects it with `python-not-available`) rather than merely making it un-editable. `python:author` governs WHO may author one once the type is available; this cell governs WHETHER the type is available at all on this deployment. Not in `required` above (additive, same convention as `sheetLinkedCreate`): older servers omit this cell entirely; clients fall back to treating python panels as unavailable.
      - `certification` boolean: Dashboard certification tiers (ADR-0085) are available on this deployment: certification domains + certifier lists (`certification:manage`), certifying a dashboard (`dashboard:certify`, further gated per resource on certifier membership), and marking a certified dashboard canonical (`dashboard:canonicalize`). True in every edition (founder decision F5). This cell is edition availability only; who may act is governed by those capabilities. Not in `required` above (additive): older servers omit this cell, and clients must treat the certification surface as hidden in that case.
      - `agentChat` boolean: The in-app Cortex Agent chat transport exists (threads + run, `/v1/agent/threads*`, `/v1/agent/run` — DVT-3518, ADR-0082 W1). True in every edition, including snowflake mode with `DVT_AGENT_IDENTITY=caller` (DVT-3961, ADR-0082 Option A): which identity authenticates the engine's Cortex Agent REST client is an implementation detail this cell doesn't surface — a per-user Snowflake PAT everywhere except snowflake-mode caller-identity installs, where it is the request's own combined ingress token (`<service>.<caller>`, no stored credential). Gates POST/DELETE `/v1/agent/threads` and POST `/v1/agent/run`; GET (list) is never gated. Not in `required` above (additive): older servers omit this cell; clients fall back to treating agent chat as unavailable.
      - `agentRunResume` boolean: The run-resume transport (DVT-4436, ADR-0082 amendment DVT-4544) is armed: `POST /v1/agent/run` persists every engine frame server-side so a disconnected client can replay/live-tail via `GET /v1/agent/runs/{runId}/events`, and both routes honor a ~75s attach window (an `event: dvt.resume` frame naming a resume cursor) that makes that resume meaningful across the Snowflake SPCS ingress's ~90s wall-clock cut. **True in snowflake mode only** — that ingress cut is what this feature exists to survive, and the snowflake-mode metadata Postgres lives inside the consumer's own account, so persisting warehouse-derived frame content there (a `response.tool_result` frame can carry verbatim query rows) never leaves it. False in gallery/enterprise: neither has an SPCS cut to survive, and dvt-operated Neon is not the consumer's account, so the same persistence there would be a real data-residency exposure. With this cell false, `POST /v1/agent/run` and `GET .../events` stay MOUNTED (gated by `agentChat`, true in every edition) but persist nothing and never write `dvt.resume` — both routes simply stream/tail to completion instead, exactly their pre-DVT-4436 shape. The always-on parts of the transport — the detached engine call itself, the `dvt.run`/`id:`/`dvt.done` frames, and `POST /v1/agent/runs/{runId}/cancel` — need no persistence and stay on in every edition regardless of this cell. Not in `required` above (additive): older servers omit this cell; clients fall back to treating run-resume as unavailable (no mount-resume localStorage key, no `GET .../events` call on mount).
      - `agentCredentialsCrud` boolean: Per-user agent-PAT registration (`PUT`/`DELETE /v1/agent/credential`) is available (DVT-3518, ADR-0082 D2). A distinct cell from `agentChat`: false in snowflake mode when `DVT_AGENT_IDENTITY=caller` (DVT-3961, ADR-0082 Option A) — the ingress caller token IS the credential, so there is nothing for a user to register, and `PUT`/`DELETE /v1/agent/credential` 403 `https://docs.dvt.dev/errors/not-in-edition` there — while `agentChat` stays true. True in every other edition/configuration, including snowflake mode with the (pre-DVT-3961, still-supported) `DVT_AGENT_IDENTITY=pat` default. `GET /v1/agent/credential/status` is never gated in either mode — in caller mode it short-circuits to `{"connected": true, "identity": "caller"}` without ever touching the credential store. Not in `required` above (additive): older servers omit this cell.
      - `agentPopup` boolean: Whether the bottom-right app-chrome agent-chat launcher and its popup panel are visible at all (DVT-3562, ADR-0082 W2 Slice C). Distinct from `agentChat`: `agentChat` says the `/v1/agent/*` transport exists and gates those routes; `agentPopup` says this deployment additionally SHOWS the always-on chrome launcher that talks to that transport. It gates no server route by design — the routes the popup reaches stay independently gated by `agentChat` (true in every edition) and `agentCredentialsCrud` (true everywhere except snowflake mode under `DVT_AGENT_IDENTITY=caller`, DVT-3961). True in the snowflake edition since DVT-3602 — the SPCS service spec provisions `DVT_AGENT_ALLOWLIST` (fail-closed) to the app's own `APP_SPCS.DVT_AGENT` on every install and upgrade (the dvt-api copy was pulled for patch 6 / 1.0.18 by DVT-4153 and restored by DVT-3962). In snowflake mode this cell is measured, not a constant: the install renders `DVT_AGENT_ALLOWLIST` onto the api container only when `register_agent()` created and granted the agent (`app_state.upgrade_log` row `register_agent` = `registered`); where either registration step soft-failed (`skipped (create)` / `skipped (grant)`) the value is empty and the cell is `false`, so the launcher does not mount. `CREATE OR REPLACE AGENT` re-runs on every upgrade, so a grant failure can turn a previously-working install's cell false — that is the intended signal (DVT-3691). Installs on patches before DVT-3602 stay fail-closed until upgraded. False in gallery/enterprise, where the allowlist is never set. Not in `required` above (additive): older servers omit this cell entirely, and the client must treat the launcher as hidden in that case.
    - `entitlement` object: The account's read-only Snowflake Marketplace entitlement tri-state (DVT-1669, ADR-0071 Layer 2), cached server-side off a slow background refresh of the engine's own account-level check. Present only when this deployment's `editionCapabilities.billing` is `marketplace` (snowflake edition); omitted (absent) in gallery/enterprise, where entitlement is meaningless. THIS FIELD IS DISPLAY-ONLY: Snowflake enforces entitlement platform-side (trial expiry auto-suspends the app, listing revocation disables it) — clients MUST NOT gate any capability or authorization decision on it, only cosmetic UX (e.g. a trial/purchased banner).
      - `status` 'purchased' | 'trial' | 'unknown', required: `purchased`: the account has an active paid Marketplace purchase. `trial`: the account is in an active Marketplace trial. `unknown`: no signal — the engine's entitlement check hasn't succeeded yet (including, today, the pre-Marketplace-listing period where the underlying Snowflake functions aren't callable at all) or the cache hasn't completed its first refresh since boot. `unknown` is NOT "not entitled" — it carries no information either way.
    - `ssoGroups` string[]: The caller's WorkOS SSO/IdP group membership (DVT-1404), mirrored from the WorkOS organization-membership `custom_attributes.groups` key at login and via the WorkOS membership webhooks. Omitted when the caller carries none — either genuinely no SSO groups configured, or a non-interactive credential path (API key, MCP OAuth, render session) that never attributes a live SSO session to the caller. Read-only; used by the connection role-mapping policy authoring UI to show which `sso_group` rules (if any) apply to the caller.
  - `meta` Meta: 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

- `401`: Missing, invalid, or expired session.
- `403`: Authenticated, but the request has no usable workspace. Two Problem types. `no-workspace`: the account has no workspace it can access (the invitation gate, or a membership revoked after the session or key was issued); re-authenticating cannot change the outcome, so clients must not retry the login flow. `no-membership`: on the MCP OAuth bearer path, the token selected a workspace the account does not belong to (or selected none) while another workspace is available; reconnecting and choosing a workspace can fix it. On the cookie and API-key paths `no-membership` keeps its existing meaning (the account holds no active organization membership): do not retry the login flow.

---

[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)
