# Notes: Nodes & Documents

**Page:** api/notes/nodes

[Download Raw Markdown](./api/notes/nodes.md)

---

{/* AUTO-GENERATED — Do not edit manually. Regenerate with: npm run docs:api:generate */}



The Notes Nodes & Documents API lets you manage the tree structure of a notebook, read and write block-based document content, export pages to static formats, and track read interactions. Use these endpoints to build notebook navigation, sync editor content, and surface read receipts.

## Nodes — Read

### `GET /api/v1/notes/notebooks/{notebookId}/nodes`

Returns a paginated list of nodes the user has access to. Filterable by type, parentId, and rootId.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `type` | query | string | No | Filter by node type. |
| `parentId` | query | string | No | Filter by parent node ID. |
| `rootId` | query | string | No | Filter by root node ID. |
| `limit` | query | integer | No | Page size. Default: `50`. |
| `offset` | query | integer | No | Pagination offset. Default: `0`. |
| `notebookId` | path | string | Yes | Notebook ID. |



```bash
curl -X GET "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes?type=page&limit=25" \
  -H "Authorization: Bearer <token>"
```


```ts
const { nodes, total } = await client.notes.nodes.list({
  notebookId: "nb_abc123",
  type: "page",
  limit: 25,
});
```


```json
{
  "nodes": [
    {
      "id": "node_8f3a2b",
      "type": "page",
      "parentId": "node_root01",
      "name": "Onboarding"
    },
    {
      "id": "node_1d9c4e",
      "type": "section",
      "parentId": "node_root01",
      "name": "Engineering"
    }
  ],
  "total": 42
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden",
  "details": [
    { "path": "notebookId", "message": "Not a collaborator" }
  ]
}
```

| 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 |



### `GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}`

Returns the full details of a single node by ID.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |



```bash
curl -X GET "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b" \
  -H "Authorization: Bearer <token>"
```


```ts
const node = await client.notes.nodes.get({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
});
```


```json
{
  "id": "node_8f3a2b",
  "type": "page",
  "name": "Onboarding",
  "parentId": "node_root01",
  "alias": "onboarding",
  "createdAt": "2025-01-12T10:14:22Z"
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Node not found | No node exists with the provided ID in this notebook | Verify node ID using listNodes or listNodeChildren |



### `GET /api/v1/notes/notebooks/{notebookId}/nodes/alias/{alias}`

Resolves a page node by its safe alias within the notebook scope.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `alias` | path | string | Yes | Page alias. |



```bash
curl -X GET "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/alias/onboarding" \
  -H "Authorization: Bearer <token>"
```


```ts
const node = await client.notes.nodes.getByAlias({
  notebookId: "nb_abc123",
  alias: "onboarding",
});
```


```json
{
  "id": "node_8f3a2b",
  "type": "page",
  "name": "Onboarding",
  "alias": "onboarding",
  "parentId": "node_root01"
}
```


```json
{
  "message": "Invalid alias format.",
  "code": "bad_request",
  "details": [
    { "path": "alias", "message": "Alias must be lowercase alphanumeric with dashes" }
  ]
}
```


```json
{
  "message": "You do not have access to this notebook.",
  "code": "forbidden"
}
```


```json
{
  "message": "No node found with that alias.",
  "code": "not_found"
}
```



### `GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/children`

Returns a paginated list of direct children of the specified node.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `limit` | query | integer | No | Page size. Default: `50`. |
| `offset` | query | integer | No | Pagination offset. Default: `0`. |
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Parent node ID. |



```bash
curl -X GET "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_root01/children?limit=10" \
  -H "Authorization: Bearer <token>"
