---
title: "Get a Sheet by ID."
method: GET
path: "/v1/sheets/{id}"
tags: ["sheets"]
---

# Get a Sheet by ID.

`GET /v1/sheets/{id}`

## Request

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

## Response `200`

The Sheet definition.

- SheetEnvelope
  - `data` Sheet, required: A dvt Sheet definition (ADR-0031): a root-level, org-scoped, versioned warehouse- writeback object. Metadata only — the row data lives in the customer's warehouse (the dvt_writeback namespace), never in dvt, so this object has no row-data field.
    - `id` string, uuid, required
    - `folderId` string, uuid, nullable, required: The containing library folder, or null when unfoldered (DVT-1563). Set via PUT /v1/sheets/{id}/folder. Only the sheet's owner (or an org admin/owner) may move it between folders.
    - `ownerId` string, uuid, required: The user who created the sheet.
    - `name` string, required
    - `kind` 'standard' | 'linked', required: 'standard' = manual mapping table, freely editable via the row-write API. 'linked' (v2, DVT-2932, ADR-0078 D1) = a live-join sheet bound at create time to a base warehouse relation (baseConnectionId/baseRelation): row-write is restricted to the declared extensionColumns — every edit must still SEND a value for every primaryKey column (required, non-null; they identify which base row the edit applies to), but primaryKey values are not editable content, only the declared extensionColumns are (pr-review round-1 fix, L4: earlier wording said PK values come "never from the client", which described what's writable, not what's sent) — and creation requires the admin or owner role (sheet:linked:create). The legacy seed-copy shape ('linked' materialized once from seedQuery) was retired (DVT-2928/0091) and never shared this behavior — existing pre-DVT-2932 'linked' rows are unaffected.
    - `connectionId` string, uuid, nullable, required: The writeback connection (a connection id). Null until wired. DVT-904 enforces at bind time (POST/PATCH) that this must reference a connection with kind 'writeback'; a pushdown connection is rejected with 400. The append path re-asserts this as defense in depth (409) before sealing WAL entries.
    - `targetDatabase` string, required: The dvt-managed writeback namespace: the install's writeback database (DVT_WRITEBACK by default on the native app; `dvt_writeback` elsewhere). dvt never writes outside it. Any other value is rejected on create/update with writeback-database-unsupported.
    - `targetSchema` string, nullable, required: Read-only, server-managed (DVT-1895): derived from the sheet's folder path and pinned write-once at first flush. Null until the sheet has flushed. Never settable via POST/PATCH — a client-supplied value is rejected with 400.
    - `targetTable` string, nullable, required: Read-only, server-managed (DVT-1895): derived from the sheet's name (and folder subpath) and pinned write-once at first flush. Null until the sheet has flushed. Never settable via POST/PATCH — a client-supplied value is rejected with 400.
    - `columns` object[], required: Declared column definitions. Reconciled against the live catalog at write time (ADR-0031 D1a).
    - `primaryKey` string[], required: Declared primary key / composite PK (column names) for linked sheets. Empty for standard.
    - `seedQuery` string, nullable, required: RETIRED (DVT-2928): the seed SQL a legacy seed-copy 'linked' sheet was materialized from. Never executed at write time — nothing ever ran this query. A non-empty seedQuery is rejected with 400 on POST/PATCH; new sheets can never have one. Only present (non-null) on a 'linked' sheet row created before this retirement.
    - `visibility` 'private' | 'shared' | 'public', required
    - `version` integer, required: Optimistic-concurrency version. Pass this back on PATCH.
    - `schemaVersion` integer, required
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `access` object: The CALLER's access to this sheet (ADR-0091 D3.1). Present only on GET /v1/sheets/{id}; omitted on list/create/patch. UX-only: the server enforces on every request and never reads this from a client. `read` is always true on a 200 (a non-reader gets 404). `write` is true when the caller passes the same checks as a write (sheet:write capability, per- resource ACL, owner, admin bypass, Snowflake live-tier viewer cap).
      - `read` boolean, required
      - `write` boolean, required
    - `rowCount` integer, nullable: Best-effort COUNT(*) observed against the warehouse target at the sheet's most recent successful WAL flush (DVT-1598). Null until the first flush, or when the observation attempt failed — never fails the flush itself. An observation, not stored row data (ADR-0011).
    - `description` string, nullable: Freeform markdown authoring notes about this sheet (DVT-1865 Description tab) — author-written text, never customer row data (ADR-0011). Null until an editor sets one via PATCH.
    - `baseConnectionId` string, uuid, nullable, required: kind='linked' v2 only (DVT-2932, ADR-0078 D1). The pushdown-kind connection this linked sheet reads its base relation through. Null for kind='standard'. Set once at create (POST /v1/sheets) and immutable thereafter — a PATCH that includes this field is rejected with 400; changing a linked sheet's base connection is a delete-and-recreate operation, not an update.
    - `baseRelation` object, nullable: kind='linked' v2 only (DVT-2932, ADR-0078 D1/D3). The base relation's TYPED identifier parts — never a dotted FQN string. Absent for kind='standard'. Set once at create and immutable thereafter (same PATCH-rejection rule as baseConnectionId).
      - `database` string: Optional — resolves to the base connection's default database when omitted.
      - `schema` string
      - `table` string
    - `baseSchemaFingerprint` object, nullable: kind='linked' v2 only (DVT-2932). A create-time snapshot of the base relation's column shape, captured from the engine's describe result and sorted by column name — the input to the DVT-2931 reconcile-on-read drift check (not yet implemented; this slice only captures the snapshot). Absent for kind='standard'.
      - `cols` object[]
        - `name` string
        - `dataType` string: Warehouse-native type string as reported by the engine describe call, e.g. 'NUMBER(38,0)' or 'character varying'.
        - `nullable` boolean
  - `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

- `401`: Missing, invalid, or expired session.
- `403`: The caller's role does not permit this action.
- `404`: Resource does not exist.

---

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