Docs API reference
Assets
The media library: images, video and audio your scenes use. Upload a file and use its id in the app; list the library to find what is there.
Every call needs an API key in the Authorization header. New to the API? Start with
the API overview.
- GET List media folders /assets/folders
- POST Create a media folder /assets/folders
- GET Get a media folder /assets/folders/{id}
- PATCH Rename or move a media folder /assets/folders/{id}
- DELETE Delete a media folder /assets/folders/{id}
- GET Get one file /assets/{id}
- PATCH Rename or file a media item /assets/{id}
- GET List media /assets
- POST Upload a file /assets
List media folders
/assets/folders assetsFlat, each with the path from the top level down to it — so a breadcrumb needs no walking.
Parameters
limitinteger queryPage size, 1–200.
1–200. Default
50cursorstring queryThe
next_cursorof the previous page.
Responses
- 200 A page of folders.
- 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
Response fields (200)
itemsobject[] required6 fields in
itemsidstring requirednamestring requiredparent_idstring or nullThe folder this one sits in;
nullat the top level.pathobject[] read-onlyTop level first, this folder last — ready to render as a breadcrumb.
2 fields in
pathidstringnamestring
created_atinteger read-onlyupdated_atinteger read-only
next_cursorstring or null requiredPass as
cursorfor the next page;nullon the last page.
curl "https://www.wunderframe.com/api/v1/assets/folders?limit=50" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY"{
"items": [
{
"id": "fld_sponsors",
"name": "Sponsors",
"parent_id": null,
"path": [
{
"id": "fld_sponsors",
"name": "Sponsors"
}
],
"created_at": 1789372800000,
"updated_at": 1789372800000
}
],
"next_cursor": null
}Error example
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}Create a media folder
/assets/folders assetsRequest body required
namestringUp to 80 characters
parent_idstring or nullOmit to leave it where it is;
nullfor the top level.
Responses
- 201 The new folder.
- 400 The request is invalid —
details.fieldnames the field when there is one. - 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
Response fields (201)
idstring requirednamestring requiredparent_idstring or nullThe folder this one sits in;
nullat the top level.pathobject[] read-onlyTop level first, this folder last — ready to render as a breadcrumb.
2 fields in
pathidstringnamestring
created_atinteger read-onlyupdated_atinteger read-only
curl -X POST "https://www.wunderframe.com/api/v1/assets/folders" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sponsors",
"parent_id": null
}'{
"id": "fld_sponsors",
"name": "Sponsors",
"parent_id": null,
"path": [
{
"id": "fld_sponsors",
"name": "Sponsors"
}
],
"created_at": 1789372800000,
"updated_at": 1789372800000
}Error example
{
"error": {
"code": "invalid",
"message": "The request is invalid — `details.field` names the field when there is one."
}
}Get a media folder
/assets/folders/{id} assetsParameters
idstring required pathThe folder’s id.
Responses
- 200 The folder.
- 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
- 404 Not found in this workspace.
Response fields (200)
idstring requirednamestring requiredparent_idstring or nullThe folder this one sits in;
nullat the top level.pathobject[] read-onlyTop level first, this folder last — ready to render as a breadcrumb.
2 fields in
pathidstringnamestring
created_atinteger read-onlyupdated_atinteger read-only
curl "https://www.wunderframe.com/api/v1/assets/folders/fld_sponsors" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY"{
"id": "fld_sponsors",
"name": "Sponsors",
"parent_id": null,
"path": [
{
"id": "fld_sponsors",
"name": "Sponsors"
}
],
"created_at": 1789372800000,
"updated_at": 1789372800000
}Error example
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}Rename or move a media folder
/assets/folders/{id} assetsOnly the fields you send change. A folder cannot be moved into itself or below itself.
Parameters
idstring required pathThe folder’s id.
Request body required
namestringUp to 80 characters
parent_idstring or nullOmit to leave it where it is;
nullfor the top level.
Responses
- 200 The folder.
- 400 The request is invalid —
details.fieldnames the field when there is one. - 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
- 404 Not found in this workspace.
- 409 Conflicts with the current state.
Response fields (200)
idstring requirednamestring requiredparent_idstring or nullThe folder this one sits in;
nullat the top level.pathobject[] read-onlyTop level first, this folder last — ready to render as a breadcrumb.
2 fields in
pathidstringnamestring
created_atinteger read-onlyupdated_atinteger read-only
curl -X PATCH "https://www.wunderframe.com/api/v1/assets/folders/fld_sponsors" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sponsors 2027"
}'{
"id": "fld_sponsors",
"name": "Sponsors",
"parent_id": null,
"path": [
{
"id": "fld_sponsors",
"name": "Sponsors"
}
],
"created_at": 1789372800000,
"updated_at": 1789372800000
}Error example
{
"error": {
"code": "invalid",
"message": "The request is invalid — `details.field` names the field when there is one."
}
}Delete a media folder
/assets/folders/{id} assetsThe folder and those below it go; everything filed in them MOVES UP to this folder’s parent. No file is ever deleted by this.
Parameters
idstring required pathThe folder’s id.
Responses
- 200 Where the contents went.
- 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
- 404 Not found in this workspace.
Response fields (200)
moved_tostring or null
curl -X DELETE "https://www.wunderframe.com/api/v1/assets/folders/fld_sponsors" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY"{
"moved_to": null
}Error example
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}Get one file
/assets/{id} assetsParameters
idstring required pathThe asset’s id.
Responses
- 200 The file.
- 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
- 404 Not found in this workspace.
Response fields (200)
idstring requiredkindstring requiredOne of
image,video,audionamestring requiredUp to 200 characters
mimestring requiredThe file type, e.g.
image/jpeg.sizeinteger requiredBytes.
widthinteger or nullPixels, when known. Files uploaded through the API are measured when first opened in the app.
heightinteger or nullduration_msinteger or nullLength of video and audio, when known.
urlstring or nullA signed download URL, valid for about an hour.
folder_idstring or nullThe folder it is filed in;
nullat the top level.created_atinteger requiredEpoch ms.
curl "https://www.wunderframe.com/api/v1/assets/Hq3vK0p9aT2xYb7LmN4sW" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY"{
"id": "Hq3vK0p9aT2xYb7LmN4sW",
"kind": "image",
"name": "keynote-backdrop.jpg",
"mime": "image/jpeg",
"size": 482113,
"width": null,
"height": null,
"duration_ms": null,
"url": "https://…signed…",
"folder_id": null,
"created_at": 1789372800000
}Error example
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}Rename or file a media item
/assets/{id} assetsRenames it, or moves it into a folder (folder_id: null for the top level). The BYTES are immutable: blocks reference an asset by id, so replacing a file would silently change every screen using it — upload a new one instead.
Parameters
idstring required pathThe asset’s id.
Request body required
namestringfolder_idstring or null
Responses
- 200 The file.
- 400 The request is invalid —
details.fieldnames the field when there is one. - 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
- 404 Not found in this workspace.
Response fields (200)
idstring requiredkindstring requiredOne of
image,video,audionamestring requiredUp to 200 characters
mimestring requiredThe file type, e.g.
image/jpeg.sizeinteger requiredBytes.
widthinteger or nullPixels, when known. Files uploaded through the API are measured when first opened in the app.
heightinteger or nullduration_msinteger or nullLength of video and audio, when known.
urlstring or nullA signed download URL, valid for about an hour.
folder_idstring or nullThe folder it is filed in;
nullat the top level.created_atinteger requiredEpoch ms.
curl -X PATCH "https://www.wunderframe.com/api/v1/assets/Hq3vK0p9aT2xYb7LmN4sW" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"folder_id": "fld_sponsors"
}'{
"id": "Hq3vK0p9aT2xYb7LmN4sW",
"kind": "image",
"name": "keynote-backdrop.jpg",
"mime": "image/jpeg",
"size": 482113,
"width": null,
"height": null,
"duration_ms": null,
"url": "https://…signed…",
"folder_id": null,
"created_at": 1789372800000
}Error example
{
"error": {
"code": "invalid",
"message": "The request is invalid — `details.field` names the field when there is one."
}
}List media
/assets assetsNewest first.
Parameters
kindstring queryOnly this kind.
One of
image,video,audioqstring querySearch file names.
folderstring queryOnly this folder, or
rootfor the top level. Leave it out for the whole library.limitinteger queryPage size, 1–200.
1–200. Default
50cursorstring queryThe
next_cursorof the previous page.
Responses
- 200 A page of media.
- 400 The request is invalid —
details.fieldnames the field when there is one. - 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
Response fields (200)
itemsobject[] required11 fields in
itemsidstring requiredkindstring requiredOne of
image,video,audionamestring requiredUp to 200 characters
mimestring requiredThe file type, e.g.
image/jpeg.sizeinteger requiredBytes.
widthinteger or nullPixels, when known. Files uploaded through the API are measured when first opened in the app.
heightinteger or nullduration_msinteger or nullLength of video and audio, when known.
urlstring or nullA signed download URL, valid for about an hour.
folder_idstring or nullThe folder it is filed in;
nullat the top level.created_atinteger requiredEpoch ms.
next_cursorstring or null requiredPass as
cursorfor the next page;nullon the last page.
curl "https://www.wunderframe.com/api/v1/assets?limit=50" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY"{
"items": [
{
"id": "Hq3vK0p9aT2xYb7LmN4sW",
"kind": "image",
"name": "keynote-backdrop.jpg",
"mime": "image/jpeg",
"size": 482113,
"width": null,
"height": null,
"duration_ms": null,
"url": "https://…signed…",
"folder_id": null,
"created_at": 1789372800000
}
],
"next_cursor": null
}Error example
{
"error": {
"code": "invalid",
"message": "The request is invalid — `details.field` names the field when there is one."
}
}Upload a file
/assets assetsSend the file itself as the request body, with its Content-Type and optionally its name in X-Filename (percent-encode non-ASCII names).
Accepted: images (PNG, JPEG, WebP, GIF, SVG) up to 25 MB; video (MP4, WebM, MOV) and audio (MP3, M4A, WAV, OGG) up to 100 MB. Larger video and audio files can be uploaded in the app, which accepts video up to 1 GB.
curl -X POST "$BASE/assets" -H "Authorization: Bearer $KEY" \
-H "Content-Type: image/jpeg" -H "X-Filename: backdrop.jpg" \
--data-binary @backdrop.jpgParameters
folderstring queryFile it in this folder. Omit for the top level.
X-Filenamestring headerThe name shown in the library. Defaults to
Untitled.<ext>.Up to 200 characters
Request body required
The file itself as the body, with one of image/jpeg, image/png, image/webp, image/gif, image/svg+xml, video/mp4, video/webm, video/quicktime, audio/mpeg, audio/mp4, audio/wav, audio/ogg as its Content-Type.
Responses
- 201 Uploaded.
- 400 The request is invalid —
details.fieldnames the field when there is one. - 401 Missing or invalid API key.
- 403 The key lacks the scope, or the role is read-only.
- 413 Too large.
- 415 Unsupported media type.
Response fields (201)
idstring requiredkindstring requiredOne of
image,video,audionamestring requiredUp to 200 characters
mimestring requiredThe file type, e.g.
image/jpeg.sizeinteger requiredBytes.
widthinteger or nullPixels, when known. Files uploaded through the API are measured when first opened in the app.
heightinteger or nullduration_msinteger or nullLength of video and audio, when known.
urlstring or nullA signed download URL, valid for about an hour.
folder_idstring or nullThe folder it is filed in;
nullat the top level.created_atinteger requiredEpoch ms.
curl -X POST "https://www.wunderframe.com/api/v1/assets" \
-H "Authorization: Bearer $WUNDERFRAME_API_KEY" \
-H "Content-Type: image/jpeg" \
-H "X-Filename: photo.jpg" \
--data-binary @photo.jpg{
"id": "Hq3vK0p9aT2xYb7LmN4sW",
"kind": "image",
"name": "keynote-backdrop.jpg",
"mime": "image/jpeg",
"size": 482113,
"width": null,
"height": null,
"duration_ms": null,
"url": "https://…signed…",
"folder_id": null,
"created_at": 1789372800000
}Error example
{
"error": {
"code": "invalid",
"message": "The request is invalid — `details.field` names the field when there is one."
}
}