---
title: "Get a dashboard"
method: GET
path: "/api/v1/ackdb/observe/dashboards/{id}"
tags: ["ackDB"]
---

# Get a dashboard

`GET /api/v1/ackdb/observe/dashboards/{id}`

## Request

- Base URL: `http://localhost:3009`
- URL: `http://localhost:3009/api/v1/ackdb/observe/dashboards/{id}`
- Auth: HTTP bearer

The full record plus the caller's effective `access`.

## Path parameters

- `id` string, required

## Response `200`

The dashboard.

- object
  - `data` AckdbDashboard, required
    - `id` string, required
    - `name` string, required
    - `description` string, nullable
    - `ownerEmail` string, nullable: null = service-created = org-visible.
    - `access` 'owner' | 'edit' | 'view': The caller's effective role.
    - `panels` AckdbDashboardPanel[], required
      - `key` string, required: Unique within the dashboard.
      - `title` string, required
      - `type` 'kpi' | 'breakdown' | 'timeseries' | 'table' | 'feed' | 'sql', required
      - `segmentId` string
      - `spec` union, required: Per type.
        - AckdbDashboardKpiSpec: One number. `count` is the segment's row count and takes NO field; every other agg requires a numeric catalog FIELD KEY (numeric traits/attributes, `sc__` score columns, `evc__` per-event-type counts, `emf__` promoted event fields). Contact-aggregate (#214) and event-aggregate (#413) columns are inline column specs, not field keys, so they cannot be named here.
          - `agg` 'count' | 'sum' | 'avg' | 'min' | 'max', required
          - `field` string: Required unless agg is `count`, forbidden when it is.
        - AckdbDashboardBreakdownSpec: Group the segment's rows by one field and reduce each group to a number. A `date` groupBy is bucketed to the day; a NULL label is a real group ("unset"), never dropped.
          - `groupBy` string, required: A groupable catalog field: string, enum, boolean, date, score label, owner, identity-link column. Numeric fields are refused.
          - `agg` 'count' | 'sum' | 'avg' | 'min' | 'max', required
          - `field` string: Required unless agg is `count`.
          - `topN` integer: Default 10.
          - `sort` 'value_desc' | 'value_asc' | 'label_asc': Default value_desc.
          - `othersBucket` boolean: Fold the remainder into one exact `others` entry. Default false.
        - AckdbDashboardTimeseriesSpec: One dense point per bucket. `bucket` x `windowDays` must yield at most 366 points (so a `day` bucket caps at 366 days), rejected at save/preview otherwise.
          - `metric` union, required: Duck-typed union: an EVENT metric, a SCORE metric, or the MEMBERSHIP metric.
            - object: The segment members' own entity_events. `eventType` is the BARE name (resolved to the stored source-prefixed form, #355). `sum` needs a promoted numeric metadata `field`; `sum`/`distinct_contacts` need an aggregatable source on the grain (company today, #413). Zero-filled server-side.
              - …
            - object: The AVG as-of score of segment members per month, read from the #411 `score.changed` stream. Month bucket only, at most 12 months, company or person grain, and the definition must exist and be ENABLED on that grain (else SCORE_NOT_FOUND). A month with no scored member is a null gap, never a fabricated 0.
              - …
            - object: Segment size over time: anchored at the exact live count and walked BACKWARDS through the S1 enter/exit log. Honest approximation - history starts at the segment's sync bootstrap and an enter+exit inside one diff interval cancels out. SYNC_UNAVAILABLE without the sync tables.
              - …
          - `bucket` 'day' | 'week' | 'month', required
          - `windowDays` integer, required
        - AckdbDashboardTableSpec: The segment results rails with a columns/sort override (the pivot override contract). Omitted columns/sort inherit the segment's own; rows come back identical to GET /observe/segments/{id}/results.
          - `columns` object[]: SegmentColumn[].
          - `sort` object[]: SegmentSort[] ({ field, dir }).
          - `limit` integer: Default 10.
        - AckdbDashboardFeedSpec: Recent membership changes for the pinned segment, from the S1 change log. `reenter` is reported (and filtered) as `enter`.
          - `kinds` string[]: Default both.
          - `limit` integer: Default 20.
          - `windowDays` integer: Optional recency cut.
        - AckdbDashboardSqlSpec: Escape hatch. A single read-only SELECT on the `ackdb_readonly` role (BEGIN READ ONLY + statement timeout + row/byte caps + extended wire protocol). Segment-less by design; never cached. No bind params in this build.
          - `sql` string, required
          - `columns` object[], required: Declared by the author so the console renders without sniffing.
            - `key` string, required
            - `label` string, required
            - `shape` 'string' | 'number' | 'currency' | 'date' | 'boolean', required
          - `maxRows` integer: Default 1000.
      - `viz` union: A validated visualization mapping for a SQL panel. Omit `viz` to retain the declared-columns table.
        - AckdbDashboardSqlLineViz: Render ordered SQL rows as a line chart. `xKey` names a declared date/string/number column; `yKey` names a declared number/currency column. Row order is the query order.
          - `type` 'line', required
          - `xKey` string, required
          - `yKey` string, required
          - `valueLabel` string: Optional tooltip noun; defaults to the y column label.
        - AckdbDashboardSqlCategoryViz: Render SQL rows as horizontal bars or a pie. `labelKey` names any declared column; `valueKey` must name a number/currency column. topN defaults to all returned rows; `othersBucket` combines the remainder.
          - `type` 'bar' | 'pie', required
          - `labelKey` string, required
          - `valueKey` string, required
          - `topN` integer
          - `othersBucket` boolean
      - `degraded` boolean: SERVER-OWNED, read-only. Set by the scrub paths (segment/source/score deletion); a degraded panel returns its degraded envelope and never runs. A request that CARRIES this field (or `degradedReason`) is rejected per panel: it would otherwise let a caller store a panel that skipped the segment-access gate, or un-disarm a panel a scrub disabled. Re-point a degraded panel at a live, accessible segment to revive it; that edit re-runs the full gate and clears the flag.
      - `degradedReason` string
    - `artifact` AckdbDashboardArtifact: Escape-hatch HTML page plus the queries that feed it. Informational: it never defines what a panel means. HTML is capped at 5MB and scanned for credentials at save.
      - `html` string, required
      - `queries` object[], required
        - `key` string, required
        - `sql` string, required
    - `layout` unknown
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required

## Other responses

- `403`: The caller cannot see this dashboard.
- `404`: DASHBOARD_NOT_FOUND - no such dashboard, or it is soft-deleted.

---

[API](https://skmtc.dev/floqer/apis/floqer-public-api.md) - [All operations](https://skmtc.dev/floqer/apis/floqer-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/floqer/apis/floqer-public-api/revisions/fce50dc07b20?raw)
