> ## Documentation Index
> Fetch the complete documentation index at: https://woku.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Folders and tools

> Organize wokus and NPS, CSAT and CES tools in a single folder tree: search, compare figures per type, move in bulk and get a folder's report and CSV through the API, SDKs or MCP

A **folder** groups wokus and NPS, CSAT and CES tools **in one tree**. You can nest folders inside folders, move any tool between them and look at a whole folder as a single unit: its figures, its report and a CSV with all its responses.

This guide covers how to do it from the v1 API, the official SDKs and the MCP server. All three use the same model.

## How it works

* A **folder** has a name, an optional color and, when nested, a parent folder. The **root** is the level with no folder.
* Each **tool** (woku, NPS, CSAT or CES) lives in one folder or at the root. Existing tools stay at the root until you move them.
* **Deleting a folder** deletes nothing inside it: its subfolders, wokus and tools move up to the parent folder (or the root).
* Moving is always reversible and does not change a tool's responses or public links.

<Note>
  The four types use different scales (stars from 1 to 5, NPS from 0 to 10, CSAT and CES from 1 to 5), so woku **never averages them together**. Each type shows its headline figure on its native scale.
</Note>

## In the app

In woku, the **Tools** view shows the same tree: folders on top and, below, wokus and NPS, CSAT and CES tools with their headline figure. You can see it as a **Grid** or a **List**, filter by type and search the whole company (also by **trackers**, see below). You can create folders with a color, drag tools into a folder or use **Move to...**, and each folder has its own menu to edit it, delete it, set up its WhatsApp alerts and WhatsApp access, and open its report.

A **folder report** has two tabs:

* **Text analytics** (the main one): the AI analysis of every comment of the folder and its subfolders, shaped like the report of a woku (recognitions, improvement opportunities, word cloud and summary). While it is generated, a progress bar shows that the report is on its way.
* **Metrics by tool**: four cards (one per type, each on its own scale) with the change against the previous period, how the result evolves over time, the distribution of scores, where the responses come from and the tools worth looking at first. You can see the whole history or the last 7, 30 or 90 days.

Everything you see in the app is also available through the API, the SDKs and the MCP, except a folder's WhatsApp access, which for now is configured only in the app.

## Folders

Use `/v1/folders` to manage the tree.

| Operation | Endpoint |
| - | - |
| List folders (all of them, or the subfolders of one) | `GET /v1/folders` |
| Create a folder | `POST /v1/folders` |
| Get a folder with its stats | `GET /v1/folders/:id` |
| Rename, change the color or set the WhatsApp alert numbers | `PATCH /v1/folders/:id` |
| Move a folder (or send it to the root) | `PATCH /v1/folders/:id/move` |
| Delete a folder (its content moves up to the parent) | `DELETE /v1/folders/:id` |

Each folder includes its path (`path`, for example `Post-sale > Delivery`) and the stats of its subtree: how many tools of each type it holds, how many subfolders and how many reviews.

```bash theme={null}
curl --request POST https://clientapi.woku.app/v1/folders \
  --header "Authorization: Bearer $WOKU_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{ "name": "Post-sale", "color": "#3498db" }'
```

To nest a folder, send `parentFolderId`. To move a folder to the root, use `PATCH /v1/folders/:id/move` with `{ "parentFolderId": null }`. A folder cannot move into itself or one of its subfolders.

## Create a tool inside a folder

NPS, CSAT and CES creations accept `folderId` (wokus keep their own creation flow and move with `PATCH /v1/wokus/:id/move`). The folder must belong to your company; otherwise the response is `404`.

```bash theme={null}
curl --request POST https://clientapi.woku.app/v1/csat-tools \
  --header "Authorization: Bearer $WOKU_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{ "name": "Delivery", "question": "How satisfied are you with your delivery?", "folderId": "<folder id>" }'
```

