# /note-folders

8 routes.

Notes v3. Folders for notes, nesting ONE level: a top-level folder can hold folders, and those hold only notes. Trashing a folder takes its subfolders and their notes with it, as trashing a project takes its contents, and restoring brings them back.

- [GET /v1/note-folders](#get-v1-note-folders)
- [POST /v1/note-folders](#post-v1-note-folders)
- [GET /v1/note-folders/{id}](#get-v1-note-folders-id)
- [PATCH /v1/note-folders/{id}](#patch-v1-note-folders-id)
- [POST /v1/note-folders/{id}/move](#post-v1-note-folders-id-move)
- [POST /v1/note-folders/{id}/trash](#post-v1-note-folders-id-trash)
- [POST /v1/note-folders/{id}/restore](#post-v1-note-folders-id-restore)
- [DELETE /v1/note-folders/{id}](#delete-v1-note-folders-id)

## GET /v1/note-folders

List note folders

Ordered by `sortKey`. `?parent_id=` takes a folder id, or `null` for the top level. Trashed folders are excluded unless `?include_trashed=true`. `noteCount` counts the live notes directly in each folder.

**Scopes**: `notes:read`

**Query**

| parameter | type | | notes |
|---|---|---|---|
| `limit` | integer | optional | min 1, max 200 |
| `cursor` | string | optional | max 4096 chars |
| `updated_since` | string (RFC 3339) | optional | max 24 chars |
| `parent_id` | string | optional | max 64 chars |
| `include_trashed` | `true`, `false` | optional |  |

**Response**

- **200** [NoteFolderList](/objects#notefolderlist). One page of folders.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [account_too_large](/errors/account_too_large) * [validation_failed](/errors/validation_failed) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)

## POST /v1/note-folders

Create a note folder

`parentId` puts it inside a TOP-LEVEL folder; folders nest one level only, so a folder that is itself inside another is refused at `/parentId`. It goes to the end of its siblings.

**Scopes**: `notes:write`  
**Idempotent.** Send `Idempotency-Key` and a retry replays the first answer instead of writing twice.

**Request body**

| field | type | | notes |
|---|---|---|---|
| `name` | string | required | max 512 chars |
| `colorHex` | string | optional | or null, 6-digit hex, with or without the `#`, max 16 chars |
| `symbol` | string | optional | or null, pattern `^[a-z0-9]+(\.[a-z0-9]+)*$`, max 64 chars |
| `parentId` | string | optional | or null, max 64 chars |
| `id` | string (UPPERCASE UUID) | optional | max 64 chars |

**Response**

- **201** [NoteFolder](/objects#notefolder). The folder as stored.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [conflict](/errors/conflict) * [duplicate_id](/errors/duplicate_id) * [payload_too_large](/errors/payload_too_large) * [unsupported_media_type](/errors/unsupported_media_type) * [account_too_large](/errors/account_too_large) * [validation_failed](/errors/validation_failed) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)

## GET /v1/note-folders/{id}

One note folder

**Scopes**: `notes:read`

**Response**

- **200** [NoteFolder](/objects#notefolder). The folder.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [not_found](/errors/not_found) * [account_too_large](/errors/account_too_large) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)

## PATCH /v1/note-folders/{id}

Rename, recolour or change the icon

`parentId` is refused here: moving reissues the ordering key among the new siblings, so it is `/move`. `null` clears the colour or the icon.

**Scopes**: `notes:write`

**Request body**

| field | type | | notes |
|---|---|---|---|
| `name` | string | optional | max 512 chars |
| `colorHex` | string | optional | or null, which clears it, 6-digit hex, with or without the `#`, max 16 chars |
| `symbol` | string | optional | or null, which clears it, pattern `^[a-z0-9]+(\.[a-z0-9]+)*$`, max 64 chars |

**Response**

- **200** [NoteFolder](/objects#notefolder). The folder after the change.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [not_found](/errors/not_found) * [payload_too_large](/errors/payload_too_large) * [unsupported_media_type](/errors/unsupported_media_type) * [account_too_large](/errors/account_too_large) * [validation_failed](/errors/validation_failed) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)

## POST /v1/note-folders/{id}/move

Move a folder, or reorder it

`parentId: null` moves it to the top level. One level only: a folder that has folders inside it can only sit at the top. `after`/`before` name a sibling folder.

**Scopes**: `notes:write`

**Request body**

| field | type | | notes |
|---|---|---|---|
| `parentId` | string | required | or null, max 64 chars |
| `after` | string | optional | max 64 chars |
| `before` | string | optional | max 64 chars |

**Response**

- **200** [NoteFolder](/objects#notefolder). The folder in its new place.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [not_found](/errors/not_found) * [payload_too_large](/errors/payload_too_large) * [unsupported_media_type](/errors/unsupported_media_type) * [account_too_large](/errors/account_too_large) * [validation_failed](/errors/validation_failed) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)

## POST /v1/note-folders/{id}/trash

Trash a folder, its subfolders and their notes

Stamps the FOLDER only. Its subfolders and the notes in them go to the trash with it, the way a project’s contents do: they keep `trashedAt: null` and leave every view and list of live notes. Only the folder is listed in `/trash`.

**Scopes**: `notes:write`

**Response**

- **200** [NoteFolder](/objects#notefolder). The folder, now trashed.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [not_found](/errors/not_found) * [payload_too_large](/errors/payload_too_large) * [unsupported_media_type](/errors/unsupported_media_type) * [account_too_large](/errors/account_too_large) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)

## POST /v1/note-folders/{id}/restore

Restore a folder and its batch

Clears the folder’s `trashedAt`; its subfolders and notes come back with it. A note trashed on its own before stays in the trash.

**Scopes**: `notes:write`

**Response**

- **200** [NoteFolder](/objects#notefolder). The folder, live again.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [not_found](/errors/not_found) * [payload_too_large](/errors/payload_too_large) * [unsupported_media_type](/errors/unsupported_media_type) * [account_too_large](/errors/account_too_large) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)

## DELETE /v1/note-folders/{id}

Delete a trashed folder permanently

Irreversible: the folder, its subfolders and every note in them (with their links and attachments). ⚠ Only a TRASHED folder: a live one is `conflict`, so trash it first.

**Scopes**: `notes:write`

**Response**

- **204** No body. Deleted. Irreversible.

**Errors**: [grant_expired](/errors/grant_expired) * [grant_revoked](/errors/grant_revoked) * [unauthorized](/errors/unauthorized) * [forbidden_scope](/errors/forbidden_scope) * [not_found](/errors/not_found) * [conflict](/errors/conflict) * [account_too_large](/errors/account_too_large) * [rate_limited](/errors/rate_limited) * [internal](/errors/internal)
