Menu

API reference · Media Library

Items

media_library · items · 8 operations

GET/v1/media-library/items

List media library files

media_library.items.list

ReadIdempotentSince 2026-11-01

Lists the images, videos and documents (PDF, PowerPoint and Word, for LinkedIn document posts) of the organization's media library, newest first, paginated by cursor (limit up to 200). Filters: folder_id (files directly inside that folder, not in its subfolders), root_only=true (the files that are not in any folder), type (image, video or document), source (upload, ai_generated or edited), tag (exact) and search (text in the name or a tag, case-insensitive). Filters run on the pages read, so a page can bring fewer than limit while has_more is true: follow next_cursor. Each file comes with its storage_path (what crm.whatsapp.send_media and media_library.items.canvas_edit take; it keeps the folder where the file was uploaded, even after moving it), who uploaded it (uploaded_by and uploaded_by_name; null for old files that stored a marker) and canvas_element_count; the signed download links (download_url, valid for an hour, and thumbnail_download_url) only with include_download_url true, or with media_library.items.get. The editor's recipe is only in get. Needs view access to the Media Library.

Scope
media_library:read
Permission
View the module
MCP tool
media_library_items_listOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.list".

Declared cost: up to 601 reads and 0 writes per call (they count against the daily quota).

Parameters

limitintegerqueryoptional

Rows per page (1 to 200; default 50).

Default: 50

cursorstringqueryoptional

The next_cursor of the previous page, to continue the list; omit it for the first page.

folder_idstringqueryoptional

Only the files right inside this folder (from media_library.folders.list).

root_onlybooleanqueryoptional

Only the files that are in no folder.

typeenumqueryoptional

image, video or document (PDF, PowerPoint or Word).

Values: image, video, document

sourceenumqueryoptional

upload, ai_generated or edited (made with the canvas editor).

Values: upload, ai_generated, edited

tagstringqueryoptional

Only the files with this exact tag.

searchstringqueryoptional

Text in the name or in a tag (case does not matter).

include_download_urlbooleanqueryoptional

Also the signed download URLs of each file (download_url, thumbnail_download_url); default false: get one file with media_library.items.get to download it.

Response

dataarray<object>
has_moreboolean
next_cursorstring

Errors

Example

curl "https://api.mb-suite.com/v1/media-library/items" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl "https://api.mb-suite.com/v1/media-library/items" \
  -H "Authorization: Bearer $MB_TEST_KEY"
GET/v1/media-library/items/{item_id}

Get one media library file

media_library.items.get

ReadIdempotentSince 2026-11-01

Returns a file of the media library: name (original_name), type (image, video or document), size in bytes, width and height (images; a document's first page, in PDF points; duration for videos), page_count and document_flags for a document, folder, tags, source (upload, ai_generated or edited), who uploaded it (uploaded_by and uploaded_by_name; null for old files that stored a marker) and when, storage_path, and download_url (a signed link valid for an hour; null when the file is not stored in this organization's library). An image edited with the canvas editor also brings canvas_elements (the editable recipe), canvas_base and edited_from_id. Not found (media_item_not_found) if the id does not exist in this organization. Needs view access to the Media Library.

Scope
media_library:read
Permission
View the module
MCP tool
media_library_items_getOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.get".

Declared cost: up to 2 reads and 0 writes per call (they count against the daily quota).

Parameters

item_idstringpathrequired

The file's id (from media_library.items.list, or the item_id that media_library.items.create returns).

Response

idstring
original_namestring
typeenum

Values: image, video, document

uploaded_atnumber
filenamestring | null
sizenumber | null
folder_idstring | null
tagsarray<string> | null
sourcestring | null
storage_pathstring | null
thumbnail_storage_pathstring | null
widthnumber | null
heightnumber | null
durationnumber | null
page_countnumber | null

A document's pages (a PDF's; PowerPoint and Word files do not bring them).

document_flagsarray<string> | null

What was seen when the PDF was checked: encrypted (password-protected), layers, mixed_page_sizes (pages of different sizes) or unreadable.

uploaded_bystring | null

The uid of who uploaded it (null when unknown: old files stored a marker instead).

uploaded_by_namestring | null

The name of who uploaded it.

edited_from_idstring | null
canvas_element_countnumber | null
canvas_elementsarray<object> | null
canvas_baseobject | null
download_urlstring | null

A signed URL to download the file without a session (it expires at download_url_expires_at). In a list only with include_download_url true.

