A post sent with scheduled_date, add_to_queue or repeat_every waits here until its time, under a job_id. Until a minute before it goes out you can read it, edit it, or cancel it.
List what's scheduled
curl "https://api.reelspan.com/v1/scheduled?profile_username=my-brand" \
-H "Authorization: Bearer $REELSPAN_API_KEY"import { Reelspan } from 'reelspan';
const reelspan = new Reelspan();
const { scheduled_posts, total } = await reelspan.scheduled.list({ profile_username: 'my-brand' });from reelspan import Reelspan
reelspan = Reelspan()
page = reelspan.scheduled.list(profile_username="my-brand"){
"scheduled_posts": [
{
"job_id": "sched_5d0e8c1a7b3f49e2a6c4d8b0",
"request_id": "2f8a6c4e0b1d4f7a9c3e5b7d1a0c2e4f",
"scheduled_date": "2026-12-01T09:00:00.000Z",
"original_timezone": "Europe/London",
"post_type": "video",
"profile_username": "my-brand",
"platforms": ["tiktok", "youtube"],
"title": "Launch day",
"description": null,
"external_id": null,
"queued": false,
"caption": null,
"platform_content": {
"tiktok": { "title": "Launch day", "description": null },
"youtube": { "title": "Launch day, in 60 seconds", "description": null }
},
"fields": {
"user": "my-brand",
"platform[]": ["tiktok", "youtube"],
"title": "Launch day",
"youtube_title": "Launch day, in 60 seconds",
"scheduled_date": "2026-12-01T09:00:00",
"timezone": "Europe/London"
},
"has_cover": false,
"has_preview": true,
"thumbnail_url": "https://api.reelspan.com/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0/thumbnail",
"preview_url": "https://api.reelspan.com/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0/preview",
"editable": true,
"repeat": null,
"approval": null
}
],
"total": 1,
"limit": 50,
"offset": 0
}Posts come soonest first. Filter with profile_username, and with from and to (date-times with an offset; to not included). Page with limit (1 to 200, default 50) and offset.
Each post shows:
scheduled_datein UTC, andoriginal_timezone, the zone it was scheduled in.post_type:video,photo,textordocument.caption: the same asdescription(Upload-Post's name for it).platform_content: the title and description each network will get.fields: every field the post was sent with.has_cover: whether a video post has its own cover image.has_preview: whether the post has media to preview.thumbnail_urlandpreview_url: links to the thumbnail and preview endpoints, ornullwhen the post has no media (a text post has no thumbnail). They are API links, so call them with your key.queued:truewhen it took a queue slot.editable:falseonce it is less than a minute from its time.repeat: for one post of a repeating series, itsseries_id, itsindex, how manytimesand how often (every).approval: when it is in an approval link, the link's id and the client's answer (pending,approvedorchanges, with their comment).
Read one
GET /v1/scheduled/{job_id} returns the same fields plus status and form (the same as fields):
const post = await reelspan.scheduled.get('sched_5d0e8c1a7b3f49e2a6c4d8b0');
console.log(post.form.privacy_level);post = reelspan.scheduled.get("sched_5d0e8c1a7b3f49e2a6c4d8b0")
print(post["form"].get("privacy_level"))See the media
Two endpoints show what a scheduled post will publish, for a calendar or a review screen.
GET /v1/scheduled/{job_id}/thumbnail gives a small JPEG, 480 px wide: a frame of the video, or the cover or first photo. It answers with a 302 redirect to a signed link valid for an hour; the request itself needs your key, the signed link doesn't. Add ?format=json to get the link instead, for example to put in an <img> tag:
curl "https://api.reelspan.com/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0/thumbnail?format=json" -H "Authorization: Bearer $REELSPAN_API_KEY"const { thumbnail_url } = await reelspan.request('GET', '/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0/thumbnail', { query: { format: 'json' } });thumb = reelspan.request("GET", "/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0/thumbnail", query={"format": "json"}){ "success": true, "thumbnail_url": "https://…", "expires_in": 3600 }The first request makes the image, so it can take a few seconds. A text post, or one with no media, gets 404 NO_MEDIA; when no image can be made from the media, the answer is 404 THUMBNAIL_UNAVAILABLE.
GET /v1/scheduled/{job_id}/preview lists every file the post will publish, each with a signed link valid for an hour:
{
"success": true,
"job_id": "sched_5d0e8c1a7b3f49e2a6c4d8b0",
"expires_in": 3600,
"media": [
{ "role": "video", "media_id": "med_…", "kind": "video", "content_type": "video/mp4", "size_bytes": 18350212, "url": "https://…" },
{ "role": "cover", "media_id": "med_…", "kind": "photo", "content_type": "image/jpeg", "size_bytes": 241337, "url": "https://…" }
]
}role is video, photo, document, cover, thumbnail, or <network>_photo for photos sent to one network only.
Reschedule or edit
PATCH /v1/scheduled/{job_id} changes the time, the text, any setting and a video's cover. Send only what changes:
| Field | What it does |
|---|---|
scheduled_date |
The new time, ISO 8601, at least a minute ahead and within 365 days. |
timezone |
The zone scheduled_date is in. Defaults to the zone the post was scheduled in. |
title, description |
The caption and the longer text. caption is another name for description. |
platform_content |
Text for one network: { "tiktok": { "title": "…" } } sets tiktok_title, description sets tiktok_description. null removes one, so the network falls back to the overall text. Naming a network the post doesn't go to gets 400. |
fields |
Any other post field, such as { "youtube_title": "…", "privacy_level": "SELF_ONLY" }. null removes one. |
cover_image_url, cover_image_base64, cover_media_id |
A new cover for a video post (JPEG, PNG or WebP, up to 20 MB): a public https URL, base64 (a data: prefix is fine), or an image uploaded with kind=photo. |
remove_cover |
true removes the cover, so the networks pick a frame themselves. |
Send at most one of the four cover fields; more gets 400. Covers are for video posts only: on a photo, text or document post the answer is 400.
curl -X PATCH https://api.reelspan.com/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0 \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"scheduled_date": "2026-12-02T18:30:00",
"timezone": "Europe/London",
"fields": { "youtube_title": "Launch day, one day late", "tiktok_title": null }
}'await reelspan.scheduled.edit('sched_5d0e8c1a7b3f49e2a6c4d8b0', {
scheduled_date: '2026-12-02T18:30:00',
timezone: 'Europe/London',
fields: { youtube_title: 'Launch day, one day late', tiktok_title: null },
});reelspan.scheduled.edit(
"sched_5d0e8c1a7b3f49e2a6c4d8b0",
scheduled_date="2026-12-02T18:30:00",
timezone="Europe/London",
fields={"youtube_title": "Launch day, one day late", "tiktok_title": None},
)To change only the TikTok caption and the cover:
curl -X PATCH https://api.reelspan.com/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0 -H "Authorization: Bearer $REELSPAN_API_KEY" -H "Content-Type: application/json" -d '{
"platform_content": { "tiktok": { "title": "Launch day 🚀 #launch" } },
"cover_image_url": "https://example.com/launch-cover.jpg"
}'await reelspan.request('PATCH', '/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0', {
json: {
platform_content: { tiktok: { title: 'Launch day 🚀 #launch' } },
cover_image_url: 'https://example.com/launch-cover.jpg',
},
});reelspan.scheduled.edit(
"sched_5d0e8c1a7b3f49e2a6c4d8b0",
platform_content={"tiktok": {"title": "Launch day 🚀 #launch"}},
cover_image_url="https://example.com/launch-cover.jpg",
)The answer is the updated post. Some things are fixed once a post is scheduled:
- The profile, the networks and the video or photos can't change. Sending
user,platform[],video,photos[]orrequest_idinfieldsgets 400. To change them, cancel the post and make a new one. - A queued post that you give a
scheduled_dateleaves the queue and keeps that exact time. - Editing a post that is in an approval link sends it back to the client for approval.
Cancel
DELETE /v1/scheduled/{job_id} cancels the post, and the upload credits it reserved come back.
curl -X DELETE https://api.reelspan.com/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0 \
-H "Authorization: Bearer $REELSPAN_API_KEY"await reelspan.scheduled.cancel('sched_5d0e8c1a7b3f49e2a6c4d8b0');reelspan.scheduled.cancel("sched_5d0e8c1a7b3f49e2a6c4d8b0"){ "success": true, "message": "Job sched_5d0e8c1a7b3f49e2a6c4d8b0 cancelled and assets deleted.", "credits_refunded": 2 }credits_refunded is the number of networks given back (0 for a test post, which never took any). The post's networks show as skipped in History, with the error code cancelled.
Cancel the rest of a series
Each post of a repeating series is its own scheduled post with its own job_id, so you can edit or cancel one without touching the others. To stop the series from one post onwards, add series=rest: that post and every later one still waiting are cancelled.
curl -X DELETE "https://api.reelspan.com/v1/scheduled/sched_5d0e8c1a7b3f49e2a6c4d8b0?series=rest" \
-H "Authorization: Bearer $REELSPAN_API_KEY"await reelspan.scheduled.cancel('sched_5d0e8c1a7b3f49e2a6c4d8b0', { withLaterRepeats: true });reelspan.scheduled.cancel("sched_5d0e8c1a7b3f49e2a6c4d8b0", with_later_repeats=True){ "success": true, "message": "4 posts of the series cancelled.", "credits_refunded": 8, "cancelled": 4 }Earlier posts of the series are left alone, and so is any that is already publishing or due within a minute. On a post that isn't part of a series, series=rest cancels just that post.
Too late to change
Once a post is publishing, or is less than a minute from its time, an edit or a cancel gets 409 with error_code: "scheduled_post_in_progress". Check editable first if you are close to the time. A post still waiting for a client's approval is the exception: it can be edited or cancelled even after its time has passed.
An unknown job_id, or one of a profile your key can't use, gets 404.