Skip to main content
The media library holds every image and video your workspace’s posts can use. Uploads happen directly to storage using a three-step flow — the file bytes never pass through the API itself.

How direct uploads work

1

Presign

Tell the API which files you want to upload (name, MIME type, size). It pre-creates a temporary media item for each and returns a short-lived, pre-signed upload URL.
2

Upload

PUT each file’s bytes straight to the returned upload_url, replaying the signed headers. This goes to storage, not to the PublishBuddy API.
3

Confirm

Tell the API which uploads finished. It verifies each object landed in storage, moves it into the workspace’s library, and marks it active.
Direct uploads replace the old POST /media_contents multipart endpoint, which has been removed from the public API. Uploading through the API is no longer supported — always use the presign → upload → confirm flow.

A single upload

1. Presign

Each entry needs a name and size (bytes); mime is optional but recommended. You can presign up to 10 files per request. Response — one PresignedMediaUploadResource per file:
The id is the temporary media item’s UUID — you’ll pass it back in the confirm step. The upload_url is valid for expires_in seconds (30 minutes).

2. Upload the bytes

PUT the file straight to upload_url, replaying every header from upload_headers exactly as returned:
This request goes to storage, not to api.publishbuddy.com. A 200/204 means the bytes are in place.

3. Confirm

Response — the finalized media objects, ready to attach to posts:
size, width, height, and time are detected asynchronously and may come back null immediately after confirm. Fetch the media item again a moment later (GET /media_contents/{mediaContent}) to read the resolved values.
Only UUIDs whose bytes actually landed in storage appear in data — a UUID you confirm without uploading is silently skipped rather than erroring.

Multiple files in one request

Presign and confirm both accept up to 10 items per request. Presign every file, PUT each one, then confirm them all together:
To place freshly uploaded files in a folder, update each one’s folder_id after confirming (see Organising with folders).

Bulk imports

For larger imports (hundreds or thousands of files), batch them in groups of 10 (the presign/confirm limit) and cap concurrency:
The media_contents endpoint group uses the throttle:api_1000_per_min rate limit, so a modest concurrency (8 or so) per token stays comfortably under it. Note the presign/confirm calls count against the API rate limit, but the PUT uploads go to storage and don’t.

Supported formats and limits

The maximum per-file size is 2 GB (declare the real byte count in the presign size field). Per-network and per-plan limits may be lower and are enforced at publish time. For very large files (long-form video), upload them once and reuse the same media_content_id across multiple posts.

Organising with folders

Folders are workspace-internal — they help your team find assets and don’t change anything that gets sent to the social network.
Move a file into a folder by updating its folder_id:

Filtering existing media

Combine folder_id with page and per_page (see Pagination) to walk large libraries.

Replacing a file

The binary attached to a media object is immutable. To “replace” an asset:
  1. Upload the new file (presign → upload → confirm gives you a new media_content_id).
  2. Update any scheduled (status: waiting) posts that reference the old ID — set their media_content_ids to include the new ID instead.
  3. Delete the old media object (optional — already-published posts hold their own reference).
Trying to mutate the file via PUT is intentionally not supported; this keeps the audit trail clean (“the post that went out on Dec 25 used exactly this asset”).

Deleting

Deletion is a soft delete — the file is hidden from listings and can no longer be attached to new posts, but any existing post that used it continues to work, including future scheduled publishes.