Skip to content

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/422 otherwise).

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 & pathWhat it doesRequired scope
POST /foldersCreate a folderfolders:write
GET /foldersList folders (or Trash)folders:read
PATCH /folders/{id}Rename and/or movefolders:write
DELETE /folders/{id}Trash a folder (recursive)folders:write
POST /folders/{id}/restoreRestore from Trash (recursive)folders:write
GET /folders/{id}/statsRecursive file count + total bytesfolders: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:

json
{
  "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"
}
FieldTypeNotes
idUUID stringThe folder id.
tenant_idUUID stringYour tenant.
space_idUUID stringThe Space this folder lives in.
parent_idUUID string or nullParent folder; null means the space root.
namestringThe folder name (path-component-validated).
deleted_atISO-8601 UTC or nullNon-null while the folder is in Trash.
created_atISO-8601 UTCWhen the folder was created.
updated_atISO-8601 UTCLast modification.

Create a folder

POST /folders — scope folders:write

Create a folder inside a Space, optionally under a parent folder.

Request body

FieldTypeRequiredNotes
namestringyesValidated as a path component (no /, no ..).
space_idUUID stringyesThe Space to create the folder in.
parent_idUUID stringnoParent folder. Omit / null for the space root. The parent must be in the same Space (else 400).

Responses

  • 201 — the new FolderOut.
  • 400parent_id is in a different Space.
  • 404space_id / parent_id not found (or not yours).
  • 422 — invalid name.

curl

bash
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

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

ts
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

ParamTypeDefaultNotes
space_idUUID stringRequired for normal browsing. Omit only with trash=true.
parent_idUUID stringnullScope to children of this folder. null (omitted) lists the space root (folders with no parent). Ignored when trash=true.
trashbooleanfalseList 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_id is required unless trash=true; omitting it for normal browsing returns 422.
  • Trash is universal. With trash=true you may omit space_id to 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, …, 10 order as numbers, not as strings (1, 10, 2).

Responses

  • 200 — a JSON array of FolderOut.
  • 422space_id missing for non-trash browsing.

curl

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

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

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

FieldTypeNotes
namestringNew name (re-validated as a path component).
parent_idUUID string or nullNew 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 updated FolderOut.
  • 400 — self-parent, cycle, or cross-Space move.
  • 404 — folder or new parent not found (or not yours).
  • 422 — invalid name.

curl

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

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

ts
// 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 trashed FolderOut (its deleted_at is now set).
  • 404 — folder not found (or not yours).

curl

bash
curl -X DELETE https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12 \
  -H "X-API-Key: fck_live_..."

Python

python
fc.folders.delete(folder_id)

TypeScript

ts
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 restored FolderOut (its deleted_at is back to null; its parent_id may have changed to null if re-homed).
  • 404 — folder not found (or not yours).

curl

bash
curl -X POST https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12/restore \
  -H "X-API-Key: fck_live_..."

Python

python
restored = fc.folders.restore(folder_id)
print(restored.parent_id)  # may be None if re-homed to the space root

TypeScript

ts
const restored = await fc.folders.restore(folderId);
console.log(restored.parentId); // may be null if re-homed to the space root

Folder 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

FieldTypeNotes
folder_idUUID stringThe folder you inspected.
file_countintegerNumber of live files in the subtree.
total_bytesintegerSum of those files' sizes, in bytes.
json
{
  "folder_id": "0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12",
  "file_count": 42,
  "total_bytes": 1048576
}

Responses

  • 200 — a FolderStats object.
  • 404 — folder not found (or not yours).

curl

bash
curl "https://api-cloud.fluidvip.com/api/v1/folders/0b6e1a2c-9f3d-4c7a-8b1e-2d4f6a8c0e12/stats" \
  -H "X-API-Key: fck_live_..."

Python

python
stats = fc.folders.stats(folder_id)
print(stats.file_count, stats.total_bytes)

TypeScript

ts
const stats = await fc.folders.stats(folderId);
console.log(stats.fileCount, stats.totalBytes);

total_bytes is 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:

StatusWhenSDK error
400Bad move — cross-Space parent, self-parent, or a cycle.ApiError
401Missing / invalid / revoked API key.AuthError
403insufficient_scope (key lacks a needed scope) or feature_not_in_plan (subscription doesn't include API access).PermissionError
404Folder, parent, or space not found — or it belongs to another tenant.NotFoundError
422Invalid folder name, or space_id missing on a non-trash list.ApiError
429Rate 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.


  • Spaces — folders always live in a Space.
  • Files — the files that live inside folders (and client_key resolution).
  • 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.

FluidCloud API — part of the Fluidvip ecosystem.