Skip to content

Files

File fields do not store bytes in Mongo. The client:

  1. Starts an upload session (declared filename, contentType, size).
  2. PUTs the bytes to the returned presigned URL (S3/MinIO).
  3. Completes the session so the file is attached to the record.

The SDKs wrap this in uploadFile (upload_file in Python).

The record must already exist. Create the document first, then upload.

Completed uploads and file deletes can fire webhooks (file.uploaded, file.deleted).

All three clients reject a buffer whose length is not the declared size before they PUT, with Upload stream length (<size>) does not match bytes read (<n>). The server accepts an object smaller than the declared size. It rejects an object larger than that size.

uploadFile accepts a Blob, ArrayBuffer, or Uint8Array.

const bytes = new Uint8Array(await file.arrayBuffer());
const meta = await posts.uploadFile(recordId, 'attachment', {
data: bytes,
size: bytes.byteLength,
filename: 'photo.jpg',
contentType: 'image/jpeg',
});
const download = await posts.getDownloadUrl(recordId, 'attachment', meta.id);
console.log(download.url);
await posts.deleteFile(recordId, 'attachment', meta.id);
Step Method Path
Start POST /api/p/:projectId/:table/:recordId/files/:field/upload-sessions
Complete POST /api/p/:projectId/:table/:recordId/files/:field/:fileId/complete
Download URL GET /api/p/:projectId/:table/:recordId/files/:field/:fileId
Delete DELETE same as download

Enable the upload, download, and fileDelete endpoints. Add file rules (fileSizeLimit, fileMimeType, fileExtensionAllow) on upload.

A disabled upload endpoint is 404 Upload endpoint not found. Download is 404 Download endpoint not found. File delete is 404 File delete endpoint not found.

The session’s maxBytes is the plan ceiling for one file. See Usage and limits.

  1. POST /api/p/{projectId}/{table}/{recordId}/files/{field}/upload-sessions with { "filename", "contentType", "size" }. size must be greater than 0. An empty filename or content type is 400. A declared size above the plan maximum is 413 File too large. A missing record is 404 Record not found. A disabled upload endpoint is 404 Upload endpoint not found.

  2. 200 data contains fileId, storageKey, uploadUrl, uploadSessionId, expiresInSeconds (900), and maxBytes (the plan ceiling). The presign TTL is 15 minutes. expiresAt on the session is that same window.

  3. PUT the bytes to uploadUrl with the same content type. This request goes to object storage, not to api.tefily.com.

  4. POST .../files/{field}/{fileId}/complete with { "uploadSessionId" }. 200 data is the file metadata: _id, schemaId, tableName, recordId, fieldName, key, filename, contentType, size, uploadedBy, createdAt. The record field is updated in the same call.

Complete rejects the session with 400 when it does not match (Upload session does not match this upload), is already completed (Upload session already completed), or has expired (Upload session has expired). A missing object is Uploaded file not found in storage. An empty object is Uploaded file is empty. An object larger than the declared size is Uploaded file is larger than declared size. A smaller object is accepted, and the stored size is the object size. Another user’s session is 403 Upload session was created by another user unless the caller bypasses access rules.

Download GET on the same path as delete returns { "url", "expiresAt", "file" }. expiresAt is 15 minutes out. The download URL is a presigned GET.

On a scalar file field, complete sets the field to the file id. On an array file field, complete appends the id. File delete removes the id from the array, or sets a scalar field to null.

maxBytes in the session response is the plan max_file_bytes (see Usage and limits).

Deleting the document, one row or in bulk, also deletes storage objects and _files rows for that tableName and recordId. Each object is removed on its own. An error is logged and is not returned on the API response.

Pending upload sessions expire after 15 minutes. The next upload begin or complete marks those sessions expired and deletes their objects.