---
title: "Resolve or reopen a comment thread."
method: POST
path: "/v1/dashboards/{id}/comments/{commentId}/resolve"
tags: ["comments"]
---

# Resolve or reopen a comment thread.

`POST /v1/dashboards/{id}/comments/{commentId}/resolve`

## Request

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

Sets or clears the top-level thread's resolved state (`resolvedAt`/`resolvedBy`).
Idempotent — calling with the state the thread is already in succeeds without
churning `resolvedAt`. Available to anyone with comment access on this dashboard
(not author-only — resolution is a collaborative triage action). 400 if the target
comment is a reply; resolution applies to the top-level thread only.

## Request body

- ResolveCommentRequest
  - `resolved` boolean, required: true to resolve the thread, false to reopen it. Required (no default). Idempotent. 400 if the target comment is a reply — resolution applies to the top-level thread only.

## Response `200`

Thread resolved or reopened.

- CommentEnvelope
  - `data` Comment, required: A dashboard comment (DVT-1179): a top-level, optionally page/element-anchored, resolvable thread starter, or a reply that inherits its parent thread's anchor and resolved state rather than carrying its own. Threading is single-level — a reply may not itself be replied to.
    - `id` string, uuid, required
    - `dashboardId` string, uuid, required
    - `pageId` string, uuid, nullable: The page this top-level thread is anchored to, if any (always the page's canonical UUID, regardless of whether it was created by UUID or slug). Null for an unanchored thread or for a reply — see parentId.
    - `elementId` string, uuid, nullable: The element (panel) this top-level thread is anchored to, if any (always the element's canonical UUID). Only set together with pageId. Null for a reply.
    - `pageName` string, nullable: The anchored page's current title, resolved from the dashboard's live state at read time (DVT-1188) — never stored, so it always reflects the page's latest title rather than whatever it was when the comment was created. Omitted when pageId is null (unanchored), or when pageId no longer resolves to a live page (e.g. the page was since deleted).
    - `elementName` string, nullable: The anchored element's current title, resolved from the dashboard's live state at read time (DVT-1188) — never stored, so it always reflects the element's latest title rather than whatever it was when the comment was created. Omitted when elementId is null, or when elementId no longer resolves to a live element on that page (e.g. the panel was since deleted). A reply inherits its parent's elementName exactly as it inherits elementId (see replies below).
    - `parentId` string, uuid, nullable: Set only on a reply — the id of the top-level thread it belongs to.
    - `authorId` string, uuid, required
    - `actorType` 'user' | 'agent' | 'system', required: Distinguishes humans from agents, matching the audit log convention.
    - `body` string, required
    - `editedAt` string, date-time, nullable: Set when the author has edited body since creation.
    - `resolvedAt` string, date-time, nullable: Top-level threads only; always null on a reply.
    - `resolvedBy` string, uuid, nullable
    - `resolved` boolean, required: Convenience derived field — true iff resolvedAt is set.
    - `replyCount` integer, required: Number of live replies under this thread. Populated by GET (list); 0 on a create/update/resolve response (those never batch-load replies).
    - `replies` Comment[]: Live replies, oldest-first. Populated by GET (list) only; omitted elsewhere. A reply's own replies/replyCount are always empty/0 (single-level threading).
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, 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

- `400`: Malformed request.
- `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)
