Media library
The media library holds your app's images, videos and documents, each at a public URL. Products, variants, store locations and pages point at those URLs. Use these endpoints to find files, keep them organised, swap a file for a new version without breaking the places that use it, and clean up.
How the library works#
- A file has a key and a URL. The key is the file's path in your app's storage, such as
12-34/products/dog-food.jpg; the URL is where anyone can fetch it. Both stay the same for the life of the file. - Folders are for you. A file's
folderis where it is filed in the library. Moving or renaming a file changes only that, never its key or URL, so nothing that uses it breaks. - Images are processed after upload. According to your app's upload preset, images are compressed, often converted to WebP, and resized into smaller copies called renditions, each with its own URL. This runs in the background shortly after the upload, so
width,height,sizeandrenditionsfill in later. A converted file keeps its original extension in the key. - Hidden files are kept out of the library's normal view, for example scans customers upload from the app. Lists leave them out unless you ask for them.
- Deleting is two steps. A deleted file goes to Trash and its URL keeps working. Purging removes it for good. Files left in Trash are purged automatically after 30 days, unless your app is set otherwise.
- Usage is tracked. Wherever a file's URL is stored, on a product, a variant, a store location or a page, we record it, so you can see what a change would affect.
The file object#
What the list endpoints return for each file.
| Field | Description |
|---|---|
| idinteger | Our id of the file. |
| filenamestring | The name shown in the library. |
| keystring | The file's path in your storage. Delete calls take it. |
| urlstring | The public URL. After a replace it ends in ?v= and the version number. |
| folderstring · nullable | The folder's key, or null for the top level. |
| sizeinteger | Size in bytes. |
| mime, width, heightnullable | Type and pixel size, once processed. |
| alt, captionstring · nullable | Alternative text and caption for the storefront. |
| tagsarray of strings | Your tags. |
| descriptionstring · nullable | Free text given at upload. |
| versioninteger | 1, plus one for every replace. |
| renditionsarray of objects | The smaller copies: label, width, height, size, key, url. |
| usage_countinteger | How many places use the file. |
| hidden, hidden_by, hidden_at, hidden_note | Whether the file is hidden, and who hid it, when and why. |
| sourcestring · nullable | Where the file came from, such as admin or app. |
| last_modified, inserted_atdatetime · ISO 8601, UTC | When the file was last written and first added. Sent without an offset. |
Browse files#
The files of your library, a page at a time, with filters for the clean-ups you do most: unused files, images without alternative text, large files.
Query parameters
| Parameter | Description |
|---|---|
| folderstring | Only the files directly in this folder, by its key. / is the top level. Leave it out for all files. |
| searchstring | Matches the name, alternative text, caption and tags. |
| kindstring | image, vector, video, audio or doc. |
| unusedboolean | Only files that nothing uses and that are older than the app's unused threshold. |
| noaltboolean | Only images without alternative text. |
| min_sizeinteger | Only files of at least this many bytes. |
| since_daysinteger | Only files written in the last so many days. |
| hidden, hidden_onlyboolean | Include hidden files, or list only them. |
| orderBystring · default name asc | name, size, inserted_at or last_modified, followed by asc or desc. |
| pageNointeger · default 1 | The page, starting at 1. |
| pageSizeinteger · default 30 | Files per page. |
Returns
data.files: the page of file objects. data.total_count: how many files match. data.hidden_count: how many of them are hidden. Unlike most lists, this one tells you the total.
Two related reads: GET /cdn/folders returns the folder tree, each folder with id, name, key, parent_cdn_folder_path, file_count, total_file_count (with subfolders) and its folders; pass folder to start below one. GET /cdn/files/summary returns file counts per kind and storage used, in bytes.
curl -G "https://api.morffeus.com/api/v2/cdn/files" \ -H "Authorization: Bearer $MORFFEUS_TOKEN" \ -d "folder=products" -d "kind=image" \ -d "noalt=true" -d "pageSize=50"
{
"data": {
"files": [
{
"id": 7731,
"filename": "dog-food.jpg",
"key": "12-34/products/dog-food.jpg",
"url": "https://cdn.example.com/12-34/products/dog-food.jpg",
"folder": "products",
"size": 84210,
"mime": "image/webp",
"width": 1600,
"height": 1600,
"alt": null,
"tags": [],
"version": 1,
"usage_count": 2,
"hidden": false,
"renditions": [
{
"label": "w800",
"width": 800,
"height": 800,
"url": "https://cdn.example.com/12-34/products/[email protected]",
…
}
],
…
}
],
"total_count": 138,
"hidden_count": 0
}
}
Edit, move and file#
Changes a file's text and visibility. None of these calls changes a file's key or URL.
| Call | Description |
|---|---|
| PATCH /cdn/file | Body: id (required) and any of alt, caption, tags (a list, or a comma-separated string), name (the name shown, which must be free in its folder), hidden and hidden_note. hidden: false keeps the file visible from then on. Returns the file, without url. |
| PATCH /cdn/files/move | Body: ids, a list of file ids, and folder, the target folder's key ("" or / for the top level). Missing folders are created. Returns one result per id, with success and message. |
| POST /cdn_folders | Creates a folder from {"cdn_folder": {…}} with name and key (both required), parent_cdn_folder_path, description. Returns 201. |
| PATCH /cdn/folder | Renames or moves a folder. Body: id (required), name, parent_folder (the new parent's key, "" for the top level), description. The files inside move with it. |
Errors
| Status | When |
|---|---|
| 404 | No such file or folder in your app: API.CdnFiles.FileNotFound, API.CdnFolders.FolderNotFound. |
| 422 | The name or key is taken: API.CdnFiles.KeyAlreadyExists, API.CdnFolders.KeyAlreadyExists. The new parent does not exist or is inside the folder: API.CdnFolders.ParentNotFound, API.CdnFolders.InvalidParent. |
curl -X PATCH "https://api.morffeus.com/api/v2/cdn/file" \ -H "Authorization: Bearer $MORFFEUS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "id": 7731, "alt": "Dog food, 2 kg bag", "tags": ["dog", "food"] }'
{
"errors": {
"CdnFiles": ["API.CdnFiles.FileNotFound"]
}
}
Replace a file#
Puts new content under the same key, so every product and page that uses the file shows the new version. The previous content is kept as a version you can go back to. The file's alternative text, caption, tags and visibility stay as they are, and its renditions are rebuilt.
Body parameters, as multipart form data
| Parameter | Description |
|---|---|
| filerequiredfile | The new content. |
| cache_strategyrequiredstring | How browsers and the CDN get the new version. version: the URL we return ends in ?v= and the version; use it where you show the file. purge: we clear the CDN's copies of the file and its renditions, and cache.purged says whether it worked; some setups do not support it. ttl: nothing is cleared, and caches pick up the change when their copy expires. |
Returns
data: the file, with its new version. cache: the strategy, the url to use, and purged for the purge strategy.
| Related call | Description |
|---|---|
| POST /cdn/files/{id}/revert | Goes back to a kept version. Body: cache_strategy (required) and version (default: the latest kept one). Kept versions expire on the Trash schedule. |
| POST /cdn/files/{id}/renditions/regenerate | Rebuilds the file's renditions, optionally with new widths in renditions, for example [1600, 800, 400]. Returns 202: the work runs in the background. |
Errors
| Status | When |
|---|---|
| 400 | No file (API.CdnFiles.FileRequired), an unknown strategy (API.CdnFiles.UnknownCacheStrategy), purge where it is not available (API.CdnFiles.PurgeNotConfigured), or a file in Trash (API.CdnFiles.FileInTrash). |
| 404 | No such file in your app, or no version to revert to (API.CdnFiles.NoVersionToRevert). |
curl -X POST "https://api.morffeus.com/api/v2/cdn/files/7731/replace" \ -H "Authorization: Bearer $MORFFEUS_TOKEN" \ -F "file=@dog-food_new.jpg" \ -F "cache_strategy=version"
{
"data": {
"id": 7731,
"key": "12-34/products/dog-food.jpg",
"version": 2,
…
},
"cache": {
"strategy": "version",
"url": "https://cdn.example.com/12-34/products/dog-food.jpg?v=2"
}
}
Where a file is used#
Every place that stores the file's URL. Check it before you replace or delete a file.
Query parameters
| Parameter | Description |
|---|---|
| offset, limitinteger · default 0, 30 | Paging. |
Returns
data: one entry per use, with entity_type and entity_id (for example product and its id), field (such as images or image_url), label (a readable name), url as stored, and total_count, the number of uses. A file that is not in your app returns an empty list.
GET /cdn/usages/broken lists the opposite: stored URLs that point at a file the library no longer has, with the same fields and a search parameter. Files in Trash do not count as broken.
{
"data": [
{
"entity_type": "product",
"entity_id": 48377,
"field": "images",
"label": "Dog food",
"url": "https://cdn.example.com/12-34/products/dog-food.jpg",
"total_count": 2
},
{
"entity_type": "product_variant",
"entity_id": 91120,
"field": "image_url",
…
}
]
}
Delete, restore and purge#
Moves a file to Trash. Its URL keeps working until the file is purged, so nothing breaks at once. Delete calls take the file's key; restore and purge take its id. Send the inputs of DELETE calls in the query string: some HTTP clients drop the body of a DELETE.
| Call | Description |
|---|---|
| DELETE /cdn?file= | One file to Trash, by its key. A file already in Trash also returns 200, and its Trash time is not reset. |
| DELETE /cdn/list | Several files: files, a list of {"key": …}. Returns one result per file, with success and message. |
| DELETE /cdn/folder?folder= | A folder by its key: every file in it and its subfolders goes to Trash, and the folders are removed. Returns deleted_files and deleted_folders. |
| GET /cdn/trash | The files in Trash, each with deleted_at, deleted_by and purge_at, and a total_count. Parameters: search, page_no, page_size (default 30), order_by (default deleted_at desc). Note the underscores, unlike GET /cdn/files. |
| POST /cdn/files/{id}/restore | Takes one file out of Trash, back into its folder. POST /cdn/files/restore with ids does several. |
| DELETE /cdn/files/{id}/purge | Removes a file in Trash for good, with its renditions and kept versions. DELETE /cdn/files/purge with ids does several. Pages that still use the URL then show up in GET /cdn/usages/broken. |
Your app can be set to refuse deleting files that are in use; the delete then fails with API.CdnFiles.FileReferenced.
Errors
| Status | When |
|---|---|
| 400 | A purge of a file that is not in Trash: API.CdnFiles.FileNotInTrash. A delete of a file in use, where your app refuses it: API.CdnFiles.FileReferenced. |
| 404 | No such file in your app: API.CdnFiles.FileNotFound. |
| 422 | DELETE /cdn/folder without a folder: API.CdnFolders.FolderRequired. |
curl -X DELETE -G "https://api.morffeus.com/api/v2/cdn" \ -H "Authorization: Bearer $MORFFEUS_TOKEN" \ --data-urlencode "file=12-34/products/dog_food_old.jpg"
{
"data": { "message": "File deleted", "success": true }
}
{
"errors": {
"CdnFiles": ["API.CdnFiles.FileNotInTrash"]
}
}
Images on products and locations#
Products, variants and store locations store image URLs. To use a library file, send its url as image_url in the product's or variant's images with POST /int/products. We store the URL as you send it and do not download it, so a URL from outside the library works too, but it is not tracked. A library URL counts as a usage of the file straight away.
Two more reads help here. GET /cdn_upload_presets lists your app's upload presets, with the output format, maximum width, quality and rendition widths each applies; the default one has is_default: true. GET /cdn/files/pdf-renders?name= finds PDFs whose pages were rendered as images, with the URL of each page.
Related#
- Products: where product and variant images are set.
- Locations: store locations and their images.
- Errors: the error envelope.