Reelspan posts to X with the X API v2. You send the post once; Reelspan uploads the media in chunks, waits for X to process it, and posts it. Text longer than 280 characters becomes a thread.
What you can post
| Post | How | Notes |
|---|---|---|
| Video post | POST /v1/posts/video |
One video per post |
| Photo post | POST /v1/posts/photos |
Up to 4 photos or GIFs |
| Text post | POST /v1/posts/text |
|
| Thread | Any of the above with long text | Split at 280 characters |
Reelspan handles for you:
- Threads. Text over 280 characters is split into posts of up to 280, on paragraph breaks first, then lines, then words. The first post carries the media; each next post replies to the one before.
- Chunked upload of videos and images, then a wait while X processes them (up to 10 minutes).
- Link removal. X charges far more for a post that contains a link, so Reelspan removes links unless you keep them (see below).
Connect the account
X connects with an OAuth sign-in: in the dashboard go to Accounts → X, or send a white-label connect link. Any X account works.
Example
A video post where only accounts you follow can reply:
curl -X POST https://api.reelspan.com/v1/posts/video \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=x" \
-F "x_title=Shipping day. Here's the 30-second tour." \
-F "reply_settings=following" \
-F "[email protected]"import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
const post = await reelspan.posts.video({
user: 'my-brand',
platforms: ['x'],
video: { data: await readFile('launch.mp4'), name: 'launch.mp4', type: 'video/mp4' },
extra: { x_title: "Shipping day. Here's the 30-second tour.", reply_settings: 'following' },
});from reelspan import Reelspan
reelspan = Reelspan()
post = reelspan.posts.video(
"my-brand", ["x"], "launch.mp4",
extra={"x_title": "Shipping day. Here's the 30-second tour.", "reply_settings": "following"},
)Fields
| Field | Type | Values | What it does |
|---|---|---|---|
x_title |
string | any length | The post text. Falls back to title. Over 280 characters it becomes a thread. |
x_keep_links |
boolean | default false |
Keep links in the text. Uses your plan's monthly allowance of X posts with links. |
x_long_text_as_post |
boolean | default false |
Post long text as one post instead of a thread. Needs X Premium on the account. |
reply_settings |
string | following, mentionedUsers, subscribers, verified |
Who can reply. Leave it out for everyone; other values are ignored. |
reply_to_id |
string | a post id | Posts this as a reply to that post. x_reply_to_id works too. |
exclude_reply_user_ids |
list | user ids | With reply_to_id: leaves these users out of the reply's mentions. |
quote_tweet_id |
string | a post id | Quotes that post. x_quote_tweet_id works too. |
poll_options |
list | 2 to 4 options, up to 25 characters each | Adds a poll. x_poll_options works too. Polls can't have media (see below). |
poll_duration |
number | minutes, 5 to 10080 (7 days), default 1440 | How long the poll stays open. x_poll_duration works too. |
poll_reply_settings |
string | following, mentionedUsers, subscribers, verified |
Who can reply to the poll post. |
tagged_user_ids |
list | up to 10 user ids | Tags these users in the photos or video. Ignored on a post without media. |
geo_place_id |
string | an X place id | Attaches a place. |
for_super_followers_only |
boolean | default false |
Only the account's subscribers can see it. |
community_id |
string | an X Community id | Posts into that Community. |
share_with_followers |
boolean | default false |
With community_id: also shows the post to the account's followers. |
card_uri |
string | an X card URI | Attaches a card. |
direct_message_deep_link |
string | an X DM link | Adds a button that opens a direct message. |
nullcast |
boolean | default false |
Posts without showing it on the timeline (a promoted-only post). |
x_alt_text |
string or list | up to 1,000 characters each | Photo alt text: one for every photo, or one per photo in order. Falls back to alt_text. |
x_first_comment |
string | up to 280 characters | A reply posted under the new post. Falls back to first_comment. |
List fields (poll_options, tagged_user_ids, exclude_reply_user_ids) can be sent as repeated fields, a JSON array, or one comma-separated string.
A poll
curl -X POST https://api.reelspan.com/v1/posts/text \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user": "my-brand",
"platform": ["x"],
"title": "Which should we build next?",
"poll_options": ["Dark mode", "CSV export", "Zapier app"],
"poll_duration": "4320"
}'X takes polls only on posts without media: on a video or photo post the poll is left out and the result carries a warning. Fewer than 2 or more than 4 options, an option over 25 characters, or a duration outside 5 to 10080 minutes fails the post with invalid_poll.
Links in X posts
X bills about $0.20 for a post with a link, against about $0.015 without. So by default Reelspan removes http:// and https:// links from the text and adds a warning to the result.
Send x_keep_links=true to keep them. Each such post uses one of your plan's X link posts for the month (see Plans and limits). When the allowance is used up, the links are removed as usual. The same check runs when you edit a scheduled post or retry one.
Limits
- Post: 280 characters (counted as people see them: an emoji is one). Longer text becomes a thread, or one long post with
x_long_text_as_postand X Premium. - Media per post: one video, or up to 4 photos and GIFs. With more photos, the first 4 are used and the result says so.
- Video size: your plan's upload limit (see Plans and limits).
- Shapes: 16:9 or 1:1 work best.
Good to know
- A thread that stops halfway keeps the posts already made: the result is a success with a warning saying where it stopped.
- Result extras:
media_id(andmedia_idsfor several photos), andpost_idsfor a thread, in order. - Alt text: if X refuses the alt text for an image, the post still goes out with a warning.
- First comment: posted as a reply to the new post.
- Analytics: followers, following, posts and likes for the account; impressions, likes, reposts, replies, quotes and saves per post.
After posting
- Delete a post with Unpublish.
- Edit its text with Edit a post. X allows edits only on accounts with X Premium, within an hour of posting and up to five times. An edit makes a new post id: the answer gives it as
post_id, withprevious_post_idandedit_history_post_ids. Links are removed from the new text unlessfields.x_keep_linksistrue, as when posting. - Repost any public post from the account with Repost. X counts reposts against the account's daily write limit.
Errors
error_code |
What happened | What to do |
|---|---|---|
x_payment_required |
The X API account behind Reelspan is out of credits | Contact Reelspan support. |
x_rate_limited |
X's rate limit was hit | Reelspan retries it later. |
x_media_failed |
X couldn't process the video or image | Read error; check the file and post again. |
x_processing_timeout |
X took more than 10 minutes to process the media | Reelspan retries it. |
x_error |
X refused the post (for example a duplicate post) | Read error for X's message. |
invalid_poll |
The poll options or duration are out of range | Send 2 to 4 options of up to 25 characters and a duration of 5 to 10080 minutes. |
reauth_required |
The sign-in expired or was revoked | Reconnect X. |