API Reference — Folders
Folders are the tree you organize files into inside a Space. A folder lives in exactly one Space, may have a parent folder (or sit at the space root), and can be renamed, moved, trashed (recursively), and restored. Use folders to mirror your own app's structure — for example one folder per job, per customer, or per pipeline stage.
All routes are under the base https://api-cloud.fluidvip.com/api/v1 and the /folders prefix. Every request authenticates with your API key in the X-API-Key header (see Authentication). The SDKs add the header for you.
- Folder ids are UUID strings; timestamps are ISO-8601 UTC.
- Every query is tenant-isolated. Ids that belong to another tenant return 404, never 403 — so a 404 means "not found or not yours".
- Folder names are validated on create and rename: a name can never contain a path separator or traversal sequence (
400/422otherwise).
Not available to API keys: per-folder access grants (
/folders/{id}/grants) require an interactive workspace-manager role and are not exposed to API keys. The seven endpoints below are everything a partner key can call on/folders.
| Method & path | What it does | Required scope |
|---|---|---|
POST /folders | Create a folder | folders:write |
GET /folders | List folders (or Trash) | folders:read |
PATCH /folders/{id} | Rename and/or move | folders:write |
DELETE /folders/{id} | Trash a folder (recursive) | folders:write |
POST /folders/{id}/restore | Restore from Trash (recursive) | folders:write |
GET /folders/{id}/stats | Recursive file count + total bytes | folders:read |
Scopes use AND semantics — your key carries the full partner scope set, so each of these is authorized. See Authentication for the complete list.
The FolderOut object
Every create/list/update/delete/restore response is one (or a list of) folder object:
{
"id": "0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12",
"tenant_id": "bb4da085-1d97-4780-9a2b-707c8b1b0001",
"space_id": "707c8b1b-aaaa-bbbb-cccc-1234567890ab",
"parent_id": null,
"name": "results",
"deleted_at": null,
"created_at": "2026-06-23T10:15:00Z",
"updated_at": "2026-06-23T10:15:00Z"
}| Field | Type | Notes |
|---|---|---|
id | UUID string | The folder id. |
tenant_id | UUID string | Your tenant. |
space_id | UUID string | The Space this folder lives in. |
parent_id | UUID string or null | Parent folder; null means the space root. |
name | string | The folder name (path-component-validated). |
deleted_at | ISO-8601 UTC or null | Non-null while the folder is in Trash. |
created_at | ISO-8601 UTC | When the folder was created. |
updated_at | ISO-8601 UTC | Last modification. |
Create a folder
POST /folders — scope folders:write
Create a folder inside a Space, optionally under a parent folder.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Validated as a path component (no /, no ..). |
space_id | UUID string | yes | The Space to create the folder in. |
parent_id | UUID string | no | Parent folder. Omit / null for the space root. The parent must be in the same Space (else 400). |
Responses
201— the newFolderOut.400—parent_idis in a different Space.404—space_id/parent_idnot found (or not yours).422— invalid name.
curl
curl -X POST https://api-cloud.fluidvip.com/api/v1/folders \
-H "X-API-Key: fck_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "job-7",
"space_id": "707c8b1b-aaaa-bbbb-cccc-1234567890ab",
"parent_id": null
}'Python
from fluidcloud import FluidCloud
fc = FluidCloud(api_key="fck_live_...")
folder = fc.folders.create(
name="job-7",
space_id="707c8b1b-aaaa-bbbb-cccc-1234567890ab",
parent_id=None,
)
print(folder.id)TypeScript
import { FluidCloud } from "fluidcloud";
const fc = new FluidCloud({ apiKey: "fck_live_..." });
const folder = await fc.folders.create({
name: "job-7",
spaceId: "707c8b1b-aaaa-bbbb-cccc-1234567890ab",
parentId: null,
});
console.log(folder.id);List folders
GET /folders — scope folders:read
List folders in one scope — a given parent, or the space root — or list Trash.
Query parameters
| Param | Type | Default | Notes |
|---|---|---|---|
space_id | UUID string | — | Required for normal browsing. Omit only with trash=true. |
parent_id | UUID string | null | Scope to children of this folder. null (omitted) lists the space root (folders with no parent). Ignored when trash=true. |
trash | boolean | false | List soft-deleted folders instead of live ones. |
Notes:
- Normal browsing is per-Space and flat — it returns the folders directly in the requested scope (the space root, or one parent's immediate children), not the whole subtree. Walk the tree by calling again with each child's id as
parent_id. space_idis required unlesstrash=true; omitting it for normal browsing returns422.- Trash is universal. With
trash=trueyou may omitspace_idto get soft-deleted folders across all your Spaces. Trash lists only the roots of trashed subtrees (the folders you actually deleted); their nested trashed descendants are not listed individually because they restore/purge together with their root. - Results are naturally sorted by name, so
1, 2, …, 10order as numbers, not as strings (1, 10, 2).
Responses
200— a JSON array ofFolderOut.422—space_idmissing for non-trash browsing.
curl
# Folders at the space root
curl "https://api-cloud.fluidvip.com/api/v1/folders?space_id=707c8b1b-aaaa-bbbb-cccc-1234567890ab" \
-H "X-API-Key: fck_live_..."
# Children of a specific folder
curl "https://api-cloud.fluidvip.com/api/v1/folders?space_id=707c8b1b-aaaa-bbbb-cccc-1234567890ab&parent_id=0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12" \
-H "X-API-Key: fck_live_..."
# Universal Trash (space_id omitted)
curl "https://api-cloud.fluidvip.com/api/v1/folders?trash=true" \
-H "X-API-Key: fck_live_..."Python
# Space root
roots = fc.folders.list(space_id="707c8b1b-aaaa-bbbb-cccc-1234567890ab")
# Children of one folder
children = fc.folders.list(
space_id="707c8b1b-aaaa-bbbb-cccc-1234567890ab",
parent_id="0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12",
)
# Universal Trash
trashed = fc.folders.list(trash=True)TypeScript
// Space root
const roots = await fc.folders.list({
spaceId: "707c8b1b-aaaa-bbbb-cccc-1234567890ab",
});
// Children of one folder
const children = await fc.folders.list({
spaceId: "707c8b1b-aaaa-bbbb-cccc-1234567890ab",
parentId: "0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12",
});
// Universal Trash
const trashed = await fc.folders.list({ trash: true });Rename and/or move a folder
PATCH /folders/{folder_id} — scope folders:write
Send name to rename, parent_id to move, or both in one call. Fields you omit are left unchanged.
Path parameter: folder_id (UUID string).
Request body
| Field | Type | Notes |
|---|---|---|
name | string | New name (re-validated as a path component). |
parent_id | UUID string or null | New parent. null moves the folder to the space root. Only treated as a move when the field is present in the body — omit it to leave the folder where it is. The new parent must be in the same Space. |
Move guards:
- A folder cannot be its own parent (
400). - A folder cannot be moved into its own descendant — that would create a cycle (
400). - The new parent must be in the same Space as the folder (
400).
Responses
200— the updatedFolderOut.400— self-parent, cycle, or cross-Space move.404— folder or new parent not found (or not yours).422— invalid name.
curl
# Rename
curl -X PATCH https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12 \
-H "X-API-Key: fck_live_..." \
-H "Content-Type: application/json" \
-d '{"name": "job-7-final"}'
# Move to the space root
curl -X PATCH https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12 \
-H "X-API-Key: fck_live_..." \
-H "Content-Type: application/json" \
-d '{"parent_id": null}'Python
# Rename
fc.folders.update(folder_id, name="job-7-final")
# Move under another folder
fc.folders.update(folder_id, parent_id="1f7c0e44-2b3a-4d5e-9a6b-7c8d9e0f1a2b")
# Move to the space root
fc.folders.update(folder_id, parent_id=None)TypeScript
// Rename
await fc.folders.update(folderId, { name: "job-7-final" });
// Move under another folder
await fc.folders.update(folderId, {
parentId: "1f7c0e44-2b3a-4d5e-9a6b-7c8d9e0f1a2b",
});
// Move to the space root
await fc.folders.update(folderId, { parentId: null });Trash a folder (recursive)
DELETE /folders/{folder_id} — scope folders:write
Moves the folder to Trash recursively: it soft-deletes the folder, all of its subfolders, and every file inside it, so nothing is left hidden-but-stored. The whole subtree is trashed under one shared timestamp, which tags it as a batch so a later restore brings back exactly these items.
This is reversible — trashed folders show up in the Trash listing (GET /folders?trash=true) and can be restored. Trashing does not free your storage quota; the bytes are released only when Trash is emptied / purged. See Deleting data and the Deletion reference for purge.
Path parameter: folder_id (UUID string).
Responses
200— the trashedFolderOut(itsdeleted_atis now set).404— folder not found (or not yours).
curl
curl -X DELETE https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12 \
-H "X-API-Key: fck_live_..."Python
fc.folders.delete(folder_id)TypeScript
await fc.folders.delete(folderId);Restore a folder (recursive)
POST /folders/{folder_id}/restore — scope folders:write
Restores the folder and everything that was trashed with it in the same cascade (matched by the shared delete timestamp). Items you had trashed separately inside it stay in Trash. If the folder's original parent is gone or still trashed, the folder is re-homed to the space root so it can't end up live-but-unreachable. Quota is untouched (the bytes were never released on trash).
Path parameter: folder_id (UUID string) — a folder currently in Trash.
Responses
200— the restoredFolderOut(itsdeleted_atis back tonull; itsparent_idmay have changed tonullif re-homed).404— folder not found (or not yours).
curl
curl -X POST https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12/restore \
-H "X-API-Key: fck_live_..."Python
restored = fc.folders.restore(folder_id)
print(restored.parent_id) # may be None if re-homed to the space rootTypeScript
const restored = await fc.folders.restore(folderId);
console.log(restored.parentId); // may be null if re-homed to the space rootFolder stats
GET /folders/{folder_id}/stats — scope folders:read
Returns the recursive contents of a folder — the file count and total size across its whole live subtree (recursing into subfolders), excluding anything in Trash. Useful for showing per-folder usage in your own UI without listing every file.
Path parameter: folder_id (UUID string).
FolderStats object
| Field | Type | Notes |
|---|---|---|
folder_id | UUID string | The folder you inspected. |
file_count | integer | Number of live files in the subtree. |
total_bytes | integer | Sum of those files' sizes, in bytes. |
{
"folder_id": "0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12",
"file_count": 42,
"total_bytes": 1048576
}Responses
200— aFolderStatsobject.404— folder not found (or not yours).
curl
curl "https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12/stats" \
-H "X-API-Key: fck_live_..."Python
stats = fc.folders.stats(folder_id)
print(stats.file_count, stats.total_bytes)TypeScript
const stats = await fc.folders.stats(folderId);
console.log(stats.fileCount, stats.totalBytes);
total_bytesis the live subtree size of one folder. For tenant-wide storage and limits, read the Quota endpoint instead.
Errors
These endpoints use the standard error model: an HTTP status with a JSON body whose top key is detail. The cases you'll hit on /folders:
| Status | When | SDK error |
|---|---|---|
400 | Bad move — cross-Space parent, self-parent, or a cycle. | ApiError |
401 | Missing / invalid / revoked API key. | AuthError |
403 | insufficient_scope (key lacks a needed scope) or feature_not_in_plan (subscription doesn't include API access). | PermissionError |
404 | Folder, parent, or space not found — or it belongs to another tenant. | NotFoundError |
422 | Invalid folder name, or space_id missing on a non-trash list. | ApiError |
429 | Rate limited (default 600 req/min per key). A Retry-After header tells you when to retry. | ApiError |
See Errors and Rate limits for the full model.
Related
- Spaces — folders always live in a Space.
- Files — the files that live inside folders (and
client_keyresolution). - Uploads — put bytes into a folder.
- Organizing files — a task-oriented walkthrough of building and navigating the folder tree.
- Deletion — purge / empty Trash to actually free storage.
- Quota — tenant-wide storage and share-link usage.
- Reference index — all endpoints at a glance.