```


```ts
const { nodes, total } = await client.notes.nodes.listChildren({
  notebookId: "nb_abc123",
  nodeId: "node_root01",
  limit: 10,
});
```


```json
{
  "nodes": [
    {
      "id": "node_8f3a2b",
      "type": "page",
      "name": "Onboarding"
    },
    {
      "id": "node_1d9c4e",
      "type": "section",
      "name": "Engineering"
    }
  ],
  "total": 7
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Node not found | No node exists with the provided ID in this notebook | Verify node ID using listNodes or listNodeChildren |



## Nodes — Write

### `POST /api/v1/notes/notebooks/{notebookId}/nodes`

Creates a new node (section, page, channel, message, database, or record) in the notebook.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | No | Optional client-provided ID. |
| `type` | string | Yes | Node type (e.g. `page`, `section`, `channel`). |
| `parentId` | string | No | Parent node ID. |
| `attributes` | object | Yes | Type-specific attributes (name, icon, etc.). |



```bash
curl -X POST "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "page",
    "parentId": "node_root01",
    "attributes": { "name": "Onboarding", "icon": "🚀" }
  }'
```


```ts
const node = await client.notes.nodes.create({
  notebookId: "nb_abc123",
  data: {
    type: "page",
    parentId: "node_root01",
    attributes: { name: "Onboarding", icon: "🚀" },
  },
});
```


```json
{
  "id": "node_8f3a2b",
  "type": "page",
  "name": "Onboarding",
  "parentId": "node_root01"
}
```


```json
{
  "message": "Invalid node type.",
  "code": "bad_request",
  "details": [
    { "path": "type", "message": "Unsupported type 'folder'" }
  ]
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Invalid node data | The request body is invalid — missing required fields or unsupported node type | Check the node type is valid and all required attributes are provided |


```json
{
  "message": "You do not have permission to perform this action.",
  "code": "forbidden"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `forbidden` | Insufficient permissions | User role does not have permission for this action | Request a higher role from the notebook or node admin |


```json
{
  "message": "Idempotency key conflict.",
  "code": "bad_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 |


```json
{
  "message": "An unexpected error occurred.",
  "code": "unknown"
}
```

| 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 |



### `PATCH /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}`

Updates node attributes (name, description, etc.). Type and parentId cannot be changed.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `attributes` | object | Yes | Partial attributes object to merge. |



```bash
curl -X PATCH "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "attributes": { "name": "Onboarding Guide", "icon": "📘" }
  }'
