Document Versions
Section titled “Document Versions”The Notes document version API provides immutable snapshots of a page’s block content. Use these endpoints to capture, list, restore, and delete historical versions of a document, which is useful for audit trails, content recovery, and collaborative editing history.
A version’s content field uses the same block map shape as the live page document: {"type":"rich_text","blocks":{"<blockId>":{...}}}. It is not a ProseMirror document and does not carry a top-level content array.
The base URL for every endpoint on this page follows the pattern https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com. Replace {projectId} and {containerId} with your 24-character hexadecimal identifiers and {server} with your container’s server name.
List document versions
Section titled “List document versions”GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions
Section titled “GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions”Lists all versions for a document, ordered by revision descending.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | The ID of the notebook that owns the document. |
nodeId | path | string | Yes | The ID of the document node. |
limit | query | integer | No | Maximum number of versions to return. Defaults to 20. |
offset | query | integer | No | Number of versions to skip before returning results. Defaults to 0. |
curl -X GET "https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/67e89abc123def456789abcd/nodes/890abcdef12345678901cdef/versions?limit=20&offset=0" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
for await (const item of client.notes.versions.listIterator('67e89abc123def456789abcd', '890abcdef12345678901cdef', { limit: 20, offset: 0 })) { console.log(item);}{ "versions": [ { "id": "67e89abc123def456789abcd", "documentId": "890abcdef12345678901cdef", "revision": 7, "createdAt": "2026-01-15T10:30:00.000Z", "createdBy": "user_abc123" }, { "id": "67e89abc123def456789abce", "documentId": "890abcdef12345678901cdef", "revision": 6, "createdAt": "2026-01-14T16:22:11.000Z", "createdBy": "user_def456" } ], "total": 2}Response statuses
Section titled “Response statuses”{ "versions": [ { "id": "67e89abc123def456789abcd", "documentId": "890abcdef12345678901cdef", "revision": 7, "createdAt": "2026-01-15T10:30:00.000Z", "createdBy": "user_abc123" } ], "total": 1}{ "code": "notebook_no_access", "message": "You do not have access to this notebook."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
notebook_no_access | No access to notebook | The notebook exists but the caller is not a member, or it is not open | Verify user identity or request access from the owner |
{ "code": "not_found", "message": "Node not found."}{ "code": "notebook_not_found", "message": "Notebook not found."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | No node with this ID exists in the notebook | Verify the node ID in the URL |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
Get a document version
Section titled “Get a document version”GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions/{versionId}
Section titled “GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions/{versionId}”Retrieves a specific document version by ID, including its full block content.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | The ID of the notebook that owns the document. |
nodeId | path | string | Yes | The ID of the document node. |
versionId | path | string | Yes | The ID of the version to retrieve. |
curl -X GET "https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/67e89abc123def456789abcd/nodes/890abcdef12345678901cdef/versions/67e89abc123def456789abcd" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const version = await client.notes.versions.get('67e89abc123def456789abcd', '890abcdef12345678901cdef', '67e89abc123def456789abcd');console.log(version);{ "id": "67e89abc123def456789abcd", "documentId": "890abcdef12345678901cdef", "revision": 7, "content": { "type": "rich_text", "blocks": { "b_kickoff": { "id": "b_kickoff", "type": "paragraph", "parentId": "890abcdef12345678901cdef", "index": "a0", "content": [ { "type": "text", "text": "Project kickoff notes" } ] } } }, "createdAt": "2026-01-15T10:30:00.000Z", "createdBy": "user_abc123"}Response statuses
Section titled “Response statuses”{ "id": "67e89abc123def456789abcd", "documentId": "890abcdef12345678901cdef", "revision": 7, "content": { "type": "rich_text", "blocks": { "b_kickoff": { "id": "b_kickoff", "type": "paragraph", "parentId": "890abcdef12345678901cdef", "index": "a0", "content": [ { "type": "text", "text": "Project kickoff notes" } ] } } }, "createdAt": "2026-01-15T10:30:00.000Z", "createdBy": "user_abc123"}{ "code": "notebook_no_access", "message": "You do not have access to this notebook."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
notebook_no_access | No access to notebook | The notebook exists but the caller is not a member, or it is not open | Verify user identity or request access from the owner |
{ "code": "not_found", "message": "Node not found."}{ "code": "not_found", "message": "Version not found."}{ "code": "notebook_not_found", "message": "Notebook not found."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | No node with this ID exists in the notebook, or the node has no version with this ID | Verify the node ID and the version ID in the URL |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
Create a document version
Section titled “Create a document version”POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions
Section titled “POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions”Captures the current document content as a new version snapshot. The new version’s revision is one greater than the previous maximum.
This endpoint takes no request body.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | The ID of the notebook that owns the document. |
nodeId | path | string | Yes | The ID of the document node. |
curl -X POST "https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/67e89abc123def456789abcd/nodes/890abcdef12345678901cdef/versions" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const version = await client.notes.versions.create('67e89abc123def456789abcd', '890abcdef12345678901cdef');console.log(version);{ "id": "67e89abc123def456789abcf", "documentId": "890abcdef12345678901cdef", "revision": 8, "createdAt": "2026-01-15T11:00:00.000Z", "createdBy": "user_abc123"}Response statuses
Section titled “Response statuses”{ "id": "67e89abc123def456789abcf", "documentId": "890abcdef12345678901cdef", "revision": 8, "createdAt": "2026-01-15T11:00:00.000Z", "createdBy": "user_abc123"}{ "code": "forbidden", "message": "You do not have permission to perform this action."}{ "code": "notebook_no_access", "message": "You do not have access to this notebook."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden | The caller can reach the node but does not have the editor role on it | Use an account with the editor role on the node |
notebook_no_access | No access to notebook | The notebook exists but the caller is not a member, or it is not open | Verify user identity or request access from the owner |
{ "code": "not_found", "message": "Node not found."}{ "code": "not_found", "message": "Document not found."}{ "code": "notebook_not_found", "message": "Notebook not found."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | No node with this ID exists in the notebook, or the node has no document to snapshot | Verify the node ID in the URL |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
Restore a document version
Section titled “Restore a document version”POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions/{versionId}/restore
Section titled “POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions/{versionId}/restore”Restores a document to the content of a previous version. The restore creates a new revision on the live document, and the source version is preserved.
This endpoint takes no request body.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | The ID of the notebook that owns the document. |
nodeId | path | string | Yes | The ID of the document node. |
versionId | path | string | Yes | The ID of the version whose content to restore. |
curl -X POST "https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/67e89abc123def456789abcd/nodes/890abcdef12345678901cdef/versions/67e89abc123def456789abcd/restore" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.notes.versions.restore('67e89abc123def456789abcd', '890abcdef12345678901cdef', '67e89abc123def456789abcd');console.log(result);{ "success": true}Response statuses
Section titled “Response statuses”{ "success": true}{ "code": "forbidden", "message": "You do not have permission to perform this action."}{ "code": "notebook_no_access", "message": "You do not have access to this notebook."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden | The caller can reach the node but does not have the editor role on it | Use an account with the editor role on the node |
notebook_no_access | No access to notebook | The notebook exists but the caller is not a member, or it is not open | Verify user identity or request access from the owner |
{ "code": "not_found", "message": "Node not found."}{ "code": "not_found", "message": "Version not found."}{ "code": "notebook_not_found", "message": "Notebook not found."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | No node with this ID exists in the notebook, or the node has no version with this ID | Verify the node ID and the version ID in the URL |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
{ "code": "unknown", "message": "Version state is corrupted."}Delete a document version
Section titled “Delete a document version”DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions/{versionId}
Section titled “DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/versions/{versionId}”Deletes a specific document version. Only the targeted version is removed. Other versions of the document, and the live document content, are not affected.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | The ID of the notebook that owns the document. |
nodeId | path | string | Yes | The ID of the document node. |
versionId | path | string | Yes | The ID of the version to delete. |
curl -X DELETE "https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/67e89abc123def456789abcd/nodes/890abcdef12345678901cdef/versions/67e89abc123def456789abce" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
const result = await client.notes.versions.delete('67e89abc123def456789abcd', '890abcdef12345678901cdef', '67e89abc123def456789abce');console.log(result);{ "success": true}Response statuses
Section titled “Response statuses”{ "success": true}{ "code": "forbidden", "message": "You do not have permission to perform this action."}{ "code": "notebook_no_access", "message": "You do not have access to this notebook."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Forbidden | The caller can reach the node but does not have the editor role on it | Use an account with the editor role on the node |
notebook_no_access | No access to notebook | The notebook exists but the caller is not a member, or it is not open | Verify user identity or request access from the owner |
{ "code": "not_found", "message": "Node not found."}{ "code": "not_found", "message": "Version not found."}{ "code": "notebook_not_found", "message": "Notebook not found."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Not found | No node with this ID exists in the notebook, or the node has no version with this ID | Verify the node ID and the version ID in the URL |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |