Assets

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.

List media folders

GET /assets/folders assets

Flat, each with the path from the top level down to it — so a breadcrumb needs no walking.

Parameters

  • limit integer query

    Page size, 1–200.

    1–200. Default 50

  • cursor string query

    The next_cursor of 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)
  • items object[] required
    6 fields in items
    • id string required
    • name string required
    • parent_id string or null

      The folder this one sits in; null at the top level.

    • path object[] read-only

      Top level first, this folder last — ready to render as a breadcrumb.

      2 fields in path
      • id string
      • name string
    • created_at integer read-only
    • updated_at integer read-only
  • next_cursor string or null required

    Pass as cursor for the next page; null on the last page.

curl "https://www.wunderframe.com/api/v1/assets/folders?limit=50" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"
Response 200
{
  "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
Response 401
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key."
  }
}

Create a media folder

POST /assets/folders assets

Request body required

  • name string

    Up to 80 characters

  • parent_id string or null

    Omit to leave it where it is; null for the top level.

Responses

  • 201 The new folder.
  • 400 The request is invalid — details.field names 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)
  • id string required
  • name string required
  • parent_id string or null

    The folder this one sits in; null at the top level.

  • path object[] read-only

    Top level first, this folder last — ready to render as a breadcrumb.

    2 fields in path
    • id string
    • name string
  • created_at integer read-only
  • updated_at integer 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
}'
Response 201
{
  "id": "fld_sponsors",
  "name": "Sponsors",
  "parent_id": null,
  "path": [
    {
      "id": "fld_sponsors",
      "name": "Sponsors"
    }
  ],
  "created_at": 1789372800000,
  "updated_at": 1789372800000
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Get a media folder

GET /assets/folders/{id} assets

Parameters

  • id string required path

    The 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)
  • id string required
  • name string required
  • parent_id string or null

    The folder this one sits in; null at the top level.

  • path object[] read-only

    Top level first, this folder last — ready to render as a breadcrumb.

    2 fields in path
    • id string
    • name string
  • created_at integer read-only
  • updated_at integer read-only
curl "https://www.wunderframe.com/api/v1/assets/folders/fld_sponsors" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"
Response 200
{
  "id": "fld_sponsors",
  "name": "Sponsors",
  "parent_id": null,
  "path": [
    {
      "id": "fld_sponsors",
      "name": "Sponsors"
    }
  ],
  "created_at": 1789372800000,
  "updated_at": 1789372800000
}
Error example
Response 401
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key."
  }
}

Rename or move a media folder

PATCH /assets/folders/{id} assets

Only the fields you send change. A folder cannot be moved into itself or below itself.

Parameters

  • id string required path

    The folder’s id.

Request body required

  • name string

    Up to 80 characters

  • parent_id string or null

    Omit to leave it where it is; null for the top level.

Responses

  • 200 The folder.
  • 400 The request is invalid — details.field names 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)
  • id string required
  • name string required
  • parent_id string or null

    The folder this one sits in; null at the top level.

  • path object[] read-only

    Top level first, this folder last — ready to render as a breadcrumb.

    2 fields in path
    • id string
    • name string
  • created_at integer read-only
  • updated_at integer 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"
}'
Response 200
{
  "id": "fld_sponsors",
  "name": "Sponsors",
  "parent_id": null,
  "path": [
    {
      "id": "fld_sponsors",
      "name": "Sponsors"
    }
  ],
  "created_at": 1789372800000,
  "updated_at": 1789372800000
}
Error example
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Delete a media folder

DELETE /assets/folders/{id} assets

The 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

  • id string required path

    The 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_to string or null
curl -X DELETE "https://www.wunderframe.com/api/v1/assets/folders/fld_sponsors" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"
Response 200
{
  "moved_to": null
}
Error example
Response 401
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key."
  }
}

Get one file

GET /assets/{id} assets

