Skip to content

The Notes Comments API lets you create, list, edit, resolve, re-anchor, and delete comment threads attached to document nodes inside a notebook. Each comment is tied to an anchor (the whole document, a specific block, or a text range within a block). The edit, resolve, re-anchor, and delete operations support an optional expectedVersion for optimistic concurrency.

Returns lightweight thread anchor metadata for comment decorations. This endpoint is intended for clients that need to render comment markers without fetching full thread bodies.

const result = await client.notes.comments.listAnchors({
notebookId: "nb_8f3a1c2e",
nodeId: "nd_42b1e7",
limit: 500,
});
NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document
nodeIdpathstringYesIdentifier of the document node
limitqueryintegerNoMaximum number of anchors to return. Default: 500
offsetqueryintegerNoNumber of anchors to skip. Default: 0
cursorquerystringNoOpaque pagination cursor returned by a previous response
{
"anchors": [
{
"threadId": "thr_91c2a4",
"anchor": {
"anchorType": "text-range",
"anchorBlockId": "blk_3f2c01",
"startBlockId": "blk_3f2c01",
"startOffset": 12,
"endBlockId": "blk_3f2c01",
"endOffset": 48,
"anchorQuote": "the implementation should be idempotent",
"anchorContextBefore": "we agreed that ",
"anchorContextAfter": " in all write paths.",
"anchorStatus": "active",
"anchorUpdatedAt": "2026-01-14T09:12:33.000Z"
},
"anchorStatus": "active",
"resolvedAt": null,
"version": 1
}
],
"nextCursor": null,
"hasMore": false
}

Returns all comments attached to a document node, paginated by cursor.

const result = await client.notes.comments.list({
notebookId: "nb_8f3a1c2e",
nodeId: "nd_42b1e7",
limit: 100,
});
NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document
nodeIdpathstringYesIdentifier of the document node
limitqueryintegerNoMaximum number of comments to return. Default: 100
offsetqueryintegerNoNumber of comments to skip. Default: 0
cursorquerystringNoOpaque pagination cursor returned by a previous response
{
"comments": [
{
"id": "cm_7a4f31c2",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f2c01",
"anchorType": "text-range",
"startBlockId": "blk_3f2c01",
"startOffset": 12,
"endBlockId": "blk_3f2c01",
"endOffset": 48,
"anchorQuote": "the implementation should be idempotent",
"anchorContextBefore": "we agreed that ",
"anchorContextAfter": " in all write paths.",
"anchorStatus": "active",
"anchorUpdatedAt": "2026-01-14T09:12:33.000Z",
"version": 3,
"content": "Should we add a note about the retry budget?",
"createdAt": "2026-01-14T09:12:33.000Z",
"createdBy": "usr_a1b2c3",
"createdByName": "Jamie Park",
"updatedAt": "2026-01-14T10:04:11.000Z",
"resolvedAt": null,
"resolvedBy": null
}
],
"nextCursor": null,
"hasMore": false
}

Creates a new comment on a document node. The anchor field describes where the comment is attached. Pass parentId to create a reply to an existing comment.

const comment = await client.notes.comments.create({
notebookId: "nb_8f3a1c2e",
nodeId: "nd_42b1e7",
data: {
content: "Should we add a note about the retry budget?",
anchor: {
type: "text-range",
startBlockId: "blk_3f2c01",
startOffset: 12,
endBlockId: "blk_3f2c01",
endOffset: 48,
quote: "the implementation should be idempotent",
contextBefore: "we agreed that ",
contextAfter: " in all write paths.",
},
},
});
NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document
nodeIdpathstringYesIdentifier of the document node
FieldTypeRequiredDescription
contentstringYesComment text. Length: 1 to 10000 characters
parentIdstringNoIdentifier of the parent comment when this is a reply
anchorBlockIdstringNoIdentifier of the block the comment is attached to. Use the structured anchor field for richer anchors
anchorobjectNoStructured anchor describing where the comment is placed. One of document, block, or text-range shapes
{
"id": "cm_7a4f31c2",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f2c01",
"anchorType": "text-range",
"startBlockId": "blk_3f2c01",
"startOffset": 12,
"endBlockId": "blk_3f2c01",
"endOffset": 48,
"anchorQuote": "the implementation should be idempotent",
"anchorContextBefore": "we agreed that ",
"anchorContextAfter": " in all write paths.",
"anchorStatus": "active",
"anchorUpdatedAt": "2026-01-14T09:12:33.000Z",
"version": 1,
"content": "Should we add a note about the retry budget?",
"createdAt": "2026-01-14T09:12:33.000Z",
"createdBy": "usr_a1b2c3",
"createdByName": "Jamie Park",
"updatedAt": null,
"resolvedAt": null,
"resolvedBy": null
}

Updates the root comment anchor for an existing thread. Use this when the original anchor target has moved or been edited and the comment needs to track a new location.

