Comments
Manage comments on docs and insights.
Comments let you add threaded conversations to docs. Page-level comments discuss the whole doc, while inline comments attach to a text selection. Comments are available under /docs/:doc_id/comments.
The same endpoints exist under
/insights/:insight_id/comments, but the/insightspaths are deprecated. Use/docsfor all new integrations.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /docs/:doc_id/comments | List all comments on a doc |
GET | /docs/:doc_id/comments/:comment_id | Get a single comment |
POST | /docs/:doc_id/comments | Create a comment |
PATCH | /docs/:doc_id/comments/:comment_id | Update a comment |
DELETE | /docs/:doc_id/comments/:comment_id | Delete a comment |
POST | /docs/:doc_id/comments/resolve | Resolve the comment thread |
POST | /docs/:doc_id/comments/unresolve | Unresolve the comment thread |
Listing comments
Retrieve all comments on a doc, including inline comments. Comments are returned in chronological order by default. Pass ?include_text_range=true to include selected text for inline comments.
GET https://dovetail.com/api/v1/docs/<DOC_ID>/comments
Authorization: Bearer <DOVETAIL_API_TOKEN>{
"data": [
{
"id": "<COMMENT_ID>",
"body": "Great insight! We should follow up on this.",
"author": {
"id": "<USER_ID>",
"name": "Jane Smith"
},
"created_at": "2026-01-15T10:30:00.000Z",
"updated_at": "2026-01-15T10:30:00.000Z",
"comment_type": "inline",
"thread_id": "<THREAD_ID>"
}
],
"page": {
"total_count": 1,
"has_more": false,
"next_cursor": null
},
"thread": {
"resolved": false,
"resolved_at": null,
"resolved_by": null
}
}The thread field is null if no page-level comments have been posted. thread_id on each comment groups replies. On list, text_range is omitted unless include_text_range=true. Single-comment GET, PATCH, and DELETE always include text_range (null for page-level comments).
You can control sort order with the sort query parameter: created_at:asc (default) or created_at:desc. See Pagination for paging through results.
Getting a single comment
GET https://dovetail.com/api/v1/docs/<DOC_ID>/comments/<COMMENT_ID>
Authorization: Bearer <DOVETAIL_API_TOKEN>{
"data": {
"id": "<COMMENT_ID>",
"body": "Great insight! We should follow up on this.",
"author": {
"id": "<USER_ID>",
"name": "Jane Smith"
},
"created_at": "2026-01-15T10:30:00.000Z",
"updated_at": "2026-01-15T10:30:00.000Z",
"comment_type": "page",
"thread_id": "<THREAD_ID>",
"text_range": null
}
}Creating a comment
POST https://dovetail.com/api/v1/docs/<DOC_ID>/comments
Authorization: Bearer <DOVETAIL_API_TOKEN>
Content-Type: application/json
{
"body": "Great insight! We should follow up on this.",
"body_type": "text"
}If no page-level comment thread exists on the doc, one is created automatically. By default the comment is attributed to the authenticated user — i.e. the user that owns the API token. Pass optional thread_id from list or get comments to reply on that page-level or inline thread (404 if the thread is missing or not on this doc).
Content format
The body_type field controls how the body input is interpreted:
| Value | Description |
|---|---|
text | Plain text (default). Line breaks are preserved. |
html | HTML content. Tags like <strong>, <em>, <a>, etc. are supported. |
Regardless of the input format, the body field in responses is always returned as plain text.
The maximum comment length is 10,000 characters.
Attributing a comment to another user (admin)
Workspace admins can pass an optional author_id when creating a comment to attribute it to a different workspace user. This is useful when importing existing comments from another tool — without it, every imported comment would appear to be authored by the API token's owner.
POST https://dovetail.com/api/v1/docs/<DOC_ID>/comments
Authorization: Bearer <DOVETAIL_API_TOKEN>
Content-Type: application/json
{
"body": "Comment imported from Linear",
"author_id": "<USER_ID>"
}{
"data": {
"id": "<COMMENT_ID>",
"body": "Comment imported from Linear",
"author": {
"id": "<USER_ID>",
"name": "Jane Smith"
},
"created_at": "2026-01-15T10:30:00.000Z",
"updated_at": "2026-01-15T10:30:00.000Z",
"comment_type": "page",
"thread_id": "<THREAD_ID>",
"text_range": null
}
}Rules:
- The API token's owner must be a workspace admin. Non-admin tokens that include
author_idget403 Forbidden. Tokens withoutauthor_idcontinue to work as before. - The target user (
author_id) must be an active member of the same workspace. Missing, deleted, or out-of-workspace users get400 Bad Request. - Once set, the comment is owned by
author_idfor permission purposes — only that user (not the original API caller) can edit or delete it via the API. The override is recorded in the workspace audit log ascomment.author_id.updated. author_idis only honoured at creation time. ThePATCHendpoint cannot change a comment's author.
Updating a comment
PATCH https://dovetail.com/api/v1/docs/<DOC_ID>/comments/<COMMENT_ID>
Authorization: Bearer <DOVETAIL_API_TOKEN>
Content-Type: application/json
{
"body": "Updated comment text.",
"body_type": "text"
}Only the original author of a comment can update it. Attempting to update another user's comment will return a 403 Forbidden error.
Deleting a comment
DELETE https://dovetail.com/api/v1/docs/<DOC_ID>/comments/<COMMENT_ID>
Authorization: Bearer <DOVETAIL_API_TOKEN>Only the original author of a comment can delete it. The deleted comment is returned in the response. Deleted comments can be restored for up to 30 days.
Resolving and unresolving threads
Each doc has one page-level comment thread and may have multiple inline threads. These endpoints resolve or unresolve the page-level thread only; inline thread resolution is not exposed by the public API.
Resolve
POST https://dovetail.com/api/v1/docs/<DOC_ID>/comments/resolve
Authorization: Bearer <DOVETAIL_API_TOKEN>{
"data": {
"resolved": true,
"resolved_at": "2026-01-15T12:00:00.000Z",
"resolved_by": {
"id": "<USER_ID>",
"name": "Jane Smith"
}
}
}Unresolve
POST https://dovetail.com/api/v1/docs/<DOC_ID>/comments/unresolve
Authorization: Bearer <DOVETAIL_API_TOKEN>{
"data": {
"resolved": false,
"resolved_at": null,
"resolved_by": null
}
}Updated 9 days ago