The Comments API lets you create, edit, delete, resolve, and re-anchor comment threads on document nodes within a notebook. Each comment is anchored to either the entire document, a specific block, or a text range, and tracks its resolution state for collaborative review workflows.
Returns lightweight thread anchor metadata for comment decorations. Use this endpoint to render comment decorations on the client without fetching full comment bodies.
Name In Type Required Description limitquery integer No Maximum number of anchors to return. Default: 500. offsetquery integer No Number of anchors to skip. Default: 0. cursorquery string No Pagination cursor returned by a previous call. notebookIdpath string Yes Identifier of the notebook that owns the document node. nodeIdpath string Yes Identifier of the document node whose anchors are being listed.
"threadId" : " cm_7a4f31c2 " ,
"anchorType" : " text-range " ,
"anchorBlockId" : " blk_d3a1f8c2 " ,
"startBlockId" : " blk_d3a1f8c2 " ,
"endBlockId" : " blk_d3a1f8c2 " ,
"anchorQuote" : " the new pricing model is finalized " ,
"anchorContextBefore" : " After reviewing the spec, " ,
"anchorContextAfter" : " and we should ship it next sprint. " ,
"anchorStatus" : " active " ,
"anchorUpdatedAt" : " 2025-04-12T18:33:07Z "
"anchorStatus" : " active " ,
"threadId" : " cm_b92e01d4 " ,
"anchorBlockId" : " blk_7c2aa1f0 " ,
"anchorContextBefore" : null ,
"anchorContextAfter" : null ,
"anchorStatus" : " orphaned " ,
"anchorUpdatedAt" : " 2025-04-10T09:14:22Z "
"anchorStatus" : " orphaned " ,
"resolvedAt" : " 2025-04-11T12:01:50Z " ,
"nextCursor" : " eyJ0aWQiOiJjbV9iOTJlMDFkNCJ9 " ,
"message" : " Invalid query parameter: limit must be a positive integer " ,
"code" : " INVALID_QUERY_PARAM " ,
"message" : " Expected a positive integer "
"message" : " You do not have access to this notebook " ,
"code" : " FORBIDDEN_NOTEBOOK_ACCESS " ,
"message" : " Document node not found " ,
"code" : " NODE_NOT_FOUND " ,
"message" : " Notebook is in a conflicting state " ,
"code" : " NOTEBOOK_CONFLICT " ,
const { anchors , hasMore , nextCursor } = await client . notes . comments . listAnchors (
Returns all comments for a document node, including the comment body, anchor metadata, author information, and resolution state.
Name In Type Required Description limitquery integer No Maximum number of comments to return. Default: 100. offsetquery integer No Number of comments to skip. Default: 0. cursorquery string No Pagination cursor returned by a previous call. notebookIdpath string Yes Identifier of the notebook that owns the document node. nodeIdpath string Yes Identifier of the document node whose comments are being listed.
"documentId" : " nd_42b1e7 " ,
"anchorBlockId" : " blk_d3a1f8c2 " ,
"anchorType" : " text-range " ,
"startBlockId" : " blk_d3a1f8c2 " ,
"endBlockId" : " blk_d3a1f8c2 " ,
"anchorQuote" : " the new pricing model is finalized " ,
"anchorContextBefore" : " After reviewing the spec, " ,
"anchorContextAfter" : " and we should ship it next sprint. " ,
"anchorStatus" : " active " ,
"anchorUpdatedAt" : " 2025-04-12T18:33:07Z " ,
"content" : " Should this reference the legal team before we ship? " ,
"createdAt" : " 2025-04-12T18:33:07Z " ,
"createdBy" : " u_a1b2c3d4 " ,
"createdByName" : " Avery Chen " ,
"message" : " Invalid cursor value " ,
"code" : " INVALID_CURSOR " ,
"message" : " Cursor is malformed or expired "
"message" : " You do not have access to this notebook " ,
"code" : " FORBIDDEN_NOTEBOOK_ACCESS " ,
"message" : " Document node not found " ,
"code" : " NODE_NOT_FOUND " ,
"message" : " Notebook is in a conflicting state " ,
"code" : " NOTEBOOK_CONFLICT " ,
const { comments , hasMore } = await client . notes . comments . list (
Creates a new comment on a document node. Provide an anchor to attach the comment to a specific block or text range; omit it to comment on the entire document.
Name In Type Required Description notebookIdpath string Yes Identifier of the notebook that owns the document node. nodeIdpath string Yes Identifier of the document node to comment on.
Field Type Required Description contentstring Yes Comment body. Between 1 and 10000 characters. parentIdstring No Identifier of a parent comment when creating a reply. anchorBlockIdstring No Block identifier the comment is attached to. anchorobject No Anchor descriptor (see variants below).
The anchor field is a discriminated union by type:
Type Required Fields Optional Fields documenttype— blocktype, blockId— text-rangetype, startBlockId, startOffset, endBlockId, endOffsetquote, contextBefore, contextAfter
"documentId" : " nd_42b1e7 " ,
"anchorBlockId" : " blk_d3a1f8c2 " ,
"anchorType" : " text-range " ,
"startBlockId" : " blk_d3a1f8c2 " ,
"endBlockId" : " blk_d3a1f8c2 " ,
"anchorQuote" : " the new pricing model is finalized " ,
"anchorContextBefore" : " After reviewing the spec, " ,
"anchorContextAfter" : " and we should ship it next sprint. " ,
"anchorStatus" : " active " ,
"anchorUpdatedAt" : " 2025-04-12T18:33:07Z " ,
"content" : " Should this reference the legal team before we ship? " ,
"createdAt" : " 2025-04-12T18:33:07Z " ,
"createdBy" : " u_a1b2c3d4 " ,
"createdByName" : " Avery Chen " ,
"message" : " Invalid anchor payload " ,
"code" : " INVALID_ANCHOR " ,
"path" : " anchor.startOffset " ,
"message" : " startOffset must be greater than or equal to endOffset "
"message" : " You do not have permission to comment on this document " ,
"code" : " FORBIDDEN_COMMENT_CREATE " ,
"message" : " Document node not found " ,
"code" : " NODE_NOT_FOUND " ,
"message" : " Comment thread is locked " ,
"code" : " COMMENT_THREAD_LOCKED " ,
"message" : " Failed to persist comment " ,
"code" : " COMMENT_PERSIST_FAILED " ,
const comment = await client . notes . comments . create ( " nb_8f3a1c2e " , " nd_42b1e7 " , {
content: " Should this reference the legal team before we ship? " ,
startBlockId: " blk_d3a1f8c2 " ,
endBlockId: " blk_d3a1f8c2 " ,
quote: " the new pricing model is finalized " ,
contextBefore: " After reviewing the spec, " ,
contextAfter: " and we should ship it next sprint. " ,
Edits the content of an existing comment. Only the comment body can be modified; anchor information is updated through the re-anchor endpoint.
Name In Type Required Description notebookIdpath string Yes Identifier of the notebook that owns the document node. nodeIdpath string Yes Identifier of the document node the comment belongs to. commentIdpath string Yes Identifier of the comment to edit.
Field Type Required Description contentstring Yes New comment body. Between 1 and 10000 characters. expectedVersioninteger No Version number expected on the server for optimistic concurrency control.
"documentId" : " nd_42b1e7 " ,
"anchorBlockId" : " blk_d3a1f8c2 " ,
"anchorType" : " text-range " ,
"startBlockId" : " blk_d3a1f8c2 " ,
"endBlockId" : " blk_d3a1f8c2 " ,
"anchorQuote" : " the new pricing model is finalized " ,
"anchorContextBefore" : " After reviewing the spec, " ,
"anchorContextAfter" : " and we should ship it next sprint. " ,
"anchorStatus" : " active " ,
"anchorUpdatedAt" : " 2025-04-12T18:33:07Z " ,
"content" : " Should this reference the legal team before we ship next quarter? " ,
"createdAt" : " 2025-04-12T18:33:07Z " ,
"createdBy" : " u_a1b2c3d4 " ,
"createdByName" : " Avery Chen " ,
"updatedAt" : " 2025-04-13T09:02:11Z " ,
"message" : " You do not have permission to edit this comment " ,
"code" : " FORBIDDEN_COMMENT_EDIT " ,
"message" : " Comment not found " ,
"code" : " COMMENT_NOT_FOUND " ,
"message" : " Comment version does not match expectedVersion " ,
"code" : " COMMENT_VERSION_MISMATCH " ,
const updated = await client . notes . comments . edit (
content: " Should this reference the legal team before we ship next quarter? " ,
Updates the root comment anchor for a comment thread. Use this when the original anchor becomes orphaned (for example, the referenced block was deleted) and you want to reattach the thread to a new location.
Name In Type Required Description notebookIdpath string Yes Identifier of the notebook that owns the document node. nodeIdpath string Yes Identifier of the document node the comment belongs to. commentIdpath string Yes Identifier of the comment thread to re-anchor.
Field Type Required Description anchorobject Yes New anchor descriptor (see variants below). expectedVersioninteger No Version number expected on the server for optimistic concurrency control.
The anchor field is a discriminated union by type:
Type Required Fields Optional Fields documenttype— blocktype, blockId— text-rangetype, startBlockId, startOffset, endBlockId, endOffsetquote, contextBefore, contextAfter
"documentId" : " nd_42b1e7 " ,
"anchorBlockId" : " blk_e91a8b40 " ,
"anchorContextBefore" : null ,
"anchorContextAfter" : null ,
"anchorStatus" : " active " ,
"anchorUpdatedAt" : " 2025-04-13T11:48:55Z " ,
"content" : " Should this reference the legal team before we ship next quarter? " ,
"createdAt" : " 2025-04-12T18:33:07Z " ,
"createdBy" : " u_a1b2c3d4 " ,
"createdByName" : " Avery Chen " ,
"updatedAt" : " 2025-04-13T11:48:55Z " ,
"message" : " Invalid anchor payload " ,
"code" : " INVALID_ANCHOR " ,
"path" : " anchor.blockId " ,
"message" : " blockId does not exist in this document "
"message" : " You do not have permission to re-anchor this comment " ,
"code" : " FORBIDDEN_COMMENT_REANCHOR " ,
"message" : " Comment not found " ,
"code" : " COMMENT_NOT_FOUND " ,
"message" : " Comment version does not match expectedVersion " ,
"code" : " COMMENT_VERSION_MISMATCH " ,
const reanchored = await client . notes . comments . reanchor (
anchor: { type: " block " , blockId: " blk_e91a8b40 " },
Marks a comment as resolved. The resolvedAt and resolvedBy fields are populated on the returned comment.
Name In Type Required Description notebookIdpath string Yes Identifier of the notebook that owns the document node. nodeIdpath string Yes Identifier of the document node the comment belongs to. commentIdpath string Yes Identifier of the comment to resolve.
Field Type Required Description expectedVersioninteger No Version number expected on the server for optimistic concurrency control.
"documentId" : " nd_42b1e7 " ,
"anchorBlockId" : " blk_d3a1f8c2 " ,
"anchorType" : " text-range " ,
"startBlockId" : " blk_d3a1f8c2 " ,
"endBlockId" : " blk_d3a1f8c2 " ,
"anchorQuote" : " the new pricing model is finalized " ,
"anchorContextBefore" : " After reviewing the spec, " ,
"anchorContextAfter" : " and we should ship it next sprint. " ,
"anchorStatus" : " active " ,
"anchorUpdatedAt" : " 2025-04-12T18:33:07Z " ,
"content" : " Should this reference the legal team before we ship next quarter? " ,
"createdAt" : " 2025-04-12T18:33:07Z " ,
"createdBy" : " u_a1b2c3d4 " ,
"createdByName" : " Avery Chen " ,
"updatedAt" : " 2025-04-14T08:21:44Z " ,
"resolvedAt" : " 2025-04-14T08:21:44Z " ,
"resolvedBy" : " u_f7e8d9c0 "
"message" : " You do not have permission to resolve this comment " ,
"code" : " FORBIDDEN_COMMENT_RESOLVE " ,
"message" : " Comment not found " ,
"code" : " COMMENT_NOT_FOUND " ,
"message" : " Comment version does not match expectedVersion " ,
"code" : " COMMENT_VERSION_MISMATCH " ,
const resolved = await client . notes . comments . resolve (
Deletes a comment and its replies. This operation is irreversible.
Name In Type Required Description expectedVersionquery integer No Version number expected on the server for optimistic concurrency control. notebookIdpath string Yes Identifier of the notebook that owns the document node. nodeIdpath string Yes Identifier of the document node the comment belongs to. commentIdpath string Yes Identifier of the comment to delete.
"message" : " You do not have permission to delete this comment " ,
"code" : " FORBIDDEN_COMMENT_DELETE " ,
"message" : " Comment not found " ,
"code" : " COMMENT_NOT_FOUND " ,
"message" : " Comment version does not match expectedVersion " ,
"code" : " COMMENT_VERSION_MISMATCH " ,
const result = await client . notes . comments . delete (