---
title: "Which dashboards touch this table."
method: GET
path: "/v1/lineage/tables/dashboards"
tags: ["lineage"]
---

# Which dashboards touch this table.

`GET /v1/lineage/tables/dashboards`

## Request

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

Identifier-keyed reverse lineage lookup: EXACT-TUPLE lookup on the raw
`{connectionId, database, schema, table}` identifier tuple, returning the live
dashboards in the caller's org whose lineage references it, filtered to dashboards
the caller may read. This matches directly on the stored raw identifier columns and
never touches catalog-object resolution, so it works even for a connection that has
never opted into catalog sync (A3) and is unaffected by catalog resync churn. This is
the only lineage reverse-lookup surface: there is no catalog-object-id alias, since
`catalog_objects.id` is re-minted on every sync pass (A3) and so is never a stable
client-held handle across syncs (see `LineageEdges`' doc comment in
`server/internal/repo/lineage.go` for the full reasoning).

The supported flow is to copy the tuple straight off an edge returned by GET
/v1/dashboards/{id}/lineage (each edge already carries `connectionId`, `database`,
`schema`, and `table` in this exact shape) rather than to construct it by hand.

All four params are REQUIRED — an ABSENT param is a 400, since there is no safe
default across every one of them (an omitted `connectionId` would silently mean "the
env/demo NULL-connection source", not "any connection"). An EMPTY STRING is legal and
semantically meaningful for `database`/`schema`: it matches an edge whose raw
identifier part is itself empty (an unqualified reference at extraction time), and it
is NOT the same as omitting the param — omission is always rejected, empty string is
always accepted.

## Query parameters

- `connectionId` string, required
- `database` string, required
- `schema` string, required
- `table` string, required

## Response `200`

Dashboards whose lineage references this table.

- object
  - `data` LineageDashboardRef[], required
    - `id` string, uuid, required
    - `title` string, required
    - `visibility` 'private' | 'shared' | 'public', required
    - `updatedAt` string, date-time, required
    - `description` string: The dashboard's own description field (raw markdown, untruncated). Absent when the dashboard has no description.
    - `version` integer: The dashboard's monotonic version counter, which IS its edit count — dashboard_revisions is deliberately not consulted (it carries no org_id).
    - `ownerName` string: Display label of the dashboard's owner — display_name, else email, else "system". ALWAYS present: the server COALESCEs to "system", so this never falls back to absent the way the audit-derived fields below do.
    - `lastEditedBy` string: Display label of the most recent create/update audit actor. For an agent-attributed edit this is the API-key name / MCP client id (the DVT-1196 "via {key}" convention), so it names WHICH credential edited it; otherwise the human display_name/email/"system". Absent when the dashboard has no create/update audit history.
    - `lastEditedByType` 'user' | 'agent': The actor_type of the audit_logs row behind lastEditedBy, clamped to `user` | `agent` (audit_logs also allows `system`/`render`, folded into `user` here) — identical in name, domain and meaning to Dashboard.lastEditedByType, so a client can share one agent-badge join across both surfaces. Absent when lastEditedBy is absent.
    - `lastViewedBy` string: Display label of the most recent viewer of this dashboard, ANY actor — org-wide "who looked at this last", NOT scoped to the calling user. Absent when nobody in the org has ever viewed it.
    - `lastViewedByAt` string, date-time: Timestamp paired with lastViewedBy above. Named `ByAt`, matching Dashboard's own field, to stay clear of DVT-1407's caller-scoped `lastViewedAt`. Present exactly when lastViewedBy is.
  - `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.
- `401`: Missing, invalid, or expired session.
- `403`: The caller's role does not permit this action.

---

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