Storage Files API Reference
REST API for Cosmos Storage: uploads (direct and resumable), versions, downloads, browsing, folders, moves, bulk operations, ZIP, ACLs, upload-time redaction, and metrics.
Updated 2026-11-03
Verified 2026-11-03
Storage is the Cosmos document management system (DMS). Files and folders are both items; every item has an owner, an access level, and optional per-user ACL entries. For architecture and configuration, see Storage Service.
Every endpoint except health checks requires Authorization: Bearer YOUR_TOKEN and X-Org-Id: YOUR_ORG_ID. A missing token returns 401; a missing or invalid X-Org-Id returns 400. X-Project-Id is optional and attributes the action to a project in Recent Activity. Errors use {"error": "BadRequest", "status": 400, "message": "..."}. See API Conventions.
Local base URL: http://localhost:8107. All paths below are under /api/v1/.
Endpoint Summary
| Method | Path | Purpose |
|---|---|---|
| POST | items/upload/ | Upload a file (multipart, up to 300 MB) |
| POST | items/upload-session/start | Start a resumable direct-to-cloud upload (up to 6 GiB) |
| POST | items/import-url/ | Import a file from a URL |
| GET | items/ | Browse and search items |
| GET, PATCH, DELETE | items/{id}/ | Item detail, update, delete |
| GET | items/{id}/stats/ | Folder statistics |
| GET, POST | items/{id}/versions/ | List versions; upload a new version |
| GET | items/{id}/content/ | Download content |
| POST | items/{id}/move/ | Move an item |
| POST | items/folders/ | Create a folder |
| GET | items/bulk-fetch/, items/bulk-fetch-by-path/ | Fetch many items with signed URLs |
| POST | items/bulk-access-level/ | Change access level for up to 1,000 items |
| POST | items/check-permissions/ | Check the caller's permissions on up to 100 items |
| GET, PUT, DELETE | items/{id}/acl/ | Read, replace, or clear ACL entries |
| POST | items/{id}/zip/, items/{id}/unzip/ | Background ZIP and unzip |
| POST | items/upload-redacted/, items/upload-redacted-zip/ | Upload with PII redaction |
| GET, DELETE | redaction/jobs/{id}/ | Redaction job status; cancel |
| POST | redaction/jobs/{id}/apply/ | Apply a reviewed redaction |
| GET | redaction/batch/{id}/ | ZIP redaction batch status |
| GET | metrics/ | Organization file, folder, and size totals |
| GET | /health/ | Health check (no auth, no /api/v1 prefix) |
Item Object
| Field | Description |
|---|---|
id | Item UUID |
org_id | Owning organization |
name, description | Name (up to 128 characters) and description (up to 512) |
parent_id, materialized_path, level | Position in the folder tree |
is_directory | true for folders |
size, latest_version_size | Size in bytes |
latest_version, latest_version_mime_type | Latest file version details |
owner_id | Owning user |
access_level | private, public_read, or public_write |
total_folders, total_files | Child counts for folders |
created_at, created_by, updated_at, updated_by | Audit fields |
Uploads
Direct upload
POST /api/v1/items/upload/
Content-Type: multipart/form-data
| Field | Required | Description |
|---|---|---|
file | Yes | File content (up to 300 MB) |
name | No | Item name; defaults to the file name |
parent_id or parent_path | No | Destination folder |
force_create_path | No | Create missing folders in parent_path |
force_upload_new_version | No | Add a version if an item with this name exists |
description | No | Description |
access_level | No | Default private |
owner_id | No | Superusers only |
Returns 201 with the item and a version object that includes a signed_url.
.m4a files are stored as audio/mp4. Storage checks that file content matches the declared type and rejects mismatches.
Resumable upload sessions
Large files upload directly to cloud storage, then Storage verifies and promotes them in the background.
-
Start —
POST /api/v1/items/upload-session/startjson{ "filename": "recording.mp4", "content_type": "video/mp4", "declared_size": 2147483648, "parent_path": "/Recordings", "force_create_path": true, "access_level": "private" }Optional fields:
kind(normalorredaction),name,parent_id,force_upload_new_version,description,owner_id,redaction, andtarget_item_id.declared_sizecan be up to 6 GiB.Returns
201:json{ "session_id": "SESSION_UUID", "session_token": "YOUR_SESSION_TOKEN", "status": "initiated", "kind": "normal", "upload_url": "https://...", "method": "PUT", "headers": {"...": "..."}, "protocol": "azure_block", "expires_at": "2026-11-03T12:00:00Z", "chunk_size": 8388608 }protocolisazure_block,gcs_resumable, orlocal_putdepending on the backend. -
Upload — send the bytes to
upload_urlusingmethodandheaders. CallPOST .../upload-session/{id}/uploadingwhen you begin, andPOST .../upload-session/{id}/refresh-urlif the URL expires. -
Complete —
POST /api/v1/items/upload-session/{id}/complete, optionally with{"checksum": "<sha256 hex>"}. Returns202; the checksum is verified asynchronously. -
Poll —
GET /api/v1/items/upload-session/{id}untilstatusiscompleted(orfailed,aborted,expired). Statuses move throughinitiated,uploading, andcompleting.POST .../upload-session/{id}/abortcancels it.
Import from URL
POST /api/v1/items/import-url/ with source_url and the same destination fields as a direct upload.
Versions and Downloads
| Method | Path | Description |
|---|---|---|
| GET | items/{id}/versions/ | List versions |
| POST | items/{id}/versions/ | Upload a new version (multipart file) |
| GET | items/{id}/content/?version=N | Download content; omit version for the latest |
Browse and Search
GET /api/v1/items/?parent_id=FOLDER_UUID&search=report&file_type=pdf&sort_by=updated_at&sort_order=desc&page_size=20
| Parameter | Description |
|---|---|
parent_id | Folder to list; omit for the root |
is_directory | Only folders or only files |
search | Name search |
recursive | Include descendants |
file_type | zip, pdf, docx, xls, csv, images, or others |
mime_type | One or more MIME types |
access_level, owner_id | Filters (owner_id accepts several values) |
sort_by | name, created_at, updated_at, or size |
sort_order | asc or desc |
page_size | Default 20, maximum 100 |
next_cursor | Cursor from the previous page |
{"results": [{"id": "ITEM_UUID", "name": "Q3 report.pdf", "is_directory": false, "...": "..."}], "next_cursor": "...", "page_size": 20}
Results only include items the caller can view.
Item Operations
| Method | Path | Body or parameters |
|---|---|---|
| GET | items/{id}/ | — |
| PATCH | items/{id}/ | name, description, access_level, owner_id, applies_to_children |
| DELETE | items/{id}/ | Soft delete; ?force=true deletes a non-empty folder |
| GET | items/{id}/stats/ | Folder statistics |
| POST | items/{id}/move/ | {"new_parent_id": "FOLDER_UUID"} |
| POST | items/folders/ | name (1–128 characters), parent_id, description, access_level, owner_id |
Bulk Operations
Bulk fetch. GET /api/v1/items/bulk-fetch/?item=UUID&item=UUID:2 returns items with signed URLs; append :version to pin a version. GET /api/v1/items/bulk-fetch-by-path/?item=/Reports/q3.pdf does the same by path. Items the caller cannot view are skipped. Administrators can set signed_url_expiry_minutes.
Bulk access level.
POST /api/v1/items/bulk-access-level/
{"items": [{"item_id": "ITEM_UUID", "access_level": "public_read", "update_children": true}]}
Up to 1,000 items. Returns {"updated_count": 1, "failed_items": []}.
Permission check.
POST /api/v1/items/check-permissions/
{"item_ids": ["ITEM_UUID_1", "ITEM_UUID_2"]}
Up to 100 IDs. Returns one permission object per item (view, update, delete, manage ACL). The frontend uses this to decide which actions to show; results are cached for 5 minutes.
Access Control
Each ACL entry grants or denies one user specific actions on an item. A user has at most one allow and one deny entry per item. allow is evaluated before deny, and RBAC *_all permissions bypass deny entries.
PUT /api/v1/items/{id}/acl/
{
"acls": [
{
"user_id": "USER_UUID",
"effect": "allow",
"can_view": true,
"can_update": true,
"can_delete": false,
"can_manage_acl": false,
"applies_to_children": true
}
]
}
PUT replaces the item's entries and returns {"success": true, "message": "...", "affected_count": 1, "acls": [...]}. GET returns the current entries; DELETE removes them.
ZIP and Unzip
POST /api/v1/items/{id}/zip/ archives a folder and POST /api/v1/items/{id}/unzip/ extracts a ZIP file. Both return 202 Accepted and run in the background. Only items the caller can view are included, and the archive type is validated before extraction.
Upload-Time Redaction
Storage can remove PII from documents and images as they are uploaded.
| Method | Path | Description |
|---|---|---|
| POST | items/upload-redacted/ | Multipart file plus config (JSON), redaction_mode (native or azure), and use_org_default. Returns 202 with a job. |
| POST | items/upload-redacted-zip/ | Redact every supported file in a ZIP. Returns 202 with a batch. |
| GET | redaction/jobs/{id}/ | Job status and results |
| POST | redaction/jobs/{id}/apply/ | Apply a reviewed redaction. Returns 202. |
| DELETE | redaction/jobs/{id}/ | Cancel a job |
| GET | redaction/batch/{id}/ | ZIP batch status |
Large uploads can also be redacted through an upload session with "kind": "redaction".
Metrics
GET /api/v1/metrics/
{"org_id": "YOUR_ORG_ID", "total_files": 1280, "total_folders": 96, "total_size": 73400320}
Limits
| Limit | Value |
|---|---|
Direct upload (items/upload/) | 300 MB |
| Resumable upload session | 6 GiB |
| ZIP redaction | 300 MB per entry; 10 times that in total |
| Azure document PII analysis | 10 MB per request; larger PDFs are split into parts of about 8 MB |
| Bulk access-level update | 1,000 items |
| Permission check | 100 items |
| Browse page size | 100 |
Testing
curl -s -X POST http://localhost:8107/api/v1/items/upload/ \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Org-Id: YOUR_ORG_ID" \
-F "file=@./report.pdf" \
-F "parent_path=/Reports" \
-F "force_create_path=true"
curl -s "http://localhost:8107/api/v1/items/?search=report" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Org-Id: YOUR_ORG_ID"