Endpoints

Booster file storage

Upload, list, link and delete the files of a booster panel from your own server with an API key.

View as Markdown

A booster panel can keep files: documents its users upload, invoices and exports that a workflow generates, product images. The endpoints on this page let your server work with those files with an API key: upload a generated report, list what visitors sent, get a download link, clean up.

The endpoints are under /api/v3/booster/storage/private/. Panels themselves reach their files through a separate access path that is not covered here.

Concepts

Folders and paths

Files are addressed by a path: a top-level folder, optional sub-folders and the file name, separated by /, for example invoices/2026/INV-0042.pdf.

  • The folder name may contain letters, digits, _ and -.
  • Sub-folder and file names may contain any characters except control characters and / \ : * ? " < > | # % '; they cannot be . or .. or start or end with a space.
  • A path has at least two parts (<folder>/<name>), at most 8 levels and 512 characters.
  • Folders and sub-folders are not created separately: they exist as long as they hold a file. A path is unique within a panel.

File storage settings

The panel owner turns the file storage on and defines folders in the panel's module settings in the app. For each folder (or * for all others) the settings say who may upload, read, list, change and delete files, which file types it accepts, how large a file may be, how many files it may hold and whether files are deleted after a number of days. A folder may give permanent public links (for images shown on a public page).

Who can access a panel's files

Requests act as the user who owns the API key. That user must own the panel (be its creator, or a member of the group that owns it) or have the panel shared with them, directly or through a group. The API key must carry the matching scope:

Scope Endpoints
ayeto.booster.storage list, count, get, url, usage
ayeto.booster.storage.write upload, upload-b64, update, delete, delete-many

The write scope does not include the read scope; a key that reads and writes needs both. The endpoints work also while the panel's file storage is switched off, so you can still read and clean up stored files.

For requests on this page the folder settings apply like this:

  • An operation set to none for a folder is disabled for everyone, including this API (403).
  • Every other level allows API requests, on all files of the folder.
  • A folder without settings (and without a * entry) is accessible only to the API and the owner.
  • The accepted file types, the file size limit and the limits of files and data per folder do apply to uploads through this API.

Files

Field Type Description
id UUID Identifier of the file.
path string Full path, e.g. invoices/2026/INV-0042.pdf.
folder string Top-level folder.
name string File name (last part of the path).
size integer Size in bytes.
content_type string Type of the content. Known formats (PNG, JPEG, GIF, WebP, AVIF, PDF, common audio and video) are recognised from the content and win over the declared type; HTML, SVG and XML are recognised too.
sha256 string SHA-256 of the content (hex).
metadata object Your data about the file (JSON object, at most 4 KB, keys cannot start with $ or contain .).
record object or null The booster database record the file belongs to: {collection, key}.
owner UUID or null The panel user who uploaded the file; null for files uploaded through the API.
created, updated integer Upload and last change time in milliseconds since the epoch.
expires_at string or null When the file is deleted, in folders that keep files for a number of days.
url string or null Link that shows or downloads the file (see Download links).
download_url string or null Link that always downloads the file.

Files and database records

A file can belong to a record of the panel's database: send the record's collection and key with the upload or set it later with update. The record must exist in the panel's database. By default a file is deleted when its record is deleted; the folder settings can keep it. Store the file's id (or path) in the record value when your panel needs to find the file from the record.

Links are absolute URLs under /api/v3/booster/storage/file/ and need no headers, so they work in <img src>, <a href> and from other servers.

  • A link is signed and valid for 60 minutes. Ask for a fresh one with Get download links when you need it, rather than storing links.
  • In folders with permanent public links, url never expires. It stops working when the folder no longer gives public links or the file is deleted.
  • Images, audio, video and PDF are shown in the browser; other types (and every download_url) are downloaded. HTML, SVG and XML files are always downloaded.
  • Image links accept ?w= and ?h= (pixels) for a resized copy, e.g. thumbnails.
  • Links support Range requests (seeking in audio and video).

Limits

Limit Value
File size the folder's limit, at most 100 MB
Data per panel the panel's limit, at most 1 GB by default
Metadata 4 KB of JSON
Files returned by one list 100 without paging, up to 1000 with limit_from / limit_to
ids in url and delete-many 100
Base64 upload use upload (multipart) for files larger than a few MB, direct upload for large ones

Files also count against the storage quota of the panel owner or, for panels of an organization, of the organization.

Common request headers and errors

Header Description
uni-api-key Your API key. See Authentication.
panel-id ID of the panel whose files you access.
Content-Type application/json, or multipart/form-data for upload.

Errors are JSON of the form {"detail": "..."} (see Errors). These can come from every endpoint:

