Files and folders live in the workspace library. A file id is digits. A folder id is a UUID. Deleted items, hidden system folders and items of other workspaces answer 404 not_found.
| Method and path | Scope | What it does |
|---|---|---|
GET /files |
files:read |
List the files and folders directly inside one folder |
GET /files/{id} |
files:read |
Read one file or folder, with its path |
GET /files/by-path |
files:read |
Read one item by path, such as /photos/2026/a.jpg |
GET /files/{id}/download |
files:read |
Get a short-lived download link |
POST /files/{id}/copy |
files:write |
Copy a file inside storage |
PATCH /files/{id} |
files:write |
Rename, move or set the modification time |
DELETE /files/{id} |
files:write |
Move to the bin |
POST /files/{id}/restore |
files:write |
Bring an item back from the bin |
List a folder
GET /files takes folder (a folder id) or path (names such as /photos/2026), not both. With neither it lists the root. Folders come first, then files, each ordered by id. limit is 1 to 1000 (default 100). Pass next_cursor back as cursor.
curl -H "Authorization: Bearer $TARKLE_TOKEN" -H "X-Workspace-Key: $KEY" \
"https://tarkle.com/api/v1/files?path=/photos/2026&limit=50"An entry has id, type (file or folder), name, size (files only), category, parent_id, created_at, updated_at, modified_at, sha256 and sha256_source (files only), etag, protected and protection_kind.
Two folders with the same name make a path ambiguous: 409 ambiguous_path. Use the id then.
List a whole tree
Add recursive=true and type=file or type=folder (type is required) to get every descendant of that type as one flat list, each with an absolute path. A sync tool can read a tree in a few calls. Hidden system folders are skipped. A folder with more than 5,000 folders below it answers 413 too_large.
Download
{ "download_url": "https://...", "expires_in": 900 }Fetch the bytes from download_url soon. Files only.
Copy
POST /files/{id}/copy with { "parent_id": "...", "name": "copy.pdf" }. parent_id null is the root and omitted is the same folder. The name defaults to the same name. A taken name is 409 name_taken (a copy never renames silently). Plan limits apply: 413 storage_full or 413 file_too_large. Folders answer 400 not_supported.
Rename and move
PATCH /files/{id} takes any of name, parent_id (a folder id or null for the root) and modified_at (files only), and at least one. Bytes never move. A taken name is 409 name_taken. A folder into itself or its own subfolder is 400 invalid_destination. System, team and active-request folders answer 403 protected.
Delete and restore
DELETE /files/{id} moves the item to the bin and answers { deleted, deleted_transfers }. If an active transfer holds the item the answer is 409 transfer_active. Repeat with ?confirm_delete_transfers=true to delete those transfers too. A Feedback board, a paid transfer with purchases, a protected folder, a file directly inside a team folder and anything inside File requests answer 403 protected.
POST /files/{id}/restore answers 410 expired past the plan’s bin retention, 409 not_deleted for an item that is not in the bin and 409 parent_unavailable when its folder is in the bin.
Every write is checked as the person the token acts as and is recorded in the workspace Activity with via: api.