Files API

building

Every field a file response carries, and which ones can be absent.

The file object

The same shape everywhere a file is returned.

A file
1{2  "id": "E7iVnWA1LiEpu3u8dRTVK",3  "projectId": "WXm71CLq69pZAZCWR2l_m",4  "ownerUserId": null,5  "filename": "sneaker-front-dEPY6g.jpg",6  "originalFilename": "sneaker front.jpg",7  "key": "files/originals/public/…/sneaker-front-dEPY6g.jpg",8  "contentType": "image/jpeg",9  "size": 204800,10  "metadata": null,11  "visibility": "public",12  "uploadStatus": "confirmed",13  "createdAt": "2026-08-14T13:38:29.830Z",14  "updatedAt": "2026-08-14T13:38:33.412Z",15  "transformations": { "image": { "enabled": true, "visibility": "public" } },16  "entity": { "type": "product", "id": "prod_abc123", "role": "gallery", "position": 0 },17  "url": "https://cdn…/files/originals/public/…",18  "variants": [{ "width": 100, "url": "…" }],19  "srcset": "…100w, …300w, …"20}
FieldNotes
idOurs. Stable for the file's life
projectIdAlways your own project
ownerUserIdWhoever you said uploaded it, or null
filenameSanitised, with a uniqueness suffix
originalFilenameWhat the user called it — display this
keyThe storage key. Returned so you can recognise your own objects; you never need to build one
contentTypeAs declared at upload
sizeBytes
visibilitypublic or private
uploadStatusAlways confirmed in list responses
transformationsWhat was asked for, not what exists
entityThe attachment, or null
urlPermanent when public, signed for five minutes when private
variantsAbsent when the file has no sizes
srcsetAbsent for the same reason

What can be absent

variants and srcset appear only for a transform-enabled image in a format we can resize. Their absence is information — check for it rather than assuming:

Rendering any file
1<img src={file.url} srcSet={file.srcset} sizes="(max-width: 768px) 100vw, 400px" />

srcSet={undefined} is valid and the browser falls back to src, so the same markup works for a PDF, an SVG and a photograph.

Pick sizes with sizes, not by choosing a width yourself. Hard-coding one means shipping a 1200px image to a phone, or a 100px one to a retina display — the browser knows both facts and you do not.

If you are not rendering to a browser — a PDF, an email, a native canvas — use variants[], which carries the same widths as the srcset:

Picking a width by hand
1const width = file.variants?.find((v) => v.width >= target);2const url = width?.url ?? file.url;

transformations means requested, not built

transformations.image.enabled records what you asked for at upload. It does not promise the sizes exist — each is generated the first time that width is requested. variants is the field that tells you which ones are on offer.