Skip to content
Hoody.com

The Notes Comments API manages threaded conversations attached to document nodes inside notebook trees. Use these endpoints to list comment decorations on a document, create a new comment with an anchor (document, block, or text range), edit an existing comment, re-anchor a thread when surrounding text changes, mark threads as resolved, or delete them entirely. List operations are paginated via limit, offset, and cursor; write operations accept an optional expectedVersion to guard against lost-update races.

All endpoints live under the notes service for your container cluster. Every URL in this page is rooted at:

https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com

Substitute {projectId} (24 hex characters), {containerId} (24 hex characters), and {server} (for example node-us) with your cluster’s values. A working concrete hostname is https://67e89abc123def456789abcd-890abcdef12345678901cdef-notes-1.node-us.containers.hoody.com.

Returns lightweight per-thread anchor metadata for the comment decorations rendered in the editor sidebar. This is the cheapest way to enumerate threads when you only need anchor locations and resolution state, not the full conversation body.

GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/comment-anchors

NameInTypeRequiredDescription
limitqueryintegerNoMaximum anchors to return. Default 500.
offsetqueryintegerNoNumber of anchors to skip before returning results. Default 0.
cursorquerystringNoOpaque pagination cursor returned by a previous call.
notebookIdpathstringYesIdentifier of the notebook containing the document node.
nodeIdpathstringYesIdentifier of the document node whose anchors are listed.
{
"anchors": [
{
"threadId": "th_8c1f7e23a0b14d6f9c2e8a4f1b3d5e72",
"anchor": {
"anchorType": "text-range",
"anchorBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"startBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"startOffset": 142,
"endBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"endOffset": 178,
"anchorQuote": "We will ship this change behind a feature flag.",
"anchorContextBefore": "After review with the platform team,",
"anchorContextAfter": "Please confirm before merging.",
"anchorStatus": "active",
"anchorUpdatedAt": "2025-03-14T11:02:48Z"
},
"anchorStatus": "active",
"resolvedAt": null,
"version": 4
}
],
"nextCursor": "eyJ0aWQiOiJ0aF84YzFmN2UyM2EwYiJ9",
"hasMore": false
}
import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notes.comments.listAnchors('nb_8f3a1c2e', 'nd_42b1e7', { limit: 200 });

Returns all comments for a document node, including reply threads. Use this when you need the full conversation body, not just the anchor metadata.

GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/comments

NameInTypeRequiredDescription
limitqueryintegerNoMaximum comments to return. Default 100.
offsetqueryintegerNoNumber of comments to skip before returning results. Default 0.
cursorquerystringNoOpaque pagination cursor returned by a previous call.
notebookIdpathstringYesIdentifier of the notebook containing the document node.
nodeIdpathstringYesIdentifier of the document node whose comments are listed.
{
"comments": [
{
"id": "cm_7a4f31c2b9e84d6f9a0c1e3b4d5f6a78",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"anchorType": "text-range",
"startBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"startOffset": 142,
"endBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"endOffset": 178,
"anchorQuote": "We will ship this change behind a feature flag.",
"anchorContextBefore": "After review with the platform team,",
"anchorContextAfter": "Please confirm before merging.",
"anchorStatus": "active",
"anchorUpdatedAt": "2025-03-14T11:02:48Z",
"version": 4,
"content": "Can we tighten this scope? \"feature flag\" is doing a lot of work here.",
"createdAt": "2025-03-14T11:02:48Z",
"createdBy": "usr_a1b2c3d4",
"createdByName": "Alex Rivera",
"updatedAt": "2025-03-14T11:08:12Z",
"resolvedAt": null,
"resolvedBy": null
}
],
"nextCursor": null,
"hasMore": false
}
import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notes.comments.list('nb_8f3a1c2e', 'nd_42b1e7', { limit: 50 });

Creates a new top-level comment or a reply (when parentId is provided) on a document node. If anchor is supplied, the comment is attached to a document, block, or text range; otherwise the comment is unanchored.

POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/comments

NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document node.
nodeIdpathstringYesIdentifier of the document node that receives the comment.
NameTypeRequiredDescription
contentstringYesComment body. 1 to 10000 characters.
parentIdstringNoIdentifier of the parent comment when creating a reply.
anchorBlockIdstringNoConvenience block id when the comment attaches to a single block.
anchorobjectNoStructured anchor. One of document, block (with blockId), or text-range (with startBlockId, startOffset, endBlockId, endOffset, and optional quote, contextBefore, contextAfter).
{
"content": "Can we tighten this scope? \"feature flag\" is doing a lot of work here.",
"anchor": {
"type": "text-range",
"startBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"startOffset": 142,
"endBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"endOffset": 178,
"quote": "We will ship this change behind a feature flag.",
"contextBefore": "After review with the platform team,",
"contextAfter": "Please confirm before merging."
}
}
{
"id": "cm_7a4f31c2b9e84d6f9a0c1e3b4d5f6a78",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"anchorType": "text-range",
"startBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"startOffset": 142,
"endBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"endOffset": 178,
"anchorQuote": "We will ship this change behind a feature flag.",
"anchorContextBefore": "After review with the platform team,",
"anchorContextAfter": "Please confirm before merging.",
"anchorStatus": "active",
"anchorUpdatedAt": "2025-03-14T11:02:48Z",
"version": 1,
"content": "Can we tighten this scope? \"feature flag\" is doing a lot of work here.",
"createdAt": "2025-03-14T11:02:48Z",
"createdBy": "usr_a1b2c3d4",
"createdByName": "Alex Rivera",
"updatedAt": null,
"resolvedAt": null,
"resolvedBy": null
}
import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notes.comments.create('nb_8f3a1c2e', 'nd_42b1e7', {
content: 'Can we tighten this scope? "feature flag" is doing a lot of work here.',
anchor: {
type: 'text-range',
startBlockId: 'blk_3f8a90b1c2d4e5f6a7b8c9d0',
startOffset: 142,
endBlockId: 'blk_3f8a90b1c2d4e5f6a7b8c9d0',
endOffset: 178,
quote: 'We will ship this change behind a feature flag.',
},
});

Updates the body of an existing comment. Pass expectedVersion to make the write conditional; the request fails with a 409 if the version on the server no longer matches.

PATCH /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/comments/{commentId}

NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the comment.
nodeIdpathstringYesIdentifier of the document node containing the comment.
commentIdpathstringYesIdentifier of the comment to edit.
NameTypeRequiredDescription
contentstringYesReplacement comment body. 1 to 10000 characters.
expectedVersionintegerNoVersion the client last observed; minimum 1. The write fails when the server’s current version differs.
{
"content": "Can we tighten this scope and link to the rollout doc?",
"expectedVersion": 4
}
{
"id": "cm_7a4f31c2b9e84d6f9a0c1e3b4d5f6a78",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"anchorType": "text-range",
"startBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"startOffset": 142,
"endBlockId": "blk_3f8a90b1c2d4e5f6a7b8c9d0",
"endOffset": 178,
"anchorQuote": "We will ship this change behind a feature flag.",
"anchorContextBefore": "After review with the platform team,",
"anchorContextAfter": "Please confirm before merging.",
"anchorStatus": "active",
"anchorUpdatedAt": "2025-03-14T11:02:48Z",
"version": 5,
"content": "Can we tighten this scope and link to the rollout doc?",
"createdAt": "2025-03-14T11:02:48Z",
"createdBy": "usr_a1b2c3d4",
"createdByName": "Alex Rivera",
"updatedAt": "2025-03-14T11:21:03Z",
"resolvedAt": null,
"resolvedBy": null
}
import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notes.comments.edit('nb_8f3a1c2e', 'nd_42b1e7', 'cm_7a4f31c2', {
content: 'Can we tighten this scope and link to the rollout doc?',
expectedVersion: 4,
});

Updates the anchor of a comment thread after surrounding text has moved or changed. Use this when an anchor becomes orphaned and the new location is known.

POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/comments/{commentId}/reanchor

NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the thread.
nodeIdpathstringYesIdentifier of the document node containing the thread.
commentIdpathstringYesIdentifier of the root comment of the thread.
NameTypeRequiredDescription
anchorobjectYesReplacement anchor. One of document, block (with blockId), or text-range (with startBlockId, startOffset, endBlockId, endOffset, and optional quote, contextBefore, contextAfter).
expectedVersionintegerNoVersion the client last observed; minimum 1. The write fails when the server’s current version differs.
{
"anchor": {
"type": "block",
"blockId": "blk_a09f81e2c3d4b5a69788f9e0"
},
"expectedVersion": 5
}
{
"id": "cm_7a4f31c2b9e84d6f9a0c1e3b4d5f6a78",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_a09f81e2c3d4b5a69788f9e0",
"anchorType": "block",
"startBlockId": null,
"startOffset": null,
"endBlockId": null,
"endOffset": null,
"anchorQuote": null,
"anchorContextBefore": null,
"anchorContextAfter": null,
"anchorStatus": "active",
"anchorUpdatedAt": "2025-03-14T12:04:55Z",
"version": 6,
"content": "Can we tighten this scope and link to the rollout doc?",
"createdAt": "2025-03-14T11:02:48Z",
"createdBy": "usr_a1b2c3d4",
"createdByName": "Alex Rivera",
"updatedAt": "2025-03-14T12:04:55Z",
"resolvedAt": null,
"resolvedBy": null
}
import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notes.comments.reanchor('nb_8f3a1c2e', 'nd_42b1e7', 'cm_7a4f31c2', {
anchor: { type: 'block', blockId: 'blk_a09f81e2c3d4b5a69788f9e0' },
expectedVersion: 5,
});

Marks a comment as resolved. Once resolved, the thread remains visible in the document but is filtered out of the default unresolved view.

POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/comments/{commentId}/resolve

NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the comment.
nodeIdpathstringYesIdentifier of the document node containing the comment.
commentIdpathstringYesIdentifier of the comment to resolve.
NameTypeRequiredDescription
expectedVersionintegerNoVersion the client last observed; minimum 1. The write fails when the server’s current version differs.
{
"expectedVersion": 5
}
{
"id": "cm_7a4f31c2b9e84d6f9a0c1e3b4d5f6a78",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_a09f81e2c3d4b5a69788f9e0",
"anchorType": "block",
"startBlockId": null,
"startOffset": null,
"endBlockId": null,
"endOffset": null,
"anchorQuote": null,
"anchorContextBefore": null,
"anchorContextAfter": null,
"anchorStatus": "active",
"anchorUpdatedAt": "2025-03-14T12:04:55Z",
"version": 6,
"content": "Can we tighten this scope and link to the rollout doc?",
"createdAt": "2025-03-14T11:02:48Z",
"createdBy": "usr_a1b2c3d4",
"createdByName": "Alex Rivera",
"updatedAt": "2025-03-14T12:18:02Z",
"resolvedAt": "2025-03-14T12:18:02Z",
"resolvedBy": "usr_f0e1d2c3"
}
import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notes.comments.resolve('nb_8f3a1c2e', 'nd_42b1e7', 'cm_7a4f31c2', {
expectedVersion: 5,
});

Deletes a comment and any replies under it. The thread’s anchor is removed from the document and its identifier is released.

DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/comments/{commentId}

NameInTypeRequiredDescription
expectedVersionqueryintegerNoVersion the client last observed. The delete fails with a 409 if the server’s current version differs.
notebookIdpathstringYesIdentifier of the notebook containing the comment.
nodeIdpathstringYesIdentifier of the document node containing the comment.
commentIdpathstringYesIdentifier of the comment to delete.
{
"success": true
}
import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notes.comments.delete('nb_8f3a1c2e', 'nd_42b1e7', 'cm_7a4f31c2', { expectedVersion: 5 });