Skip to Content
ConnectFiles API

Files API

The Files API provides upload, metadata management, folder organization, and asset serving backed by Supabase Storage.

Endpoints

GET /api/files → 200 — list files POST /api/files → 201 — upload a file (multipart) or create metadata (JSON) GET /api/files/:id → 200 — get file metadata PATCH /api/files/:id → 200 — update file metadata or replace file (multipart) DELETE /api/files/:id → 204 — delete a file PATCH /api/files → 200 — batch update DELETE /api/files → 204 — batch delete POST /api/files/import → 200 — import from URL GET /api/files/:id/download → 200 — get download URL GET /api/assets/:id → 200 — serve file asset (public URL) GET /api/folders → 200 — list folders POST /api/folders → 201 — create folder PATCH /api/folders/:id → 200 — update folder DELETE /api/folders/:id → 204 — delete folder

File Object

The File entity has the following fields. Fields marked * are always returned; others are null when not applicable.

FieldTypeDescription
id *stringUnique identifier (UUID)
storage *stringStorage bucket name (default: "files")
filename_diskstring | nullFilename as stored on disk
filename_download *stringOriginal filename for downloads
titlestring | nullDisplay title
typestring | nullMIME type
filesize *numberFile size in bytes (0 for metadata-only records)
widthnumber | nullImage width in pixels (not computed by server — set client-side)
heightnumber | nullImage height in pixels (not computed by server — set client-side)
durationnumber | nullDuration in seconds (video/audio)
charsetstring | nullCharacter encoding for text files
folderstring | nullParent folder ID
descriptionstring | nullDescription of the file
locationstring | nullLocation metadata
tagsstring[]Array of tags
metadataobjectArbitrary JSON metadata (EXIF, etc.)
embedstring | nullEmbed code/URL for external media
focal_point_xnumber | nullFocal point X coordinate for cropping
focal_point_ynumber | nullFocal point Y coordinate for cropping
tus_idstring | nullTUS resumable upload identifier
tus_dataobject | nullTUS upload data
uploaded_bystring | nullUser who uploaded the file
uploaded_onstring | nullUpload timestamp
created_on *stringRecord creation timestamp
modified_bystring | nullUser who last modified the file
modified_on *stringLast modification timestamp

Upload a File

Multipart Upload

Send a multipart/form-data request with the file binary and optional metadata:

curl -X POST https://your-domain.com/api/files \ -H "Authorization: Bearer <token>" \ -F "file=@/path/to/image.png" \ -F "title=My Image" \ -F "description=A sample image" \ -F "folder=<folder_id>" \ -F "storage=files"
Form fieldRequiredDescription
fileYes (multipart)The file binary
titleNoDisplay title
descriptionNoDescription text
folderNoParent folder ID
storageNoStorage bucket name (default: "files")

Response (201):

