Manage media
Everything you upload or import lives in your workspace's media library. To add files, see Upload media; this page covers the rest.
Register a presigned upload
Files uploaded straight to storage with a presigned PUT (POST /v0/media/presign) aren't in
the library until you register them. POST /v0/media/register records the uploaded object in
place — no copy — and returns its media record; calling it again for the same key returns
the same record.
curl -X POST https://api.schedulin.app/v0/media/register \ -H "x-api-key: $SCHEDULIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "<your-org>/launch.mp4", "name": "launch.mp4" }'
const media = await client.media.register({ key: "<your-org>/launch.mp4" });
media = client.media.register(key="<your-org>/launch.mp4")
From the CLI: schedulin media register <key>. See
Upload media for the full presign → PUT → register flow.
Collect files from someone's device
When the file is on a user's phone or laptop (or pasted into a chat with your AI agent), create an upload link and hand it to them. The link opens a Schedulin page where they can drop files straight into your media library — no API key needed on their side.
curl -X POST https://api.schedulin.app/v0/media/upload-link \ -H "x-api-key: $SCHEDULIN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "expiresInHours": 24 }'
{ "url": "https://…/upload/…", "expiresAt": "2026-06-02T15:00:00.000Z" }
const link = await client.media.createUploadLink({ expiresInHours: 24 }); console.log(link.url);
link = client.media.create_upload_link(expires_in_hours=24) print(link.url)
expiresInHours defaults to 24 (max 168, one week). Once the user says they're done, list
media to find the new files and use their url in a post.
List and search media
GET /v0/media is paginated (page, limit up to 100) and returns the most recently
updated items first. Filter with q (file name), type (image, video, or all), and
tagIds. See Pagination.
curl "https://api.schedulin.app/v0/media?q=launch&type=image&limit=20" \ -H "x-api-key: $SCHEDULIN_API_KEY"
const { items, totalPages } = await client.media.list({ q: "launch", type: "image", limit: 20 });
page = client.media.list(q="launch", type="image", limit=20) for item in page.items: print(item.id, item.url)
Fetch a single item with GET /v0/media/{id} (client.media.retrieve).
Delete media
curl -X DELETE https://api.schedulin.app/v0/media/6f0c… \ -H "x-api-key: $SCHEDULIN_API_KEY"
Deleting removes the media record and the file from storage. Copies already cached by the CDN may still be served from the old URL for a short while after the delete. Don't rely on the URL going dead immediately.
Media that is still attached to a post can't be deleted — the API returns 409 Conflict;
remove it from those posts (or delete them) first.
Update media
PUT /v0/media/{id} updates a record's metadata (url, mimeType, width, height,
size, duration) and returns the updated media record.