Notes: Collaboration
Section titled “Notes: Collaboration”Manage collaborators, emoji reactions, and notebook-wide user roles. The service exposes three resource groups: node-scoped collaborators (sections, pages, databases) with roles admin, editor, collaborator, or viewer; node-scoped reactions; and notebook-wide users with roles owner, admin, collaborator, guest, or none. The string editor is valid only on node-scoped collaborator endpoints and is not a valid notebook-wide user role.
Node collaborators
Section titled “Node collaborators”GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators
Section titled “GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators”Returns all collaborators on a node with their roles and user info.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
nodeId | path | string | Yes | Node identifier |
Response
Section titled “Response”{ "collaborators": [ { "userId": "u_8d3f1a7c9b2e4f5a", "role": "admin", "name": "Ada Lovelace", "username": "ada", "avatar": "https://cdn.hoody.com/avatars/ada.png", "createdAt": "2025-01-15T09:12:44.000Z", "updatedAt": "2025-02-04T17:30:02.000Z" }, { "userId": "u_2c4b9e1a8d3f7b0c", "role": "editor", "name": "Grace Hopper", "username": "grace", "avatar": null, "createdAt": "2025-01-18T14:05:11.000Z", "updatedAt": null } ]}{ "message": "You do not have access to this node.", "code": "forbidden", "details": [ { "path": "nodeId", "message": "No collaborator role on the requested node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Access denied | User does not have permission to access this node | Check collaborator list or request access from the node admin |
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 |
{ "message": "Node not found.", "code": "not_found", "details": [ { "path": "nodeId", "message": "No node with this ID in the notebook" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Node not found | No node exists with the provided ID in this notebook | Verify node ID using client.notes.nodes.list() or client.notes.nodes.listChildren() |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
SDK usage
Section titled “SDK usage”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.collaborators.list(notebookId, nodeId);curl -X GET \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators' \ -H "Authorization: Bearer $HOODY_TOKEN"POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators
Section titled “POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators”Adds a user as a collaborator on a node with a specified role. Requires admin permission.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
nodeId | path | string | Yes | Node identifier |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
collaboratorId | string | Yes | Identifier of the user to add as a collaborator |
role | string | Yes | Node-scoped collaborator role. One of admin, editor, collaborator, viewer |
{ "collaboratorId": "u_2c4b9e1a8d3f7b0c", "role": "collaborator"}Response
Section titled “Response”{ "userId": "u_2c4b9e1a8d3f7b0c", "role": "collaborator", "createdAt": "2025-03-02T11:48:19.000Z", "updatedAt": null}{ "message": "Node type does not support collaborators.", "code": "bad_request", "details": [ { "path": "nodeId", "message": "Node type is not section, page, or database" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Unsupported node type | This node type does not support collaborators | Collaborators can only be added to sections, pages, and databases |
{ "message": "You do not have permission to manage collaborators.", "code": "forbidden", "details": [ { "path": "nodeId", "message": "Caller is not an admin on the node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Not an admin | Only admins can manage collaborators on this node | Request admin access from the node owner |
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 |
{ "message": "Collaborator user was not found.", "code": "user_not_found", "details": [ { "path": "collaboratorId", "message": "No notebook user with this ID" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
user_not_found | User not found | The collaborator user does not exist in this notebook | Verify user ID or create the user with client.notes.members.invite() first |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
{ "message": "Idempotency key conflict.", "code": "bad_request", "details": [ { "path": "idempotencyKey", "message": "Key already used for a different request" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Idempotency conflict | A different request was already made with the same idempotency key | Use a new idempotency key for a different request |
{ "message": "An unexpected error occurred.", "code": "unknown", "details": [ { "path": "server", "message": "Unhandled exception" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
unknown | Internal server error | An unexpected error occurred while processing the request | Retry the request; if it persists, contact support |
SDK usage
Section titled “SDK usage”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.collaborators.add(notebookId, nodeId, { collaboratorId: 'u_2c4b9e1a8d3f7b0c', role: 'collaborator'});curl -X POST \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators' \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "collaboratorId": "u_2c4b9e1a8d3f7b0c", "role": "collaborator" }'PATCH /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators/{collaboratorId}
Section titled “PATCH /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators/{collaboratorId}”Changes the role of an existing collaborator. Requires admin permission.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
nodeId | path | string | Yes | Node identifier |
collaboratorId | path | string | Yes | Collaborator identifier to update |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
role | string | Yes | New node-scoped collaborator role. One of admin, editor, collaborator, viewer |
{ "role": "editor"}Response
Section titled “Response”{ "userId": "u_2c4b9e1a8d3f7b0c", "role": "editor", "createdAt": "2025-01-18T14:05:11.000Z", "updatedAt": "2025-03-04T10:22:01.000Z"}{ "message": "Node type does not support collaborators.", "code": "bad_request", "details": [ { "path": "nodeId", "message": "Node type is not section, page, or database" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Unsupported node type | This node type does not support collaborators | Collaborators can only be managed on sections, pages, and databases |
{ "message": "You do not have permission to manage collaborators.", "code": "forbidden", "details": [ { "path": "nodeId", "message": "Caller is not an admin on the node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Not an admin | Only admins can change collaborator roles | Request admin access from the node owner |
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 |
{ "message": "Collaborator not found.", "code": "not_found", "details": [ { "path": "collaboratorId", "message": "No collaborator with this ID on the node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Collaborator not found | No collaborator with the given ID exists on this node | Verify collaborator ID using client.notes.collaborators.list() |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
{ "message": "An unexpected error occurred.", "code": "unknown", "details": [ { "path": "server", "message": "Unhandled exception" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
unknown | Internal server error | An unexpected error occurred while processing the request | Retry the request; if it persists, contact support |
SDK usage
Section titled “SDK usage”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.collaborators.setRole(notebookId, nodeId, collaboratorId, { role: 'editor'});curl -X PATCH \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators/{collaboratorId}' \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "role": "editor" }'DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators/{collaboratorId}
Section titled “DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators/{collaboratorId}”Removes a collaborator from a node. Requires admin permission.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
nodeId | path | string | Yes | Node identifier |
collaboratorId | path | string | Yes | Collaborator identifier to remove |
Response
Section titled “Response”{ "success": true}{ "message": "Node type does not support collaborators.", "code": "bad_request", "details": [ { "path": "nodeId", "message": "Node type is not section, page, or database" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Unsupported node type | This node type does not support collaborators | Collaborators can only be managed on sections, pages, and databases |
{ "message": "You do not have permission to manage collaborators.", "code": "forbidden", "details": [ { "path": "nodeId", "message": "Caller is not an admin on the node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Not an admin | Only admins can remove collaborators | Request admin access from the node owner |
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 |
{ "message": "Collaborator not found.", "code": "not_found", "details": [ { "path": "collaboratorId", "message": "No collaborator with this ID on the node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Collaborator not found | No collaborator with the given ID exists on this node | Verify collaborator ID using client.notes.collaborators.list() |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
{ "message": "An unexpected error occurred.", "code": "unknown", "details": [ { "path": "server", "message": "Unhandled exception" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
unknown | Internal server error | An unexpected error occurred while processing the request | Retry the request; if it persists, contact support |
SDK usage
Section titled “SDK usage”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.collaborators.remove(notebookId, nodeId, collaboratorId);curl -X DELETE \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/collaborators/{collaboratorId}' \ -H "Authorization: Bearer $HOODY_TOKEN"Node reactions
Section titled “Node reactions”GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions
Section titled “GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions”Returns all reactions on a node with the collaborator who reacted.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
nodeId | path | string | Yes | Node identifier |
Response
Section titled “Response”{ "reactions": [ { "reaction": "\uD83D\uDC4D", "collaboratorId": "u_8d3f1a7c9b2e4f5a", "createdAt": "2025-03-04T10:01:22.000Z", "name": "Ada Lovelace", "username": "ada" }, { "reaction": "\uD83D\uDD25", "collaboratorId": "u_2c4b9e1a8d3f7b0c", "createdAt": "2025-03-04T10:05:49.000Z", "name": "Grace Hopper", "username": "grace" } ]}{ "message": "You do not have access to this node.", "code": "forbidden", "details": [ { "path": "nodeId", "message": "No collaborator role on the requested node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Access denied | User does not have permission to access this node | Check collaborator list or request access from the node admin |
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 |
{ "message": "Node not found.", "code": "not_found", "details": [ { "path": "nodeId", "message": "No node with this ID in the notebook" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Node not found | No node exists with the provided ID in this notebook | Verify node ID using client.notes.nodes.list() or client.notes.nodes.listChildren() |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
SDK usage
Section titled “SDK usage”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.reactions.list(notebookId, nodeId);curl -X GET \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions' \ -H "Authorization: Bearer $HOODY_TOKEN"POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions
Section titled “POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions”Adds an emoji reaction to a node on behalf of the current user.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
nodeId | path | string | Yes | Node identifier |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
reaction | string | Yes | Emoji reaction to add. Between 1 and 64 characters |
{ "reaction": "\uD83D\uDC4D"}Response
Section titled “Response”{ "reaction": "\uD83D\uDC4D", "collaboratorId": "u_8d3f1a7c9b2e4f5a", "createdAt": "2025-03-04T10:01:22.000Z"}{ "message": "Invalid reaction payload.", "code": "bad_request", "details": [ { "path": "reaction", "message": "Field is required and must be 1 to 64 characters" } ]}{ "message": "You do not have access to this node.", "code": "forbidden", "details": [ { "path": "nodeId", "message": "No collaborator role on the requested node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Access denied | User does not have permission to access this node | Check collaborator list or request access from the node admin |
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 |
{ "message": "Node not found.", "code": "not_found", "details": [ { "path": "nodeId", "message": "No node with this ID in the notebook" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Node not found | No node exists with the provided ID in this notebook | Verify node ID using client.notes.nodes.list() or client.notes.nodes.listChildren() |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
{ "message": "Idempotency key conflict.", "code": "bad_request", "details": [ { "path": "idempotencyKey", "message": "Key already used for a different request" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
bad_request | Idempotency conflict | A different request was already made with the same idempotency key | Use a new idempotency key for a different request |
{ "message": "An unexpected error occurred.", "code": "unknown", "details": [ { "path": "server", "message": "Unhandled exception" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
unknown | Internal server error | An unexpected error occurred while processing the request | Retry the request; if it persists, contact support |
SDK usage
Section titled “SDK usage”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.reactions.add(notebookId, nodeId, { reaction: '\uD83D\uDC4D'});curl -X POST \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions' \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reaction": "\uD83D\uDC4D" }'DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions/{reaction}
Section titled “DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions/{reaction}”Removes an emoji reaction from a node for the current user.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
nodeId | path | string | Yes | Node identifier |
reaction | path | string | Yes | Emoji reaction to remove. Pass the same string that was used to add it |
Response
Section titled “Response”{ "success": true}{ "message": "You do not have access to this node.", "code": "forbidden", "details": [ { "path": "nodeId", "message": "No collaborator role on the requested node" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
forbidden | Access denied | User does not have permission to access this node | Check collaborator list or request access from the node admin |
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 |
{ "message": "Node not found.", "code": "not_found", "details": [ { "path": "nodeId", "message": "No node with this ID in the notebook" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
not_found | Node not found | No node exists with the provided ID in this notebook | Verify node ID using client.notes.nodes.list() or client.notes.nodes.listChildren() |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
{ "message": "An unexpected error occurred.", "code": "unknown", "details": [ { "path": "server", "message": "Unhandled exception" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
unknown | Internal server error | An unexpected error occurred while processing the request | Retry the request; if it persists, contact support |
SDK usage
Section titled “SDK usage”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.reactions.remove(notebookId, nodeId, '\uD83D\uDC4D');curl -X DELETE \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/reactions/%F0%9F%91%8D' \ -H "Authorization: Bearer $HOODY_TOKEN"Notebook users
Section titled “Notebook users”POST /api/v1/notes/notebooks/{notebookId}/users
Section titled “POST /api/v1/notes/notebooks/{notebookId}/users”Creates one or more users in the notebook by username. Returns created users and any errors.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
users | array | Yes | Users to invite. Maximum 50 entries. Each entry requires username and role |
users[].username | string | Yes | Username to invite |
users[].role | string | Yes | Notebook-wide role. One of owner, admin, collaborator, guest, none. Only an owner can invite a new user as owner; when an admin does, that entry is skipped and listed in errors (the other entries are still created). Inviting a username that is already a member never changes their role: the existing member is returned unchanged |
{ "users": [ { "username": "ada", "role": "admin" }, { "username": "grace", "role": "collaborator" } ]}Response
Section titled “Response”{ "users": [ { "id": "u_8d3f1a7c9b2e4f5a", "name": "Ada Lovelace", "avatar": "https://cdn.hoody.com/avatars/ada.png", "role": "admin", "customName": null, "customAvatar": null, "createdAt": "2025-03-10T12:00:00.000Z", "updatedAt": null, "revision": "r_01HK9EXAMPLE0000000000000000", "status": 1 }, { "id": "u_2c4b9e1a8d3f7b0c", "name": "Grace Hopper", "avatar": null, "role": "collaborator", "customName": null, "customAvatar": null, "createdAt": "2025-03-10T12:00:00.000Z", "updatedAt": null, "revision": "r_01HK9EXAMPLE0000000000000001", "status": 1 } ], "errors": []}{ "message": "At least one user is required.", "code": "user_input_required", "details": [ { "path": "users", "message": "Array is empty or missing" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
user_input_required | User input required | At least one user must be provided in the request body | Provide a non-empty users array with username and role |
{ "message": "Notebook is read-only.", "code": "notebook_readonly", "details": [ { "path": "notebookId", "message": "Write operations are disabled" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
notebook_readonly | Notebook is read-only | The notebook is in read-only mode and cannot be modified | Contact the notebook owner to restore write access |
user_invite_no_access | No permission to add users | User role does not have permission to add users to this notebook | Only owners and admins can add users |
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 |
{ "message": "Notebook not found.", "code": "notebook_not_found", "details": [ { "path": "notebookId", "message": "No notebook with this ID" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
SDK usage
Section titled “SDK usage”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.members.invite(notebookId, { users: [ { username: 'ada', role: 'admin' }, { username: 'grace', role: 'collaborator' } ]});curl -X POST \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/users' \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "users": [ { "username": "ada", "role": "admin" }, { "username": "grace", "role": "collaborator" } ] }'PATCH /api/v1/notes/notebooks/{notebookId}/users/{userId}/role
Section titled “PATCH /api/v1/notes/notebooks/{notebookId}/users/{userId}/role”Changes the notebook role of a user. Requires owner or admin permission. The owner role belongs to owners: only an owner can make someone an owner or change the role of an owner, so an admin can change roles only between admin, collaborator, guest and none, and only for users who are not owners. A notebook always keeps at least one owner: the last owner cannot be demoted until someone else is made owner.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
notebookId | path | string | Yes | Notebook identifier |
userId | path | string | Yes | User identifier in the notebook |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
role | string | Yes | New notebook-wide role. One of owner, admin, collaborator, guest, none |
{ "role": "admin"}Response
Section titled “Response”{ "id": "u_2c4b9e1a8d3f7b0c", "name": "Grace Hopper", "avatar": null, "role": "admin", "customName": null, "customAvatar": null, "createdAt": "2025-03-10T12:00:00.000Z", "updatedAt": "2025-03-11T09:42:11.000Z", "revision": "r_01HK9EXAMPLE0000000000000002", "status": 1}The request body was rejected. The response is an object with message, code, and optional details describing the failing field. Common cases include a role outside the allowed enum, or attempting to demote the last remaining owner.
{ "message": "Notebook is read-only.", "code": "notebook_readonly", "details": [ { "path": "notebookId", "message": "Write operations are disabled" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
notebook_readonly | Notebook is read-only | The notebook is in read-only mode and cannot be modified | Contact the notebook owner to restore write access |
user_update_no_access | No permission to update users | The caller is not an owner or admin, or is an admin trying to grant the owner role or change an owner’s role | Only owners and admins can change user roles; only owners can grant the owner role or change an owner’s role |
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 |
{ "message": "User not found.", "code": "user_not_found", "details": [ { "path": "userId", "message": "No notebook user with this ID" } ]}| Error Code | Title | Description | Resolution |
|---|---|---|---|
user_not_found | User not found | No user exists with the provided ID in this notebook | Verify user ID using the users list |
notebook_not_found | Notebook not found | No notebook exists with the provided ID | Verify the notebook ID in the URL |
SDK usage
Section titled “SDK usage”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.members.setRole(notebookId, userId, { role: 'admin'});curl -X PATCH \ 'https://{projectId}-{containerId}-notes-1.{server}.containers.hoody.com/api/v1/notes/notebooks/{notebookId}/users/{userId}/role' \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "role": "admin" }'