docs
/
AppEngine API

Files and media

Upload, thumbnails, signed URLs, privacy, and the org-scoped storage layout.

Files live in S3-compatible object storage. The repository controller exposes about 25 file handlers under /repository/file/*, plus a customer-scoped subset and a Pexels-backed stock media search.

Uploading

POST/repository/file/uploadJWT

multipart/form-data, field name file. Requires the create content permission.

Form fieldPurpose
fileThe file itself. A missing file is 400 Invalid file, null.
locationDestination folder. Joined as location + '/' + originalname; without it, the original filename is the whole path.
metadataOptional metadata; when absent it is derived from the path.
isPrivateThe string "true" to keep the object private. Anything else makes it publicly readable.
curl -X POST https://appengine.appmint.io/repository/file/upload \
  -H 'Authorization: Bearer …' -H 'orgid: acme' \
  -F '[email protected]' \
  -F 'location=products/2026' \
  -F 'isPrivate=false'
isPrivate is compared as a string

The handler tests body.isPrivate === 'true'. It arrives from a multipart form as text, so a JSON boolean true will not match — the object ends up public. Send the literal string.

POST/repository/file/upload-urlJWT

Fetches a remote URL and stores it, with the same side effects as a direct upload.

{ "url": "https://example.com/a.png", "location": "imports", "name": "a", "thumbnails": true, "isPrivate": false }

The MIME type and extension are sniffed from the download (.svg is special-cased), and the object is written to <location>/<name>[.<ext>].

What an upload does

1. Scope the path to the org addOrgIdToPath prefixes the tenant, so every key is namespaced.

2. Clear stale thumbnails Any previous thumbnails for that key are deleted first — re-uploading over a path does not leave the old derivatives behind.

3. Write the object putObject into S3_BUCKET with the derived ContentType.

4. Apply the ACL Unless isPrivate, the object is set public-read.

5. Generate thumbnails Via sharp, unless disabled. Failures are logged and swallowed — the upload still succeeds without thumbnails.

6. Return the merged descriptor The file entry from a listing, merged with the thumbnail descriptors.

Thumbnails

Three sizes by default:

VariantWidth
xs100
sm200
md400

Override with the IMAGE_SIZES env var (JSON, e.g. {"xs":100,"sm":200,"md":400,"lg":800}). Only image extensions are processed — png, jpeg, jpg, gif, tiff, bmp, webp by default, configurable via IMAGE_EXTENSIONS.

Derivatives are stored beside the original under a thumbnails segment inserted at the second path position, with the size appended to the filename:


acme/products/2026/widget.jpg
acme/thumbnails/products/2026/widget_sm.jpg

Regenerate on demand:

POST/repository/file/thumbnailsJWT

Takes { location } — a single path or an array.

These variants are what BaseModel.post.images.meta.xs|sm|md points at, which is why an image referenced from a record already has responsive sizes available.

Reading files

POST/repository/fileJWT
POST/repository/file/bufferJWT
POST/repository/file/streamJWT
POST/repository/file/urlJWT
POST/repository/file/signurlJWT
POST/repository/file/statJWT
POST/repository/file/existsJWT
POST/repository/file/get_assetJWT
Treat signed URLs as secrets

A signed URL grants access to the object to whoever holds it. Do not put one in a page that is cached or indexed, and re-issue rather than storing them long-term.

Managing files

POST/repository/file/copyJWT
POST/repository/file/moveJWT
POST/repository/file/deleteJWT
POST/repository/file/appendJWT
POST/repository/file/prependJWT
POST/repository/file/createfolderJWT
POST/repository/file/make-privateJWT
POST/repository/file/make-publicJWT
GET/repository/file/driverJWT

append and prepend are fully supported only by the local driver; on S3 they delegate to the underlying disk.

Listing

POST/repository/file/flatlistJWT
GET/repository/file/flatlist/:prefix/:pageNumberJWT

Paged, 100 keys per page by default. ?check-privacy=true resolves each object's ACL, which costs an extra call per key.

Listing options support prefix, maxKeys, pageNumber, startPage, recursive, endsWith, includes, thumbnail, foldersOnly and checkPrivacy.

POST/repository/file/indexJWT

Indexes a file location so it becomes searchable.

Favicons

POST/repository/file/create_faviconJWT

Builds favicon.ico and favicon.png at the org bucket root from a source image (sharp + to-ico) and returns { ico: { signedUrl, path }, png: { signedUrl, path } }.

Customer-scoped files

Three parallel endpoints let an end user manage their own uploads without reaching the operator surface:

POST/repository/customer/file/uploadJWT
POST/repository/customer/file/flatlistJWT
POST/repository/customer/file/deleteJWT

Stock media

Pexels-backed search, so the Studio asset picker can offer stock imagery inline:

POST/repository/media/photosJWT
POST/repository/media/photos/curatedJWT
POST/repository/media/videosJWT
POST/repository/media/videos/popularJWT

Assets

Assets are records that describe files — searchable, taggable, and attached to other records.

POST/repository/find-asset/:datatypeJWT
POST/repository/search-asset/:datatypeJWT
POST/repository/update-asset/:datatype/:idJWT
POST/repository/delete-asset/:datatypeJWT

Storage configuration

VariablePurpose
S3_BUCKETBucket name
S3_KEY, S3_SECRETCredentials
S3_ENDPOINTEndpoint — set for S3-compatible providers
S3_REGIONRegion
FILE_PATHBase path within the disk
IMAGE_SIZESThumbnail sizes, JSON
IMAGE_EXTENSIONSExtensions eligible for thumbnails, JSON
Two storage paths coexist

The direct S3 client used by put, createThumbnails and createFavicon writes to S3_BUCKET with the org id as a path prefix. The flydrive StorageManager built in getStorage is configured for a per-org bucket — S3_BUCKET + '-' + orgId. If you are provisioning storage or auditing where a file landed, check which of the two the operation went through.