{ "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "storage": "files", "filename_disk": "550e8400-e29b-41d4-a716-446655440000.png", "filename_download": "image.png", "title": "My Image", "description": "A sample image", "type": "image/png", "filesize": 204800, "width": null, "height": null, "folder": null, "tags": [], "metadata": {}, "uploaded_by": "<user_id>", "uploaded_on": "2024-01-15T10:30:00Z", "created_on": "2024-01-15T10:30:00Z", "modified_on": "2024-01-15T10:30:00Z" } }

width and height are not computed by the server. They will be null unless the client provides them on upload or updates them later via PATCH.

Upload Constraints

ConstraintDefaultEnv Variable
Maximum upload size100 MBFILES_MAX_UPLOAD_SIZE (bytes)
Allowed MIME typesAll types allowedFILES_MIME_TYPE_ALLOW_LIST (comma-separated, e.g. image/png,image/jpeg)

Uploads exceeding FILES_MAX_UPLOAD_SIZE or with a MIME type not in FILES_MIME_TYPE_ALLOW_LIST will be rejected with a 400 error.

JSON Mode (Metadata-Only)

Create a file record without uploading binary content. Useful for tracking external assets or placeholder entries:

curl -X POST https://your-domain.com/api/files \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "type": "image/png", "filename_download": "external-asset.png", "title": "External Asset", "storage": "files" }'

The type and filename_download fields are required in JSON mode. The response has the same shape as the multipart upload, with filesize: 0.

List Files

GET /api/files supports the following query parameters for filtering, sorting, and pagination:

ParamTypeDescription
limitnumberMaximum number of items to return
offsetnumberNumber of items to skip (for cursor-based pagination)
pagenumberPage number (alternative to offset)
searchstringFree-text search across title and filename
sortstringSort field(s), comma-separated. Prefix with - for descending (e.g. -uploaded_on)
fieldsstringComma-separated list of fields to return (e.g. id,title,filesize)
filterstring (JSON)JSON-encoded filter object (e.g. {"folder":{"_eq":"<id>"}})
metastringSet to filter_count to include metadata in the response

Example — list with pagination and metadata:

GET /api/files?limit=10&offset=0&meta=filter_count&sort=-uploaded_on

Response (200):

{ "data": [ { "id": "...", "title": "Image 1", "filesize": 204800, "..." }, { "id": "...", "title": "Image 2", "filesize": 102400, "..." } ], "meta": { "filter_count": 10, "total_count": 42 } }

When meta=filter_count is not passed, the meta key is omitted from the response.

Get File Metadata

Retrieve a single file’s metadata by ID:

GET /api/files/:id
ParamTypeDescription
fieldsstringComma-separated list of fields to return
metastringSet to filter_count to include count metadata

Response (200):

{ "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "title": "My Image", "filename_download": "image.png", "type": "image/png", "filesize": 204800, "width": null, "height": null, "folder": null, "uploaded_by": "<user_id>", "uploaded_on": "2024-01-15T10:30:00Z" } }

Update File Metadata

JSON Body Update

Update metadata fields via JSON:

curl -X PATCH https://your-domain.com/api/files/<id> \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"title": "Updated Title", "description": "A better description", "tags": ["hero", "blog"]}'

Response (200):

{ "data": { "id": "<id>", "title": "Updated Title", "description": "A better description", "tags": ["hero", "blog"], "...": "..." } }

Multipart File Replacement

Replace the file binary for an existing file record using multipart form data:

curl -X PATCH https://your-domain.com/api/files/<id> \ -H "Authorization: Bearer <token>" \ -F "file=@/path/to/new-version.png"

The response has the same shape as the JSON update. The old file binary is replaced in storage; the file record’s filesize, type, and filename_download are updated automatically from the new file.

Delete a File

curl -X DELETE https://your-domain.com/api/files/<id> \ -H "Authorization: Bearer <token>"

Returns 204 No Content on success.

Serving Files

Use the asset endpoint to serve file content. The response is raw binary (not JSON) with appropriate Content-Type and Content-Disposition headers — suitable for <img src>, <video src>, or direct download links.

GET /api/assets/:id
Query paramDescription
downloadForces a file download (Content-Disposition: attachment)
widthResize image to this width (Supabase Pro plans only)
heightResize image to this height (Supabase Pro plans only)

Assets are served with Cache-Control: public, max-age=31536000 (1 year). Updated files may not reflect immediately in all clients due to aggressive caching.

<img src="https://your-domain.com/api/assets/550e8400-e29b-41d4-a716-446655440000" alt="My Image" <!-- Authorization header must be set via fetch/XHR for protected assets --> />

All asset requests require a valid Authorization header. There is no unauthenticated asset serving — grant the requesting user’s policy read access on daas_files to allow access.

Download File

Get a signed download URL for a file. The response is JSON containing a temporary URL, not the file content itself.

GET /api/files/:id/download
Query paramTypeDefaultDescription
expires_innumber3600URL expiration time in seconds

Response (200):

{ "url": "https://<project>.supabase.co/storage/v1/object/sign/files/<filename_disk>?token=...", "expires_in": 3600 }

Import from URL

Download a remote file and store it in Supabase Storage:

curl -X POST https://your-domain.com/api/files/import \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com/image.jpg", "data": {"title": "Imported Image"}}'

Returns 200 with the imported file data:

{ "data": { "id": "550e8400-...", "filename_download": "image.jpg", "title": "Imported Image", "...": "..." } }

Folder Organization

Files can be organized into hierarchical folders.

Create a Folder

curl -X POST https://your-domain.com/api/folders \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"name": "Blog Images", "parent": null}'

Response (201):

{ "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Blog Images", "parent": null, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } }

List Folders

GET /api/folders

Response (200):

{ "data": [ { "id": "550e8400-...", "name": "Blog Images", "parent": null, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ], "meta": { "filter_count": 1, "total_count": 1 } }

Update a Folder

curl -X PATCH https://your-domain.com/api/folders/<id> \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"name": "Renamed Folder"}'

Response (200):

{ "data": { "id": "550e8400-...", "name": "Renamed Folder", "parent": null, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T11:00:00Z" } }

Setting a folder as its own parent (PATCH /api/folders/:id with "parent": "<same_id>") is rejected with a 400 error: A folder cannot be its own parent.

Delete a Folder

curl -X DELETE https://your-domain.com/api/folders/<id> \ -H "Authorization: Bearer <token>"

Returns 204 No Content on success.

A folder with subfolders or containing files cannot be deleted. Attempting to delete a non-empty folder returns a 400 error with code FOLDER_NOT_EMPTY. Delete all files and subfolders first.

Upload into a Folder

curl -X POST https://your-domain.com/api/files \ -H "Authorization: Bearer <token>" \ -F "file=@hero.jpg" \ -F "folder=<folder_id>"

Batch Operations

Batch Update

Update metadata for multiple files in a single request. Two formats are supported:

Keys format — apply the same update to multiple files:

curl -X PATCH https://your-domain.com/api/files \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"keys": ["id-1", "id-2", "id-3"], "data": {"title": "Bulk Updated"}}'

Array format — apply per-file updates:

curl -X PATCH https://your-domain.com/api/files \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '[ {"id": "id-1", "title": "New Title A"}, {"id": "id-2", "title": "New Title B", "description": "Updated desc"} ]'

Returns 200 with the updated file data.

Batch Delete

Batch delete accepts a JSON body with an array of file IDs (or an object with a keys array):

# Batch delete by ID list curl -X DELETE https://your-domain.com/api/files \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '["id-1", "id-2", "id-3"]' # Alternative: keys object curl -X DELETE https://your-domain.com/api/files \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"keys": ["id-1", "id-2"]}'

Returns 204 No Content.

Last updated on