download_url_expires_atnumber | null
thumbnail_download_urlstring | null

Errors

Example

curl "https://api.mb-suite.com/v1/media-library/items/{item_id}" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl "https://api.mb-suite.com/v1/media-library/items/{item_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/media-library/items

Upload an image, video or document to the media library

media_library.items.create

WriteIdempotentSince 2026-11-01

Uploads (adds) an image, a video or a document to the media library, in one of two ways. In one call: send the file itself as content_base64 with content_type and name (up to 768000 bytes = 750 KB decoded, because the request body is capped at 1 MB). Or in two steps, for files of up to 1 GB (a document, up to 100 MB): call media_library.uploads.create, PUT the bytes to its upload_url with the headers it returns, then call this with its storage_path. Takes JPEG, PNG, WebP or GIF images, MP4, MOV or WebM videos, and PDF, PowerPoint (PPT, PPTX) or Word (DOC, DOCX) documents of up to 100 MB, LinkedIn's limit for document posts (type document; to use it in a social_planner post with format document, its master_media url is /api/v1/storage/resolve?key=<its storage_path, URL-encoded>). A file uploaded with media_library.uploads.create (and its thumbnail) already counted toward the storage quota when its URL was issued; a file sent inline checks that the organization's storage has room (otherwise 409 limit_reached, details.resource storage) and counts toward the quota from here on. Optional: folder_id, name (default: the uploaded file name), tags, width/height (read from the file for images up to 10 MB when missing; for a document, send its first page in PDF points), duration for a video, page_count for a document (send it: the server does not open documents; LinkedIn takes up to 300 pages and checks them when it processes the file), and thumbnail_storage_path for a video or a document (its first page, uploaded with purpose video_thumbnail or document_thumbnail). With public_url: true (images only) it also returns public_url, a signed link that works without a session for 30 days, or for public_url_expires_in_days (1 to 3650) when you send it, and public_url_expires_at (it always expires): for the body of an email or a web page; it stops working earlier when the file is deleted from storage (deleting through the API keeps the file 30 days in the trash first). Idempotent by file: the same storage_path, or the same content and name in the same folder, returns the file already there with created: false (public_url: true on it issues a new link, with the same expiry rule, for a file already in the library). The storage_path of a library file also works in crm.whatsapp.send_media (a PDF or a Word file as media_type document). Errors: storage_path_invalid, storage_object_not_found, unsupported_media_type (also public_url on a video or a document), file_too_large (a document over 100 MB, any other file over 1 GB), thumbnail_only_for_videos (a thumbnail on an image), thumbnail_path_invalid (also a thumbnail that another file already uses), media_folder_not_found, invalid_input (a folder_id that is a reserved storage folder name: thumbnails, booking_avatar). Needs full access to the Media Library.

Instructions for agents

If the upload URL expired before the PUT, ask for a new one with media_library.uploads.create; do not retry the registration with a path that was never uploaded. A public_url is public: share it only where the image is meant to be seen.

Scope
media_library:write
Permission
Edit in the module
MCP tool
media_library_items_createOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.create".
Events it can emit
media_library.item.created

Declared cost: up to 9 reads and 1 writes per call (they count against the daily quota).

Parameters

storage_pathstringbodyoptional

The storage_path media_library.uploads.create returned (the file already uploaded to its URL), or that of a file already in the library.

content_base64stringbodyoptional

The file itself in base64, up to 750 KB decoded: one step, without the signed upload URL (needs content_type and name).

content_typeenumbodyoptional

The type of the inline file (required with content_base64): image/jpeg, image/png, image/webp, image/gif, video/mp4, video/quicktime, video/webm, application/pdf, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document.

Values: image/jpeg, image/png, image/webp, image/gif, video/mp4, video/quicktime, video/webm, application/pdf, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document

folder_idstring | nullbodyoptional
namestringbodyoptional

The visible name; default: the uploaded file's name. Required with content_base64.

tagsarray<string>bodyoptional

Free-text tags (up to 50, 64 characters each).

widthintegerbodyoptional

Width in pixels; for images up to 10 MB it is read from the file when missing. For a document, its first page in PDF points (the server does not open documents).

heightintegerbodyoptional

Height in pixels; for images up to 10 MB it is read from the file when missing. For a document, its first page in PDF points (the server does not open documents).

durationnumberbodyoptional

A video's length, in seconds.

page_countintegerbodyoptional