Parameters

  • id string required path

    The 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)
  • id string required
  • kind string required

    One of image, video, audio

  • name string required

    Up to 200 characters

  • mime string required

    The file type, e.g. image/jpeg.

  • size integer required

    Bytes.

  • width integer or null

    Pixels, when known. Files uploaded through the API are measured when first opened in the app.

  • height integer or null
  • duration_ms integer or null

    Length of video and audio, when known.

  • url string or null

    A signed download URL, valid for about an hour.

  • folder_id string or null

    The folder it is filed in; null at the top level.

  • created_at integer required

    Epoch ms.

curl "https://www.wunderframe.com/api/v1/assets/Hq3vK0p9aT2xYb7LmN4sW" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"
Response 200
{
  "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
Response 401
{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid API key."
  }
}

Rename or file a media item

PATCH /assets/{id} assets

Renames 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

  • id string required path

    The asset’s id.

Request body required

  • name string
  • folder_id string or null

Responses

  • 200 The file.
  • 400 The request is invalid — details.field names 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)
  • id string required
  • kind string required

    One of image, video, audio

  • name string required

    Up to 200 characters

  • mime string required

    The file type, e.g. image/jpeg.

  • size integer required

    Bytes.

  • width integer or null

    Pixels, when known. Files uploaded through the API are measured when first opened in the app.

  • height integer or null
  • duration_ms integer or null

    Length of video and audio, when known.

  • url string or null

    A signed download URL, valid for about an hour.

  • folder_id string or null

    The folder it is filed in; null at the top level.

  • created_at integer required

    Epoch 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"
}'
Response 200
{
  "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
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

List media

GET /assets assets

Newest first.

Parameters

  • kind string query

    Only this kind.

    One of image, video, audio

  • q string query

    Search file names.

  • folder string query

    Only this folder, or root for the top level. Leave it out for the whole library.

  • limit integer query

    Page size, 1–200.

    1–200. Default 50

  • cursor string query

    The next_cursor of the previous page.

Responses

  • 200 A page of media.
  • 400 The request is invalid — details.field names 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)
  • items object[] required
    11 fields in items
    • id string required
    • kind string required

      One of image, video, audio

    • name string required

      Up to 200 characters

    • mime string required

      The file type, e.g. image/jpeg.

    • size integer required

      Bytes.

    • width integer or null

      Pixels, when known. Files uploaded through the API are measured when first opened in the app.

    • height integer or null
    • duration_ms integer or null

      Length of video and audio, when known.

    • url string or null

      A signed download URL, valid for about an hour.

    • folder_id string or null

      The folder it is filed in; null at the top level.

    • created_at integer required

      Epoch ms.

  • next_cursor string or null required

    Pass as cursor for the next page; null on the last page.

curl "https://www.wunderframe.com/api/v1/assets?limit=50" \
  -H "Authorization: Bearer $WUNDERFRAME_API_KEY"
Response 200
{
  "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
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}

Upload a file

POST /assets assets

Send 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.

Shell
curl -X POST "$BASE/assets" -H "Authorization: Bearer $KEY" \
  -H "Content-Type: image/jpeg" -H "X-Filename: backdrop.jpg" \
  --data-binary @backdrop.jpg

Parameters

  • folder string query

    File it in this folder. Omit for the top level.

  • X-Filename string header

    The 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.field names 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)
  • id string required
  • kind string required

    One of image, video, audio

  • name string required

    Up to 200 characters

  • mime string required

    The file type, e.g. image/jpeg.

  • size integer required

    Bytes.

  • width integer or null

    Pixels, when known. Files uploaded through the API are measured when first opened in the app.

  • height integer or null
  • duration_ms integer or null

    Length of video and audio, when known.

  • url string or null

    A signed download URL, valid for about an hour.

  • folder_id string or null

    The folder it is filed in; null at the top level.

  • created_at integer required

    Epoch 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
Response 201
{
  "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
Response 400
{
  "error": {
    "code": "invalid",
    "message": "The request is invalid — `details.field` names the field when there is one."
  }
}