The media library keeps files you want to post more than once: a brand intro, a product video, a set of photos. Files in the library are never deleted on their own. You post them by media_id, without uploading them again.
Files that are not in the library are temporary: an upload is deleted 7 days after the posts that use it finish, and an upload no post ever used is deleted after a day.
Add files
There are three ways to put a file in the library:
- Upload and keep it at once: Upload media with
save=true(and an optionaltitle). - Keep something already uploaded:
POST /v1/librarywith itsmedia_ids. - Import from a link:
POST /v1/library/importwith a Google Drive or Dropbox share link, or any public https link.
curl -X POST "https://api.reelspan.com/v1/media/upload?kind=video&save=true&title=Brand%20intro" \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "[email protected]"import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
const { media_id } = await reelspan.media.upload(
{ data: await readFile('launch.mp4'), name: 'launch.mp4', type: 'video/mp4' },
{ kind: 'video', save: true, title: 'Brand intro' },
);from reelspan import Reelspan
reelspan = Reelspan()
media_id = reelspan.media.upload("launch.mp4", kind="video", save=True, title="Brand intro")["media_id"]Keep an earlier upload
curl -X POST https://api.reelspan.com/v1/library \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"media_ids": ["med_4f2a…"], "title": "Brand intro"}'await reelspan.library.keep(['med_4f2a…'], 'Brand intro');reelspan.library.keep(["med_4f2a…"], title="Brand intro")Send 1 to 50 media_ids. A file that is already in the library only gets the new title.
Import from a link
curl -X POST https://api.reelspan.com/v1/library/import \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://drive.google.com/file/d/1AbC…/view?usp=sharing", "title": "Product demo"}'const { item } = await reelspan.library.import('https://drive.google.com/file/d/1AbC…/view?usp=sharing', 'Product demo');item = reelspan.library.import_url("https://drive.google.com/file/d/1AbC…/view?usp=sharing", title="Product demo")["item"]The link must be https. A Google Drive or Dropbox file must be shared as "anyone with the link". Reelspan copies the file in, so the link can change or go away afterwards. It takes videos, photos and PDFs: a video or PDF up to your plan's upload size, a photo up to 20 MB, as long as the library has room.
Post from the library
Use the media_id where a post takes an uploaded file:
video_media_idon Post a videophoto_media_ids[]on Post photosdocument_media_idon Post a document
curl -X POST https://api.reelspan.com/v1/posts/video \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=tiktok" \
-F "platform[]=youtube" \
-F "title=Meet the team" \
-F "video_media_id=med_4f2a…"await reelspan.posts.video({ user: 'my-brand', platforms: ['tiktok', 'youtube'], title: 'Meet the team', videoMediaId: 'med_4f2a…' });reelspan.posts.video("my-brand", ["tiktok", "youtube"], title="Meet the team", video_media_id="med_4f2a…")List the library
curl "https://api.reelspan.com/v1/library?kind=video&limit=20" \
-H "Authorization: Bearer $REELSPAN_API_KEY"const page = await reelspan.library.list({ kind: 'video', limit: 20 });page = reelspan.library.list(kind="video", limit=20){
"success": true,
"usage": { "used_bytes": 734003200, "limit_bytes": 26843545600, "items": 12 },
"items": [
{
"media_id": "med_4f2a…",
"kind": "video",
"title": "Brand intro",
"filename": "launch.mp4",
"content_type": "video/mp4",
"size_bytes": 48211022,
"duration_seconds": 31.5,
"width": 1080,
"height": 1920,
"saved_at": "2026-11-03T10:22:41.000Z",
"url": "https://…"
}
],
"next_before": "2026-11-03T10:22:41.000Z"
}- Newest first.
kindisvideo,photoordocument; leave it out for all. limitis 1 to 100 (default 48). When there are more, passnext_beforeasbeforeto get the next page; it isnullon the last page.- Each item's
urlis a link to the file that works for an hour. For a fresh one later, callGET /v1/library/{media_id}/file, which redirects (302) to a new link. duration_seconds,widthandheightarenullwhen they aren't known (always for PDFs).
Remove a file
curl -X DELETE https://api.reelspan.com/v1/library/med_4f2a… \
-H "Authorization: Bearer $REELSPAN_API_KEY"await reelspan.library.remove('med_4f2a…');reelspan.library.remove("med_4f2a…")Removing takes the file out of the library and frees its space. The file itself is deleted once no post waiting to go out uses it, so a scheduled post that uses it still publishes.
Storage per plan
Files in the library count against your plan's library space. Temporary uploads don't.
| Plan | Library space |
|---|---|
| Free | 1 GB |
| Starter | 25 GB |
| Pro | 100 GB |
| Agency | 250 GB |
| Scale | 500 GB |
usage in each answer shows the bytes used, your plan's limit and the number of files. When a file doesn't fit, the answer is 413 with error_code: LIBRARY_FULL and says how much space is left. See Plans and limits.
Errors
| Status | error_code |
When |
|---|---|---|
| 400 | varies | The import link couldn't be fetched or isn't a video, photo or PDF. The message says why. |
| 404 | MEDIA_NOT_FOUND |
No upload or library file with that media_id in your workspace. |
| 413 | LIBRARY_FULL |
Not enough library space left. |
| 413 | FILE_TOO_LARGE |
The imported file is over the size limit, or bigger than the space left. |
Listing and downloading need the read scope; adding, importing and removing need publish.