```


```ts
const node = await client.notes.nodes.update({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  data: { attributes: { name: "Onboarding Guide", icon: "📘" } },
});
```


```json
{
  "id": "node_8f3a2b",
  "type": "page",
  "name": "Onboarding Guide",
  "icon": "📘"
}
```


```json
{
  "message": "Invalid attributes payload.",
  "code": "bad_request",
  "details": [
    { "path": "attributes", "message": "name must be a non-empty string" }
  ]
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Node not found | No node exists with the provided ID in this notebook | Verify node ID using listNodes or listNodeChildren |


```json
{
  "message": "Concurrent update conflict.",
  "code": "conflict"
}
```


```json
{
  "message": "An unexpected error occurred.",
  "code": "unknown"
}
```

| 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 |



### `DELETE /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}`

Permanently deletes a node and its associated data (documents, files, reactions).


This action is irreversible. All child nodes, documents, and attachments under the deleted node are also removed.


#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |



```bash
curl -X DELETE "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b" \
  -H "Authorization: Bearer <token>"
```


```ts
const { success } = await client.notes.nodes.delete({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
});
```


```json
{
  "success": true
}
```


```json
{
  "message": "You do not have permission to perform this action.",
  "code": "forbidden"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `forbidden` | Insufficient permissions | User role does not have permission for this action | Request a higher role from the notebook or node admin |


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Node not found | No node exists with the provided ID in this notebook | Verify node ID using listNodes or listNodeChildren |


```json
{
  "message": "An unexpected error occurred.",
  "code": "unknown"
}
```

| 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 |



## Documents

### `GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/document`

Retrieves document content for a node. Supports block filtering via `blockIds` and line range queries.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `blockIds` | query | string | No | Comma-separated list of block IDs to include. |
| `lines` | query | string | No | Line range in the form `start-end` (e.g. `1-50`). |
| `output` | query | string | No | Output format. One of `json`, `md`, `html`. |
| `includeComments` | query | string | No | Include comments. One of `none`, `appendix`. Default: `"none"`. |
| `ticket` | query | string | No | Pre-issued export ticket (required when `output=html`). |
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |



```bash
curl -X GET "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b/document?output=md" \
  -H "Authorization: Bearer <token>"
```


```ts
const doc = await client.notes.documents.get({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  output: "md",
  includeComments: "none",
});
```


```json
{
  "id": "doc_4b71a9",
  "content": {
    "type": "doc",
    "content": [
      { "type": "heading", "level": 1, "text": "Onboarding" },
      { "type": "paragraph", "text": "Welcome to the team." }
    ]
  },
  "createdAt": "2025-01-12T10:14:22Z",
  "createdBy": "user_1a2b3c",
  "updatedAt": "2025-02-04T08:31:05Z",
  "updatedBy": "user_4d5e6f"
}
```


```json
{
  "message": "Invalid or missing authentication.",
  "code": "unauthorized"
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |


```json
{
  "message": "Document not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Document not found | No document content exists for this node, or the node type does not support documents | Create document content with putDocument first |



### `PUT /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/document`

Creates a new document or fully replaces an existing document for a node.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `content` | object | Yes | Full document content (block tree). |



```bash
curl -X PUT "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b/document" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "content": {
      "type": "doc",
      "content": [
        { "type": "heading", "level": 1, "text": "Onboarding" },
        { "type": "paragraph", "text": "Welcome to the team." }
      ]
    }
  }'
```


```ts
const doc = await client.notes.documents.put({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  data: {
    content: {
      type: "doc",
      content: [
        { type: "heading", level: 1, text: "Onboarding" },
        { type: "paragraph", text: "Welcome to the team." },
      ],
    },
  },
});
```


```json
{
  "id": "doc_4b71a9",
  "content": {
    "type": "doc",
    "content": [
      { "type": "heading", "level": 1, "text": "Onboarding" }
    ]
  },
  "createdAt": "2025-01-12T10:14:22Z",
  "createdBy": "user_1a2b3c",
  "updatedAt": "2025-02-05T09:00:00Z",
  "updatedBy": "user_1a2b3c"
}
```


```json
{
  "message": "Node type does not support documents.",
  "code": "bad_request"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Unsupported node type | This node type does not support document content | Only page, channel, and similar node types support documents |


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |
| `forbidden` | Insufficient permissions | User role does not have permission for this action | Request a higher role from the notebook or node admin |


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Node not found | No node exists with the provided ID in this notebook | Verify node ID using listNodes or listNodeChildren |


```json
{
  "message": "An unexpected error occurred.",
  "code": "unknown"
}
```

| 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 |



### `PATCH /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/document`

Merges content into an existing document at the top level. Existing blocks are preserved unless overwritten.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `content` | object | Yes | Block-level content to merge. |



```bash
curl -X PATCH "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b/document" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "content": {
      "type": "doc",
      "content": [
        { "type": "paragraph", "text": "Added in patch." }
      ]
    }
  }'
```


```ts
const doc = await client.notes.documents.patch({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  data: {
    content: {
      type: "doc",
      content: [{ type: "paragraph", text: "Added in patch." }],
    },
  },
});
```


```json
{
  "id": "doc_4b71a9",
  "content": {
    "type": "doc",
    "content": [
      { "type": "heading", "level": 1, "text": "Onboarding" },
      { "type": "paragraph", "text": "Added in patch." }
    ]
  },
  "createdAt": "2025-01-12T10:14:22Z",
  "createdBy": "user_1a2b3c",
  "updatedAt": "2025-02-05T11:22:18Z",
  "updatedBy": "user_1a2b3c"
}
```


```json
{
  "message": "Node type does not support documents.",
  "code": "bad_request"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Unsupported node type | This node type does not support document content | Only page, channel, and similar node types support documents |


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |
| `forbidden` | Insufficient permissions | User role does not have permission for this action | Request a higher role from the notebook or node admin |


```json
{
  "message": "Document not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Document not found | No document exists for this node — create it with putDocument first | Use putDocument to create the document before patching |


```json
{
  "message": "An unexpected error occurred.",
  "code": "unknown"
}
```

| 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 |



## Export

### `GET /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/blocks/{blockId}/svg`

Renders a drawing block as an SVG image. Supports optional background color and scale factor.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `bg` | query | string | No | CSS-compatible background color (e.g. `#ffffff`, `transparent`). |
| `scale` | query | number | No | Scale factor applied to the output dimensions. |
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |
| `blockId` | path | string | Yes | Drawing block ID. |



```bash
curl -X GET "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b/blocks/block_d12/svg?bg=transparent&scale=2" \
  -H "Authorization: Bearer <token>" \
  -o drawing.svg
```


```ts
const svg = await client.notes.documents.exportBlockSvg({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  blockId: "block_d12",
  bg: "transparent",
  scale: 2,
});
```


```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">
  <rect width="100%" height="100%" fill="transparent"/>
  <path d="M10 80 Q 95 10 180 80 T 350 80" stroke="#1f6feb" fill="none" stroke-width="3"/>
</svg>
```


The response body is raw `image/svg+xml`. Save it to a file or stream directly to a client.




### `POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/export-ticket`

Creates a short-lived export ticket for static HTML document delivery. Pass the returned `ticket` to `getDocument` with `output=html`.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |

#### Request Body

| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `output` | string | No | `"html"` | Export format. Must be `html`. |
| `includeComments` | string | No | `"none"` | Whether to append comments. One of `none`, `appendix`. |
| `includeBackground` | boolean | No | `true` | Whether to render the page background. |
| `themeMode` | string | No | `"dark"` | Theme mode. One of `light`, `dark`. |
| `themeId` | string \| null | No | — | Optional theme identifier (max 64 chars). |
| `themeVariables` | object | No | — | Map of theme variable name to value. |
| `fileName` | string | No | — | Suggested file name (max 128 chars). |



```bash
curl -X POST "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b/export-ticket" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "output": "html",
    "includeComments": "appendix",
    "themeMode": "light",
    "fileName": "Onboarding.html"
  }'
```


```ts
const { ticket, expiresAt, usesRemaining } = await client.notes.documents.createExportTicket({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  data: {
    output: "html",
    includeComments: "appendix",
    themeMode: "light",
    fileName: "Onboarding.html",
  },
});
```


```json
{
  "ticket": "tk_01HXY8K3B5QJZ9W3E0F2M7PR8V",
  "expiresAt": "2025-02-05T11:30:00Z",
  "usesRemaining": 3
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```



## Interactions

### `POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/interactions/opened`

Records that the current user has opened the node. Tracks first and last opened timestamps.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `openedAt` | string | No | ISO-8601 timestamp; defaults to server time. |



```bash
curl -X POST "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b/interactions/opened" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{}'
```


```ts
const result = await client.notes.interactions.markOpened({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  data: {},
});
```


```json
{
  "nodeId": "node_8f3a2b",
  "collaboratorId": "collab_7e1a",
  "firstSeenAt": "2025-01-20T09:00:00Z",
  "lastSeenAt": "2025-02-05T11:22:18Z",
  "firstOpenedAt": "2025-02-05T11:22:18Z",
  "lastOpenedAt": "2025-02-05T11:22:18Z"
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Node not found | No node exists with the provided ID in this notebook | Verify node ID using listNodes or listNodeChildren |


```json
{
  "message": "Idempotency key conflict.",
  "code": "bad_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 |


```json
{
  "message": "An unexpected error occurred.",
  "code": "unknown"
}
```

| 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 |



### `POST /api/v1/notes/notebooks/{notebookId}/nodes/{nodeId}/interactions/seen`

Records that the current user has seen the node. Tracks first and last seen timestamps.

#### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `notebookId` | path | string | Yes | Notebook ID. |
| `nodeId` | path | string | Yes | Node ID. |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `seenAt` | string | No | ISO-8601 timestamp; defaults to server time. |



```bash
curl -X POST "https://api.hoody.com/api/v1/notes/notebooks/nb_abc123/nodes/node_8f3a2b/interactions/seen" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{}'
```


```ts
const result = await client.notes.interactions.markSeen({
  notebookId: "nb_abc123",
  nodeId: "node_8f3a2b",
  data: {},
});
```


```json
{
  "nodeId": "node_8f3a2b",
  "collaboratorId": "collab_7e1a",
  "firstSeenAt": "2025-02-05T11:21:00Z",
  "lastSeenAt": "2025-02-05T11:21:00Z",
  "firstOpenedAt": null,
  "lastOpenedAt": null
}
```


```json
{
  "message": "You do not have access to this node.",
  "code": "forbidden"
}
```

| 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 |


```json
{
  "message": "Node not found.",
  "code": "not_found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Node not found | No node exists with the provided ID in this notebook | Verify node ID using listNodes or listNodeChildren |


```json
{
  "message": "Idempotency key conflict.",
  "code": "bad_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 |


```json
{
  "message": "An unexpected error occurred.",
  "code": "unknown"
}
```

| 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 |