Skip to main content

File Storage

Files are attached to record fields of type file. Each file is stored in tenant-isolated storage with path traversal protection built in.

Field configuration​

Add a file field to your entity schema:

{
"fieldType": "file",
"config": {
"accept": ["image/png", "image/jpeg", "application/pdf"],
"maxSize": 5242880,
"multiple": false
}
}
OptionTypeDefaultDescription
acceptstring[]all typesAllowed MIME types
maxSizenumberno limitMax bytes per file
multiplebooleanfalseAllow multiple files on a single field

All three options are optional. Without accept, any file type is allowed.

Uploading files​

Via MCP​

MCP Tool: upload_file (Profile: core)

Upload from a URL:

upload_file({
entityName: "contacts",
recordId: "rec_123",
fieldKey: "avatar",
url: "https://example.com/photo.jpg"
})

Upload from base64:

upload_file({
entityName: "contacts",
recordId: "rec_123",
fieldKey: "avatar",
base64: "iVBORw0KGgo...",
fileName: "photo.jpg",
mimeType: "image/jpeg"
})

When uploading from base64, fileName and mimeType are required.

Via REST API​

curl -X POST https://api.fyso.dev/api/files/contacts/rec_123/avatar \
-H "Authorization: Bearer <token>" \
-F "file=@photo.jpg"

Uses multipart/form-data. The file is validated against the field's accept and maxSize config.

Downloading files​

curl https://api.fyso.dev/api/files/<key>

Downloads are public. Images and PDFs are served inline (displayed in the browser). Other types trigger a download.

The <key> is the full storage path returned when the file was uploaded.

Deleting files​

curl -X DELETE https://api.fyso.dev/api/files/<key> \
-H "Authorization: Bearer <token>"

Deletion is immediate. The file is removed from storage and the record field is cleared.

Storage path​

Files are stored at:

{tenantSlug}/{entityName}/{recordId}/{fieldKey}/{uuid}.{ext}

Each file gets a unique UUID — uploading a new file to the same field doesn't overwrite the old one. Delete explicitly if you need to replace.

Limits​

LimitValue
Max upload size10 MB per request
MIME validationChecked against field accept config
Size validationChecked against field maxSize config
Path traversalBlocked — storage paths are sanitized

Example: profile avatar upload and display​

# Upload an avatar
curl -X POST https://api.fyso.dev/api/files/contacts/rec_123/avatar \
-H "Authorization: Bearer <token>" \
-F "file=@photo.jpg"

# Response includes the file key
# { "success": true, "data": { "key": "my-app/contacts/rec_123/avatar/a1b2c3.jpg", ... } }

# Display the avatar (public URL, no auth needed)
curl https://api.fyso.dev/api/files/my-app/contacts/rec_123/avatar/a1b2c3.jpg