A document's pages (the server does not open documents: send them). LinkedIn takes documents of up to 300 pages and checks them when it processes the file.

thumbnail_storage_pathstringbodyoptional

A video's thumbnail, or a document's first page: the storage_path of an upload made with purpose video_thumbnail or document_thumbnail.

public_urlbooleanbodyoptional

Also return a public URL (no session) of the image, for an email body or a page. Images only; it expires in 30 days unless public_url_expires_in_days says otherwise.

public_url_expires_in_daysintegerbodyoptional

How many days that public URL lasts (1 to 3650; default 30). It always expires.

Response

item_idstring
createdboolean
itemobject
public_urlstring
public_url_expires_atnumber | null

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/media-library/items" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/media-library/items" \
  -H "Authorization: Bearer $MB_TEST_KEY"
PATCH/v1/media-library/items/{item_id}

Rename, tag or move a file

media_library.items.update

WriteIdempotentSince 2026-11-01

Changes a media library file: name (the visible name; control characters and slashes are removed), tags (replaces the whole list) and folder_id to move it to another folder (null takes it out of every folder). The file itself does not change. Unknown fields are rejected; an unknown folder fails with media_folder_not_found. Returns the updated file. To move many files at once use media_library.items.bulk.move. Needs full access to the Media Library.

Scope
media_library:write
Permission
Edit in the module
MCP tool
media_library_items_updateOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.update".

Declared cost: up to 2 reads and 1 writes per call (they count against the daily quota).

Parameters

item_idstringpathrequired

The file's id (from media_library.items.list, or the item_id that media_library.items.create returns).

updatesobjectbodyrequired

The fields to change (at least one).

Response

itemobject

Errors

Example

curl -X PATCH "https://api.mb-suite.com/v1/media-library/items/{item_id}" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "updates": {}
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X PATCH "https://api.mb-suite.com/v1/media-library/items/{item_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "updates": {}
}'
POST/v1/media-library/items/bulk/move

Move many files to a folder

media_library.items.bulk.move

WriteBulk · up to 200IdempotentSince 2026-11-01

Moves up to 200 media library files to one folder (folder_id; null takes them out of every folder), like dragging a selection in the app. Files already there count as unchanged; ids that do not exist are skipped and returned in not_found. Outside the app it requires a dry run (which lists what moves) and a confirm_token. Needs full access to the Media Library.

Needs confirmation: first dry_run: true (preview and confirm_token, valid 10 minutes and for one run), then the same body with confirm_token. In a few operations only with certain data: the description says when. Why and how: Dry run and confirm_token.

Scope
media_library:write
Permission
Edit in the module
MCP tool
media_library_items_bulk_moveOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.bulk.move".

Declared cost: up to 202 reads and 200 writes per call (they count against the daily quota).

Parameters

item_idsarray<string>bodyrequired

The files' ids (1 to 200), from media_library.items.list.

folder_idstring | nullbodyrequired

Response

movednumber
unchangednumber
not_foundarray<string>

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/media-library/items/bulk/move" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "folder_id": "FOLDER_ID",
  "dry_run": true
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/media-library/items/bulk/move" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "folder_id": "FOLDER_ID",
  "dry_run": true
}'
DELETE/v1/media-library/items/{item_id}

Delete a media library file

media_library.items.delete

IrreversibleSince 2026-11-01

Deletes a file from the media library. It goes to the 30-day trash, where an owner or admin can restore it (platform.trash.restore); the stored file is kept meanwhile (and keeps counting toward the storage quota) so the restore brings it back intact, and it is deleted from storage when the trash item is purged or expires. Posts, ads or emails that already used the image keep their own copy. Outside the app it needs a dry run and a confirm_token, except a REST DELETE with a key allowed to delete. Needs full access to the Media Library.

With an API key, this DELETE runs directly: the record stays 30 days in the trash and the response carries its trash_item_id. With an OAuth token, and through the MCP, it needs dry_run → confirm_token.

Scope
media_library:write and “Allow deletions” (media_library:delete in OAuth)
Permission
Edit in the module
MCP tool
media_library_items_deleteOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.delete".
Events it can emit
media_library.item.deleted

Declared cost: up to 1 reads and 1 writes per call (they count against the daily quota).

Parameters

item_idstringpathrequired

The file's id (from media_library.items.list, or the item_id that media_library.items.create returns).

Response

oktrue
trash_item_idstring