To move a tool that already exists: `PATCH /v1/nps-tools/:id/move`, `PATCH /v1/csat-tools/:id/move` or `PATCH /v1/ces-tools/:id/move`, with `{ "folderId": "<id>" }`, or `{ "folderId": null }` for the root. Every tool returns its `folderId` (`null` at the root).

## Search and list tools

`GET /v1/tools` returns folders and tools of **every type** in a single cursor-paginated list.

| Parameter | What it does |
| - | - |
| `folderId` | Lists that folder's direct content. Without it, lists the root. |
| `scope=company` | Lists every tool of the company as a flat list. |
| `q` | Searches names and questions, ignoring case and accents. The search covers the whole company and also returns matching folders. |
| `types` | Filters by type: `woku`, `nps`, `csat`, `ces` (comma separated). |
| `sort` | `name` (default), `-name`, `created` or `-created`. |
| `trackers` | Tracker chips, repeatable (`?trackers=TRR:00482&trackers=OC:2024`). A tool matches when it has **every** one: the tracker name is matched exactly and the value partially and ignoring case (`482` also matches `00482`). Up to 10 chips. Like a search, it is company-wide and lists no folders. A tracker the company does not have matches nothing, and a chip without a name or a value answers `400`. |
| `createdFrom`, `createdTo` | Creation date range. |
| `limit`, `cursor` | Page size (up to 100) and the next page cursor (`nextCursor`). |
| `foldersLimit`, `foldersCursor` | "See more" for folders: `foldersLimit` (1 to 100) pages the folders of the level; without it every folder is returned. With `foldersCursor` (the previous `foldersNextCursor`) only that page of folders is returned, without tools. |

The response carries `folders`, `foldersNextCursor`, `tools`, `nextCursor` and `facets` (how many tools of each type match the filters). Each tool includes `type`, `name`, `folderId`, `reviewCount`, `lastResponseAt` and its headline figure on its native scale (`headline`).

## Figures per type

`GET /v1/tools/stats` returns, for the whole company or for a folder and its subfolders (`folderId`), the reviews and the headline figure of each type, optionally within a period (`from`, `to`):

| Type | Headline figure |
| - | - |
| Woku | Average stars (1 to 5) |
| NPS | NPS score (from -100 to 100), with promoters, passives and detractors |
| CSAT | Percentage of satisfied responses (scores 4 and 5) |
| CES | Average effort (1 to 5) |

A type with no responses returns `null` as its figure. If a type fails to compute, it reports `{ "error": true }` and the others stay valid.

## Metrics per tool of a folder

`GET /v1/folders/:id/metrics` returns, for a folder and its subfolders, the figures of **each** tool (woku, NPS, CSAT and CES) over a period, compared with the previous period of the same length.

| Parameter | What it does |
| - | - |
| `days` | Period in days: `7`, `30` (default) or `90`. With `0` the whole history is computed and `previous` is empty (`count: 0` and `null` figures). |

The response has:

* `tools`: one row per tool with `type`, `id`, `name`, `totalResponses`, `lastResponseAt` and two windows, `current` and `previous`, each with `count`, `headline` (the figure on its native scale), `positive` and `negative` (share of positive and negative responses: 4 and 5 or 1 and 2, or promoters and detractors for NPS) and the raw counts `positiveCount`, `negativeCount` and `scoreSum`, to combine tools without rounding drift.
* `daily`: the daily sums (in UTC) of both periods per type (`count`, `scoreSum` and the `positive` and `negative` counts), to draw a trend with any grouping. The windows are UTC calendar days ending today, so summing `daily` over the period gives `current.count`.
* `distribution`: how many responses each score got in the period. For NPS position 0 is score 0 (11 positions); for the rest position 0 is score 1 (5 positions).

Scales are never mixed across types. A tool with no responses returns `null` as its figure. On the MCP, `get_folder_tools_metrics` returns `toolCount` and the tools with the most responses (`limit`, 50 by default), and the daily sums only with `includeDaily`.

