---
title: "Dashboards related by shared lineage tables."
method: GET
path: "/v1/dashboards/{id}/related"
tags: ["lineage"]
---

# Dashboards related by shared lineage tables.

`GET /v1/dashboards/{id}/related`

## Request

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

Returns other dashboards in the org ranked by Jaccard similarity of the warehouse
tables their lineage touches: `jaccard = |A ∩ B| / |A ∪ B|` over each dashboard's
distinct (connection, database, schema, table) tuple set. Two dashboards that share
no tables never appear. Requires dashboard read access on this dashboard; results are
further filtered to dashboards the caller may themselves read — an unreadable
neighbor is simply excluded, never surfaced as a redacted stub.

## Query parameters

- `limit` integer

## Response `200`

Related dashboards, most similar first.

- object
  - `data` RelatedDashboard[], required
    - `dashboard` LineageDashboardRef, required: A bounded dashboard reference returned by the lineage read surfaces (deliberately not the full Dashboard — no spec). Everything past `updatedAt` is OPTIONAL provenance enrichment (DVT-2317) used by the Related list's meta lines; `required` is deliberately unchanged, so a client written against the original four fields keeps working. These fields mirror `Dashboard`'s own DVT-1418 provenance block field-for-field, by NAME as well as by meaning — same `lastEditedBy` / `lastEditedByType` / `lastViewedBy` / `lastViewedByAt`, resolved by the same server helpers. In particular `lastViewedByAt` is NOT `Dashboard.lastViewedAt`: that one is DVT-1407's CALLER-SCOPED read receipt ("when did *I* last open this"), while this is org-wide ("when did *anyone* last open this"). The `ByAt` name exists on `Dashboard` precisely to keep those two apart, and this schema uses it for the same reason. Every enrichment field is OMITTED — not null, not empty — when the underlying fact does not exist: a dashboard with no audit history has no `lastEditedBy`, one nobody has opened has no `lastViewedBy`. Nothing here is nullable; absence is the only "unknown" signal, matching how the server serialises it.
      - `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.
    - `jaccard` number, double, required: |A ∩ B| / |A ∪ B| over each dashboard's distinct lineage table set. Always > 0.
    - `sharedCount` integer, required: Number of shared table tuples (the intersection size, |A ∩ B|).
    - `sharedTables` SharedTable[], required: The shared table tuples themselves, CAPPED AT 50 TUPLES PER DASHBOARD (a display sample, not a complete listing, and not a paginated one — there is no cursor). `sharedCount` is unaffected by this cap and remains the true intersection size, so `sharedCount` may exceed `sharedTables.length`; derive any "N more" affordance from `sharedCount`, never from the array length.
      - `connectionId` string, uuid, nullable
      - `database` string
      - `schema` string
      - `table` string, 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

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