The trash item this deletion left: the item_id of platform.trash.restore (POST /trash/{item_id}/restore). Missing if nothing went to the trash.

trash_item_idsarray<string>

Only when the deletion left more than one copy: all of them, the first being trash_item_id.

trash_expires_atnumber

When the copy leaves the trash for good (epoch ms): 30 days after the deletion.

Errors

Example

curl -X DELETE "https://api.mb-suite.com/v1/media-library/items/{item_id}" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X DELETE "https://api.mb-suite.com/v1/media-library/items/{item_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/media-library/items/bulk/delete

Delete many media library files

media_library.items.bulk.delete

IrreversibleBulk · up to 200Since 2026-11-01

Deletes up to 200 media library files; each one goes to the 30-day trash and can be restored on its own (the stored files are kept meanwhile). Ids that do not exist are skipped and returned in not_found. Outside the app it requires a dry run (which lists what will be deleted) and a confirm_token. Needs full access to the Media Library.

Needs confirmation: first dry_run: true (preview and confirm_token, valid 10 minutes and for one run), then the same body with confirm_token. In a few operations only with certain data: the description says when. Why and how: Dry run and confirm_token.

Scope
media_library:write and “Allow deletions” (media_library:delete in OAuth)
Permission
Edit in the module
MCP tool
media_library_items_bulk_deleteOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.bulk.delete".
Events it can emit
media_library.item.deleted

Declared cost: up to 200 reads and 200 writes per call (they count against the daily quota).

Parameters

item_idsarray<string>bodyrequired

The files' ids (1 to 200), from media_library.items.list.

Response

deletednumber
not_foundarray<string>
trash_item_idsarray<string>

The trash items this deletion left, one per record: the item_id of platform.trash.restore (POST /trash/{item_id}/restore).

trash_expires_atnumber

When the copy leaves the trash for good (epoch ms): 30 days after the deletion.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/media-library/items/bulk/delete" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "dry_run": true
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/media-library/items/bulk/delete" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "dry_run": true
}'
POST/v1/media-library/items/{item_id}/canvas-edit

Edit an image with the canvas editor

media_library.items.canvas_edit

WriteSince 2026-11-01

Composes elements on top of a library image with the canvas editor (no AI, no credits). Editing an original never touches it: it creates a new image in the same folder (source edited, edited_from_id, named new_name or "<name> (edited)") that keeps the recipe, so it can be edited again; editing that derived image updates it in place with a new file (mode created or updated in the result). elements (1 to 20) are positioned in fractions of the image (x_frac, y_frac, width_frac). Through the API the practical ones are type logo (asset logo, logo_dark or logo_icon: the organization's brand logos) and type image (image.storage_path of a file in this organization's library, image.natural_ratio = width / height); text, cta and shape need a raster rendered by the app's editor (raster.storage_path), so they are only practical from the app. Errors: not_an_image, canvas_base_too_large (base over 25 MB), canvas_base_missing or canvas_base_deleted, canvas_elements_invalid, canvas_composition_failed, limit_reached (details.resource storage: the storage is full), role_required (viewers and portal clients), rate_limited (20 per minute per person). Needs full access to the Media Library.

Instructions for agents

Tell the person whether a new image was created (mode created, with its name) or an edited image was updated, and that the original is untouched.

Scope
media_library:write
Permission
Edit in the module
MCP tool
media_library_items_canvas_editOn the full surface; on the compact one, mb_execute_operation with id: "media_library.items.canvas_edit".

Declared cost: up to 8 reads and 2 writes per call (they count against the daily quota).

Parameters

item_idstringpathrequired

The file's id (from media_library.items.list, or the item_id that media_library.items.create returns).

elementsarray<object>bodyrequired

The elements to compose on the image (1 to 20), as the canvas editor saves them: id, type (logo, image, text, cta or shape), x_frac, y_frac and width_frac (fractions of the image, 0 to 1), and per type: asset for a logo; image.storage_path (a file of this library) and image.natural_ratio (width / height) for an image; text, cta and shape also need raster.storage_path (a raster rendered by the app's editor).

new_namestringbodyoptional

The name of the new derived image (only when editing an original); default: the original's name plus ' (edited)' in the caller's language (' (editada)' in Spanish and Portuguese).

Response

itemobject
modeenum

Values: created, updated

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/media-library/items/{item_id}/canvas-edit" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "elements": []
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/media-library/items/{item_id}/canvas-edit" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "elements": []
}'