```bash theme={null}
curl "https://clientapi.woku.app/v1/folders/FOLDER_ID/metrics?days=30" \
  --header "Authorization: Bearer $WOKU_API_KEY"
```

## Move in bulk

`POST /v1/tools/move` moves up to 200 items of mixed types in a single call. It is idempotent: moving items to where they already are succeeds. If an item or the destination folder is missing, nothing moves.

```json theme={null}
{
  "items": [
    { "type": "csat", "id": "<tool id>" },
    { "type": "woku", "id": "<woku id>" },
    { "type": "folder", "id": "<folder id>" }
  ],
  "folderId": null
}
```

Use `"folderId": null` to send the items to the root.

## A folder's report, PDF and CSV

* `GET /v1/folders/:id/report` generates (and stores) an AI report over **all** the tools of the folder and its subfolders: recognitions, improvement opportunities, word cloud and summary. Each quote keeps the context of its tool. Because the scales differ, the report does not include a score distribution. A report that was already generated is reused while the number of reviews does not change; use `regenerate=true` to force a new one and `lang=es` or `lang=en` for the language. A folder with no tools, or with fewer than two commented responses, returns an empty report, not an error.
* `GET /v1/folders/:id/pdf` downloads the report as a PDF file (`lang=es` or `lang=en`), with a breakdown per tool type (count, responses and headline figure on its native scale). It has no rating distribution. It is a binary file: it is on the API and the SDKs, not on the MCP server.
* `GET /v1/folders/:id/csv` downloads a CSV file with **one row per response** of every tool in the folder and its subfolders: folder and path, tool type and name, score with its scale, comment, comment type (text or audio), classification (recognition or improvement), customer email, channel and date. A customer that no longer exists leaves the cell empty, and an anonymous response shows as `Anónimo`.

## WhatsApp alerts per folder

A folder can alert people on WhatsApp when a comment classified as an **improvement opportunity** arrives on any of its tools: wokus, NPS, CSAT or CES. The recipients are the numbers configured on the folder.

```bash theme={null}
curl --request PATCH https://clientapi.woku.app/v1/folders/FOLDER_ID \
  --header "Authorization: Bearer $WOKU_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{ "whatsappAlertRecipients": [{ "whatsappId": "56912345678", "name": "Ana" }] }'
```

* `whatsappAlertRecipients` **replaces** the previous list (up to 10); send `[]` to remove every number. Numbers use E.164 format without the `+`.
* Each number can carry `sources` (`woku`, `nps`, `csat`, `ces`): the kinds of comment that alert it. If you omit it, the number is alerted for all four. Numbers that existed before this feature keep receiving woku alerts only.
* A folder's number also receives the alerts of the tools in its subfolders, once even if it is in several.
* Every folder returns the list as `whatsappAlertRecipients`.
* So that a journey creating a tool per order cannot flood anyone, each number receives at most **5 tool alerts per hour**; later ones are dropped.
* The alert is sent **once per response** and counts as one WhatsApp notification of your plan. It includes the company, the tool with its folder, the customer, the comment and the score on its scale.
* In the MCP, `update_folder` accepts the same field.

## Journeys in folders

Each customer journey creates its own CSAT, CES and NPS tools, thousands of them if the journey creates one per order. So they do not pile up at the root, woku can sort them on its own into the tree **Viajes > journey > moment**.

* The organization is **optional per company**. You switch it on once and from then on the new tools of each moment are placed in their moment's folder.
* When you switch it on, a **one-off pass in the background** moves the tools of existing journeys that still have no folder. It is safe to repeat: it never touches what already has a folder and a second run changes nothing.
* If you move a tool to another folder, it **does not go back on its own**. Moving or renaming the folders of the tree never breaks a journey: the next case keeps creating its tool in its moment's folder, wherever that folder is now.
* Integrations sort their own folders the same way (for example Shopify and Pancake).

| Operation | Endpoint |
| - | - |
| See the status (whether it is on, running and how much is left) | `GET /v1/journey-folders` |
| Switch it on and run the one-off pass (answers `202`; `409` if one is already running) | `POST /v1/journey-folders/organize` |