Status detail Cause
401 API key not provided / API key is invalid The key is empty, unknown, disabled or lacks the endpoint's scope.
403 permission denied You neither own the panel nor have it shared with you.
403 operation '<operation>' is disabled for folder '<folder>' The folder settings set this operation to none. The operation is upload, read, list, update or delete.
404 panel not found No panel with this ID, or the panel is disabled.
404 file not found No file with this ID or path in the panel.
422 validation error The panel-id header is missing or not a UUID, or the body does not match the request model.
429 rate limit message Too many requests; see Rate limits.

Upload a file

Stores a file. Send it as multipart/form-data.

Endpoint POST /api/v3/booster/storage/private/upload
Scope ayeto.booster.storage.write
Rate limit default

Request

Form field Type Required Description
file file yes The content.
path string yes Target path. A path ending with / is a directory: the uploaded file name is appended.
metadata string no JSON object with your data about the file.
record_collection, record_key string, UUID no The database record the file belongs to (both or neither).
overwrite boolean no Replace a file at the same path (needs the delete right in its folder). Default false.
rename boolean no When the path is taken, store as name (1).ext, name (2).ext, … Default false.

Response

The stored file with links.

Errors

Status detail Cause
409 a file '<path>' already exists The path is taken and neither overwrite nor rename was sent.
422 path must start with a folder: '<folder>/<name>' The path has only one part.
422 folder name can only contain letters, digits, '_' and '-' Invalid folder name.
422 path segments cannot … Invalid sub-folder or file name (see Folders and paths).
422 folder '<folder>' does not accept <type> files The folder does not accept this file type.
422 the file is larger than <n> MB The file exceeds the folder's or the general size limit.
422 the file content is <type>, not <declared> / the file content is not <declared> The content does not match the declared image or PDF type.
422 files in this folder must belong to a database record The folder requires a record and none was sent.
422 record '<key>' is not in collection '<collection>' The record exists in another collection.
404 Database record not found No such record in the panel's database.
403 database access is not allowed for this panel A record was sent but the panel has no database.
422 metadata must be a JSON object / metadata is larger than 4096 bytes Invalid metadata.
403 folder '<folder>' has reached the maximum of <n> files / folder '<folder>' is full Folder limit reached.
403 the file storage of this panel is full Panel limit reached.
422 storage quota exceeded / organization storage quota exceeded The owner's (organization's) storage quota is full.

Examples

bash
curl -X POST "https://ayeto.ai/api/v3/booster/storage/private/upload" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -F "file=@INV-0042.pdf;type=application/pdf" \
  -F "path=invoices/2026/" \
  -F 'metadata={"customer": "ACME", "total": 1250}' \
  -F "record_collection=orders" \
  -F "record_key=8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70"
json
{
  "id": "5b0a1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d",
  "path": "invoices/2026/INV-0042.pdf",
  "folder": "invoices",
  "name": "INV-0042.pdf",
  "size": 48213,
  "content_type": "application/pdf",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "metadata": {"customer": "ACME", "total": 1250},
  "record": {"collection": "orders", "key": "8f14e45f-ceea-467a-9b1c-4e1f2a6b3c70"},
  "owner": null,
  "created": 1791374100000,
  "updated": 1791374100000,
  "expires_at": null,
  "url": "https://ayeto.ai/api/v3/booster/storage/file/3d2c5a8e-…/5b0a1c2d-…/1791377700i.Xk2…/INV-0042.pdf",
  "download_url": "https://ayeto.ai/api/v3/booster/storage/file/3d2c5a8e-…/5b0a1c2d-…/1791377700a.p9Q…/INV-0042.pdf"
}

Upload a file as base64

The same as Upload a file with a JSON body, for small files.

Endpoint POST /api/v3/booster/storage/private/upload-b64
Scope ayeto.booster.storage.write

Request

Field Type Required Description
path string yes Target path; its last part is the file name.
data string yes Base64 content or a data URL (data:text/csv;base64,…).
content_type string no Declared type (otherwise from the data URL or the file extension).
metadata, record, overwrite, rename no As in Upload a file; record is {collection, key}.

Response and errors

As in Upload a file, plus 422 data is not valid base64.

Example

bash
curl -X POST "https://ayeto.ai/api/v3/booster/storage/private/upload-b64" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{"path": "exports/orders-2026-10.csv", "data": "data:text/csv;base64,aWQsdG90YWwKMSwxMjUw"}'

Upload a large file directly

Large files (tens to hundreds of MB) can go straight to the storage service instead of through the API, in three steps: announce the file, POST it to the returned URL, complete the upload. Whether direct uploads are available depends on the AYETO installation; when they are not, upload/init answers 409 direct upload is not available, use the upload route and you use Upload a file.

