A video can reach Reelspan three ways: in the post request itself, as a public URL Reelspan downloads, or uploaded first and referred to by media_id. For anything over 100 MB, upload it first with a direct upload: the file goes straight to storage in parts, and the post request stays small.
Size limits
| Plan | Largest video |
|---|---|
| Free | 0.5 GB |
| Starter | 1 GB |
| Pro | 2 GB |
| Agency | 4 GB |
| Scale | 8 GB |
The plan limit applies to videos however they arrive (file, URL or direct upload). Other files have fixed limits: photos up to 20 MB each and PDF documents up to 100 MB. A file over the limit is refused with 413 and error_code: FILE_TOO_LARGE.
Separately, a single request sent to the API can carry at most 100 MB, so a file bigger than that must use a direct upload (or a URL). Each network also has its own limits, checked when Reelspan publishes there; see Video requirements.
With the SDKs: nothing to do
The Node.js and Python SDKs switch to a direct upload on their own for files of 90 MB or more, upload the parts three at a time with retries per part, then post with the resulting media_id. You pass the file as usual:
import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
await reelspan.posts.video({
user: 'my-brand',
platforms: ['youtube'],
title: 'Full keynote',
video: { data: await readFile('keynote.mp4'), name: 'keynote.mp4', type: 'video/mp4' },
});from reelspan import Reelspan
reelspan = Reelspan()
reelspan.posts.video("my-brand", ["youtube"], "keynote.mp4", "Full keynote")To upload once and post later (or several times), call media.upload and keep the media_id. It takes an onProgress (Node) / on_progress (Python) callback for a progress bar:
const media = await reelspan.media.upload(
{ data: await readFile('keynote.mp4'), name: 'keynote.mp4', type: 'video/mp4' },
{ kind: 'video', onProgress: (sent, total) => console.log(`${Math.round((sent / total) * 100)}%`) },
);
await reelspan.posts.video({ user: 'my-brand', platforms: ['youtube'], title: 'Full keynote', videoMediaId: media.media_id });media = reelspan.media.upload("keynote.mp4", kind="video", on_progress=lambda sent, total: print(f"{sent * 100 // total}%"))
reelspan.posts.video("my-brand", ["youtube"], title="Full keynote", video_media_id=media["media_id"])The 90 MB threshold can be changed with directUploadBytes (Node) or direct_upload_bytes (Python) when you create the client.
Direct upload by hand
Three steps: start, send the parts, complete.
1. Start
Tell Reelspan the kind and size of the file. It checks the size against your plan and answers with one signed URL per part.
curl -X POST https://api.reelspan.com/v1/media/uploads \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"kind": "video", "size_bytes": 734003200, "filename": "keynote.mp4"}'{
"success": true,
"kind": "video",
"media_id": "med_…",
"part_size": 8388608,
"parts": [
{ "part_number": 1, "url": "https://…" },
{ "part_number": 2, "url": "https://…" }
],
"expires_in": 3600
}Parts are at least 8 MB, and there are never more than 1,000 of them. The part URLs are valid for an hour (expires_in, in seconds), and an upload that is not completed within a day is forgotten.
2. Send the parts
PUT each part's bytes to its URL: part n is the bytes from (n - 1) × part_size, part_size long (the last part is whatever is left). Each URL is signed for its part's exact length, so a body of any other size is refused. Keep the ETag header of every response.
# part 1 of a file split with: split -b 8388608 -d keynote.mp4 part_
curl -X PUT --upload-file part_00 "$PART_1_URL" -D - | grep -i etagParts can go in parallel and in any order. If one fails, send that part again to the same URL.
3. Complete
Send every part number with its ETag. Reelspan then reads the stored file's real size and first bytes, refuses it if it is not the kind you declared or is over your limit, and returns the media_id ready to use.
curl -X POST https://api.reelspan.com/v1/media/uploads/med_…/complete \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"parts": [{"part_number": 1, "etag": "\"9b2cf5…\""}, {"part_number": 2, "etag": "\"41d8cd…\""}]}'{ "success": true, "media_id": "med_…", "kind": "video", "content_type": "video/mp4", "size_bytes": 734003200, "duration_seconds": 1834.2 }Then post it with video_media_id (or photo_media_ids[] for photos, document_media_id for a PDF):
curl -X POST https://api.reelspan.com/v1/posts/video \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=youtube" \
-F "title=Full keynote" \
-F "video_media_id=med_…"To give up on an upload part-way, POST /v1/media/uploads/{media_id}/abort discards the parts already sent.
| Error | When |
|---|---|
FILE_TOO_LARGE (413) |
size_bytes, or the stored file, is over your plan's limit. |
EMPTY_FILE (400) |
size_bytes is missing or zero, or nothing was stored. |
PARTS_REQUIRED (400) |
The complete call had no valid parts. |
UNSUPPORTED_MEDIA / WRONG_MEDIA_KIND (400) |
The stored file isn't a supported type, or isn't the kind you declared. |
UPLOAD_NOT_FOUND (404) |
The media_id is unknown or the upload expired. Start again. |
Small files: one request
Under 100 MB you can send the file in the post itself ([email protected]), or upload it once with POST /v1/media/upload (a multipart field named file, and ?kind=video, photo or document) to get a media_id. See Upload media.
Public URLs, Google Drive and Dropbox
Any video, photos[] or document value can be a public https:// URL instead of a file. Reelspan downloads it before the post is accepted, so the same size limits apply and a failed download refuses the request with URL_FETCH_FAILED.
- Only
https://URLs are fetched, with up to three redirects. Addresses on private networks are refused. - Google Drive share links (
drive.google.com/file/d/…anddrive.google.com/open?id=…) and Dropbox share links are turned into direct downloads for you. The file must be shared so that anyone with the link can open it. - One request can fetch at most 100 media URLs in total (
TOO_MANY_MEDIA_URLS).
Posting the same large video to several profiles, or again later? Upload it once and reuse the
media_id. Media that no post uses is deleted after a day, and the media of a finished post after a retention period, unless you keep it in the media library.