The status includes `enabled`, `enabledAt`, `organizedAt`, `organizing` and `pending` (journeys and tools still without a folder). Check it every so often while `organizing` is `true`.

```bash theme={null}
curl --request POST https://clientapi.woku.app/v1/journey-folders/organize \
  --header "Authorization: Bearer $WOKU_API_KEY"
```

`GET /v1/journeys` and `GET /v1/journeys/:id` return `folderId` (the journey's folder) and `momentFolders` (the folder of each moment, by its key). Before organizing, `folderId` is `null` and `momentFolders` is `{}`. The folders woku creates (the `Viajes` root, each journey, each moment and the integration ones) report their `origin` in `GET /v1/folders` and `GET /v1/tools`: `journeys-root`, `journey`, `journey-moment` or `integration`. Integration folders also report `integrationProvider` (for example `shopify` or `pancake`). Your own folders have `origin: null`.

```ts theme={null}
const status = await woku.journeyFolders.status();
if (!status.enabled) await woku.journeyFolders.organize();
const journey = await woku.journeys.get(journeyId);
console.log(journey.folderId, journey.momentFolders);
```

On the MCP server, `get_journey_folders_status` and `organize_journey_folders` do the same, and `get_journey` and `list_journeys` include `folderId` and `momentFolders`.

## SDKs and MCP

<CodeGroup>
  ```ts JavaScript theme={null}
  const folder = await woku.folders.create({ name: 'Post-sale' });
  await woku.csatTools.create({ name: 'Delivery', question: 'How satisfied are you?', folderId: folder.id });

  for await (const tool of await woku.tools.list({ folderId: folder.id, types: ['csat', 'nps'] })) {
    console.log(tool.type, tool.name, tool.headline.value);
  }
  const stats = await woku.tools.stats({ folderId: folder.id });
  await woku.tools.move({ items: [{ type: 'csat', id: toolId }], folderId: null });
  const csv = await woku.folders.csv(folder.id);
  const pdf = await woku.folders.pdf(folder.id, { lang: 'en' }); // Uint8Array
  const metrics = await woku.folders.metrics(folder.id, { days: 30 }); // per tool, against the previous period
  const tagged = await woku.tools.list({ trackers: ['TRR:00482'] });
  ```

  ```python Python theme={null}
  folder = woku.folders.create({"name": "Post-sale"})
  woku.csat_tools.create({"name": "Delivery", "question": "How satisfied are you?", "folderId": folder["id"]})

  for tool in woku.tools.list({"folderId": folder["id"], "types": ["csat", "nps"]}):
      print(tool["type"], tool["name"], tool["headline"]["value"])
  stats = woku.tools.stats({"folderId": folder["id"]})
  woku.tools.move({"items": [{"type": "csat", "id": tool_id}], "folderId": None})
  csv_text = woku.folders.csv(folder["id"])
  pdf_bytes = woku.folders.pdf(folder["id"], {"lang": "en"})
  metrics = woku.folders.metrics(folder["id"], {"days": 30})  # per tool, against the previous period
  tagged = woku.tools.list({"trackers": ["TRR:00482"]})
  ```
</CodeGroup>

Full reference in the [JavaScript SDK](/docs/en/development/sdk-javascript) and the [Python SDK](/docs/en/development/sdk-python).

On the MCP server, an agent has `search_voc_tools` (with `trackers`), `get_voc_tools_stats`, `get_folder_tools_metrics`, `move_voc_tools`, `create_folder`, `update_folder`, `move_folder` and `delete_folder`. `get_folder_report` accepts `scope: "all"` for the mixed report and `format: "csv"` for the responses, and `create_nps_tool`, `create_csat_tool` and `create_ces_tool` accept `folderId`. The `organize_listening` playbook of `woku_guide` walks through the process. See [MCP tools](/docs/en/mcp/tools).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.