Endpoints POST /api/v3/booster/storage/private/upload/init, POST /api/v3/booster/storage/private/upload/complete
Scope ayeto.booster.storage.write
  1. upload/init with path, filename (when the path ends with /), content_type, size (exact size in bytes) and optionally metadata, record, overwrite, rename. The folder rules, type and limits are checked as for an upload. The response is {upload_id, url, fields, expires_at}.
  2. POST to url as multipart/form-data: every entry of fields as a form field, then the file as the field file (it must be the last part). The file must have exactly the announced size and type. This request goes to the storage service, without your API key.
  3. upload/complete with {"upload_id": "…"} before expires_at (one hour). The uploaded content is checked again (size, type from the content) and the file is returned. An upload that is never completed is deleted.
Status detail Cause
409 direct upload is not available, use the upload route Use Upload a file.
404 upload not found Unknown or expired upload_id, or already completed.
422 the file was not uploaded / the uploaded file has another size than announced Step 2 did not store the announced file.

Other errors as in Upload a file.

List files

Returns the files directly in a directory and its sub-folders. Without folder it returns the panel's top-level folders.

Endpoint POST /api/v3/booster/storage/private/list
Scope ayeto.booster.storage

Request

Field Type Required Description
folder string no Top-level folder. Without it only folders is returned.
prefix string no Sub-folder inside the folder, e.g. 2026 or 2026/q1.
recursive boolean no Also files in sub-folders at any depth. Default false.
params object no filters, sort_key, sort_order, limit_from, limit_to as in the booster database. Fields: name, path, size, content_type, owner, created, updated, record.collection, record.key, metadata.<path>. Newest first by default.
links boolean no Include url and download_url. Default true.

Response

{"files": [...], "folders": [...]}: files of the page and the names of the sub-folders directly in the directory.

Example

bash
curl -X POST "https://ayeto.ai/api/v3/booster/storage/private/list" \
  -H "uni-api-key: $AYETO_API_KEY" \
  -H "panel-id: 3d2c5a8e-7b41-4f0e-9a6d-2c8b1e4f7a90" \
  -H "Content-Type: application/json" \
  -d '{"folder": "invoices", "prefix": "2026", "params": {"filters": [["metadata.customer", "==", "ACME"]]}}'

Count files

The number of files a list with the same folder, prefix, recursive (default true here) and params.filters would return across all pages. Without folder, all files of the panel.

Endpoint POST /api/v3/booster/storage/private/count
Scope ayeto.booster.storage

Get a file

One file with fresh links, by id or path.

Endpoint POST /api/v3/booster/storage/private/get
Scope ayeto.booster.storage
json
{"path": "invoices/2026/INV-0042.pdf"}

Fresh links of up to 100 files.

Endpoint POST /api/v3/booster/storage/private/url
Scope ayeto.booster.storage

Request

Field Type Required Description
ids array of UUID yes Files (1–100).
ttl_minutes integer no Shorter lifetime than the default 60 minutes.
download boolean no Links that always download. Default false.

Response

An array of {id, url, expires_at}; expires_at (milliseconds) is null for permanent public links.

Update a file

Renames or moves a file, replaces its metadata or its record. A move to another folder needs the upload right there and the delete right in the current folder, and the file must fit the new folder's type and size rules. The content never changes; upload with overwrite to replace it.

Endpoint POST /api/v3/booster/storage/private/update
Scope ayeto.booster.storage.write

Request

Field Type Required Description
id UUID yes The file.
path string no New path.
metadata object no New metadata (replaces the old).
record object no New record {collection, key}.
unlink_record boolean no Remove the record link.

Response and errors

The updated file. Errors as in Upload a file; 409 when the new path is taken.

Delete files

Endpoints POST /api/v3/booster/storage/private/delete ({"id": "…"}), POST /api/v3/booster/storage/private/delete-many ({"ids": [...]}, up to 100)
Scope ayeto.booster.storage.write

Returns {"accepted": true}. Links of a deleted file stop working at once. delete-many deletes the files in order and stops at the first one that fails.

Storage usage

Endpoint POST /api/v3/booster/storage/private/usage (empty body)
Scope ayeto.booster.storage
json
{"files": 214, "size": 73400320, "limit": 1073741824, "folders": {"invoices": 52428800, "products": 20971520}}

limit is the panel's limit in bytes (0 = only the owner's storage quota applies).

Events

Files stored, changed (moved, new metadata or record) and deleted through this API are events of the panel like any other: they start workflows with a booster file trigger on the panel, and the panel's webhooks that subscribe to file events receive them. Deletions by retention or together with a record are events too.