const updated = await client.notes.comments.reanchor({
notebookId: "nb_8f3a1c2e",
nodeId: "nd_42b1e7",
commentId: "cm_7a4f31c2",
data: {
anchor: {
type: "block",
blockId: "blk_3f2c01",
},
expectedVersion: 1,
},
});
NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document
nodeIdpathstringYesIdentifier of the document node
commentIdpathstringYesIdentifier of the root comment in the thread
FieldTypeRequiredDescription
anchorobjectYesNew anchor for the thread. One of document, block, or text-range shapes
expectedVersionintegerNoCurrent version of the comment. If it does not match, the request is rejected with 409
{
"id": "cm_7a4f31c2",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f2c01",
"anchorType": "block",
"startBlockId": null,
"startOffset": null,
"endBlockId": null,
"endOffset": null,
"anchorQuote": null,
"anchorContextBefore": null,
"anchorContextAfter": null,
"anchorStatus": "active",
"anchorUpdatedAt": "2026-01-14T11:02:18.000Z",
"version": 2,
"content": "Should we add a note about the retry budget?",
"createdAt": "2026-01-14T09:12:33.000Z",
"createdBy": "usr_a1b2c3",
"createdByName": "Jamie Park",
"updatedAt": "2026-01-14T11:02:18.000Z",
"resolvedAt": null,
"resolvedBy": null
}

Marks a comment as resolved and records the resolving user and timestamp.

const resolved = await client.notes.comments.resolve({
notebookId: "nb_8f3a1c2e",
nodeId: "nd_42b1e7",
commentId: "cm_7a4f31c2",
data: {
expectedVersion: 2,
},
});
NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document
nodeIdpathstringYesIdentifier of the document node
commentIdpathstringYesIdentifier of the comment to resolve
FieldTypeRequiredDescription
expectedVersionintegerNoCurrent version of the comment. If it does not match, the request is rejected with 409
{
"id": "cm_7a4f31c2",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f2c01",
"anchorType": "text-range",
"startBlockId": "blk_3f2c01",
"startOffset": 12,
"endBlockId": "blk_3f2c01",
"endOffset": 48,
"anchorQuote": "the implementation should be idempotent",
"anchorContextBefore": "we agreed that ",
"anchorContextAfter": " in all write paths.",
"anchorStatus": "active",
"anchorUpdatedAt": "2026-01-14T09:12:33.000Z",
"version": 3,
"content": "Should we add a note about the retry budget?",
"createdAt": "2026-01-14T09:12:33.000Z",
"createdBy": "usr_a1b2c3",
"createdByName": "Jamie Park",
"updatedAt": "2026-01-14T11:08:01.000Z",
"resolvedAt": "2026-01-14T11:08:01.000Z",
"resolvedBy": "usr_a1b2c3"
}

Edits the content of an existing comment. Only the author of the comment is permitted to edit it.

const edited = await client.notes.comments.edit({
notebookId: "nb_8f3a1c2e",
nodeId: "nd_42b1e7",
commentId: "cm_7a4f31c2",
data: {
content: "Should we add a note about the retry budget and the circuit breaker?",
expectedVersion: 1,
},
});
NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document
nodeIdpathstringYesIdentifier of the document node
commentIdpathstringYesIdentifier of the comment to edit
FieldTypeRequiredDescription
contentstringYesNew comment text. Length: 1 to 10000 characters
expectedVersionintegerNoCurrent version of the comment. If it does not match, the request is rejected with 409
{
"id": "cm_7a4f31c2",
"documentId": "nd_42b1e7",
"parentId": null,
"anchorBlockId": "blk_3f2c01",
"anchorType": "text-range",
"startBlockId": "blk_3f2c01",
"startOffset": 12,
"endBlockId": "blk_3f2c01",
"endOffset": 48,
"anchorQuote": "the implementation should be idempotent",
"anchorContextBefore": "we agreed that ",
"anchorContextAfter": " in all write paths.",
"anchorStatus": "active",
"anchorUpdatedAt": "2026-01-14T09:12:33.000Z",
"version": 2,
"content": "Should we add a note about the retry budget and the circuit breaker?",
"createdAt": "2026-01-14T09:12:33.000Z",
"createdBy": "usr_a1b2c3",
"createdByName": "Jamie Park",
"updatedAt": "2026-01-14T10:04:11.000Z",
"resolvedAt": null,
"resolvedBy": null
}

Deletes a comment and all of its replies. This action is irreversible.

const result = await client.notes.comments.delete({
notebookId: "nb_8f3a1c2e",
nodeId: "nd_42b1e7",
commentId: "cm_7a4f31c2",
expectedVersion: 3,
});
NameInTypeRequiredDescription
notebookIdpathstringYesIdentifier of the notebook containing the document
nodeIdpathstringYesIdentifier of the document node
commentIdpathstringYesIdentifier of the comment to delete
expectedVersionqueryintegerNoCurrent version of the comment. If it does not match, the request is rejected with 409
{
"success": true
}