API Reference: Files
Upload trusted files, retrieve metadata, generate presigned download URLs, and access image variants.
Overview
The Files API manages the team's media library: trusted uploads, file metadata, folders, presigned download URLs, image variants, version history, and storage usage. Files are stored in S3 and referenced from data records through file and image fields. Media-library management endpoints remain privileged tier. The upload-intent endpoints under /v1/file-uploads are standard tier. API keys require edit-qualified TEAM_ADMIN_MEDIA_LIBRARY permission; OAuth and delegated sessions require both that permission and files:write. Signed-in first-party webapp Team Users retain the existing ability to add root-level attachments to forms and conversations, but their bytes now pass through the same trust boundary. Targeting a media-library folder or replacing an existing file requires edit-qualified TEAM_ADMIN_MEDIA_LIBRARY permission for every caller.
Key Concepts
- File metadata — Each file has a
fileSimplyId,filename,fileType(e.g.IMAGE),mimeType,fileSizeBytes, optional image dimensions,altText, folder placement, andcurrentVersionNumber. - Presigned download URLs — Time-limited URLs that grant temporary direct access to the underlying S3 object.
- Image variants — Image files generate resized variants (for example
THUMBNAIL_IMAGE,WEB_SIZE_IMAGE, andRESPONSIVE_320throughRESPONSIVE_1920) for optimized delivery. - Folders — Files can be organized into nested media-library folders, each with its own
fileFolderSimplyId. - Trusted uploads — New bytes first enter a private, versioned quarantine bucket. Simply360 binds the declaration to the exact S3 object version, waits for GuardDuty Malware Protection, validates the file signature, sanitizes SVG, and promotes only a
NO_THREATS_FOUNDresult.
List Files
GET /v1/files lists media-library files with paging (page, pageSize) and filters: fileType, fileFolderSimplyId (use null for the root folder), search, labelSimplyIds, sortBy, sortOrder, and includeDeleted.
const files = await s360.files.list({ fileType: 'IMAGE', search: 'logo', pageSize: 25 });
curl -s "https://api.simply360.app/v1/files?fileType=IMAGE&search=logo" \
-H "Authorization: Bearer $S360_API_KEY"
Get File Metadata
Returns the file's metadata plus a presigned originalUrl (and thumbnailUrl for images).
TypeScript SDK
const file = await s360.files.get('FILE-1234-ABCD');
console.log(`Name: ${file.data.filename}`);
console.log(`Type: ${file.data.mimeType}`);
console.log(`Size: ${file.data.fileSizeBytes} bytes`);
cURL
curl -s "https://api.simply360.app/v1/files/FILE-1234-ABCD" \
-H "Authorization: Bearer $S360_API_KEY"
Get Download URL
Generate a presigned download URL. The original file URL is valid for one hour (expiresIn: 3600); pass variantType (for example THUMBNAIL_IMAGE or WEB_SIZE_IMAGE) to download a variant instead (five-minute expiry). Do not cache these URLs long-term.
TypeScript SDK
const download = await s360.files.getDownloadUrl('FILE-1234-ABCD');
console.log(`URL: ${download.data.url}`);
console.log(`Expires: ${download.data.expiresAt}`);
// Variant download
const thumb = await s360.files.getDownloadUrl('FILE-1234-ABCD', { variantType: 'THUMBNAIL_IMAGE' });
cURL
curl -s "https://api.simply360.app/v1/files/FILE-1234-ABCD/download" \
-H "Authorization: Bearer $S360_API_KEY"
Need many URLs at once? POST /v1/files/download-urls (SDK: getDownloadUrls) returns presigned URLs for a batch of files.
Image Variants
List a file's generated variants with getVariants. Each entry has a fileVariantSimplyId, variantType, and format; fetch a variant's bytes through the download endpoint with variantType.
const variants = await s360.files.getVariants('FILE-1234-ABCD');
for (const variant of variants.data) {
console.log(`${variant.variantType} (${variant.format})`);
}
curl -s "https://api.simply360.app/v1/files/FILE-1234-ABCD/variants" \
-H "Authorization: Bearer $S360_API_KEY"
If variants are missing or stale, queue regeneration with POST /v1/files/{fileSimplyId}/variants/regenerate (images only).
Update, Move, and Delete
// Update metadata (PATCH /v1/files/{fileSimplyId})
await s360.files.update('FILE-1234-ABCD', { altText: 'Team photo at the gala' });
// Move to a folder (PUT /v1/files/{fileSimplyId}/folder)
await s360.files.moveToFolder('FILE-1234-ABCD', { fileFolderSimplyId: 'FLDR-1234-ABCD' });
// Soft-delete (DELETE /v1/files/{fileSimplyId})
await s360.files.delete('FILE-1234-ABCD');
Deletes are soft by default: the file is flagged deleted and hidden from listings, but the S3 object remains. Passing { "force": true } in the DELETE body permanently destroys the row. POST /v1/files/bulk-delete deletes many files in one call.
Folders
| Endpoint | Description |
|---|---|
GET /v1/files/folders | List folders (optionally by parentFileFolderSimplyId). |
POST /v1/files/folders | Create a folder. |
PATCH /v1/files/folders/{fileFolderSimplyId} | Rename / update a folder. |
DELETE /v1/files/folders/{fileFolderSimplyId} | Delete an empty folder. |
Versions and Storage
GET /v1/files/{fileSimplyId}/versions— current and historical version metadata.GET /v1/files/{fileSimplyId}/versions/{versionNumber}/download— presigned URL for a specific version.GET /v1/files/storage-usage— the team's media-library storage usage.
Uploads
The TypeScript SDK owns the full upload handshake. It hashes the exact bytes, creates a constrained intent, submits the signed form directly to private quarantine, and polls until scanning and promotion reach a terminal state:
const file = new File([bytes], 'report.pdf', { type: 'application/pdf' });
const uploaded = await s360.files.upload({ file, filename: file.name });
console.log(uploaded.data.fileSimplyId); // public File Simply ID
console.log(uploaded.data.versionNumber);
To replace an existing file without changing its public ID, pass isNewVersionOfFileSimplyId. The server records the expected current version when the intent is created and fails closed if another replacement wins first.
await s360.files.upload({
file,
filename: file.name,
isNewVersionOfFileSimplyId: 'FILE-1234-ABCD',
});
Raw HTTP Flow
POST /v1/file-uploadswithfilename, exact allowlistedcontentType,fileSizeBytes, and the base64 SHA-256 digest inchecksumSha256. Optional fields arefileFolderSimplyIdandisNewVersionOfFileSimplyId.- Submit every returned
upload.fieldsvalue and then the file part toupload.urlasmultipart/form-data. The signed POST expires after ten minutes and constrains the key, size, type, checksum, upload ID, and team ID. Do not change or omit fields. - Call
POST /v1/file-uploads/{fileUploadSimplyId}/complete. A202response means scanning or promotion is still pending; poll that endpoint untilCOMPLETED,REJECTED, orEXPIRED.GET /v1/file-uploads/{fileUploadSimplyId}reads the same durable status without returning storage coordinates.
Upload intents are bound to the creating credential and selected team. Promotion uses a renewable single-owner lease, a unique permanent key per lease, a database version check, and a fresh storage-limit check serialized per Team, so retries and concurrent uploads remain idempotent. Unscanned, unsupported, access-denied, failed, timed-out, signature-mismatched, checksum-mismatched, or malware-positive objects are never promoted. Quarantine is private and lifecycle-expired; permanent object metadata preserves the original/content checksums and GuardDuty result. Supported formats are deliberately allowlisted, generic application/octet-stream and HTML are rejected, Office Open XML packages are inspected rather than accepted as arbitrary ZIP files, and ISO base-media types must carry a compatible declared brand. Text, CSV, JSON, XML, and SVG receive full-content inspection and are capped at 10 MiB; JSON must parse, SVG is sanitized before storage, and the general binary upload maximum is 500 MiB.
POST /v1/files/batch and POST /v1/files/temp-cleanup remain compatibility endpoints for older Simply360-created temporary objects. They are not the public upload entry point and must not be used to accept caller-selected S3 URLs. New API, SDK, webapp, and MCP-assisted flows use /v1/file-uploads.
Usage Notes
- Presigned download URLs are temporary. Request a fresh URL when needed rather than caching.
- Image variants are generated asynchronously after upload. They may not be available for the first few seconds.
- Records reference files by
fileSimplyIdin file and image fields; deleting a file does not automatically rewrite record field values. See API Reference: Data Records. - File listings support team labels (
labelSimplyIds) for organization beyond folders. - The MCP
request_file_uploadtool returns a signed-in browser handoff. It never places local bytes, storage keys, or presigned upload credentials in model context. - GuardDuty scanning is a platform infrastructure cost, not a new customer-billable API usage unit. Promoted bytes still count toward the team's existing storage allowance or paid storage billing.
- The HTTP contract is available for native-client adoption, but this change does not add a native Simply Anywhere file-picker UI. The TypeScript helper targets clients with
Blob,FormData, and Web Crypto support. TeamAgent also receives no local-byte channel; hosted MCP uses the browser handoff above. - Editor services may persist an uploaded image only after converting its File Simply ID to a service-owned durable delivery URL. Website Studio supplies that finalizer; document/email editors keep upload hidden until their delivery finalizers exist.