X API video posts: preview_media_id, title and call_to_actions
The X API create-post media object takes preview_media_id, title, description and call_to_actions. A poster frame from Sume video-frames fills the preview.

The X API create-post media object accepts more than media_ids: a preview_media_id for the preview image, a title and description rendered on the Post card for video, call_to_actions, an embeddable flag and up to 10 tagged_user_ids. A poster frame pulled with Sume's video-frames can serve as the preview image once you upload it to X as its own media.
What fields does the media object hold?
The schema requires media_ids (1-4 numeric strings) and marks everything else optional. preview_media_id is the media id whose asset is used as the preview image. embeddable, when true, means the media's asset URLs do not expire and external syndicated playback is allowed.
| Field | What the spec says |
|---|---|
| media_ids | 1-4 ids to attach |
| preview_media_id | Media whose asset is the preview image |
| title | Title rendered on the Post card for video |
| description | Description rendered on the Post card for video |
| call_to_actions | visit_site, watch_now or app_install |
| embeddable | Asset URLs do not expire; syndicated playback allowed |
| tagged_user_ids | Up to 10 user ids |
How do I build the preview image?
Extract a few stills with POST /v1/video-frames, choose the best, upload that file to X as a separate image, and pass its id as preview_media_id. Use format: "jpeg" and a max_edge that suits the card. The extract returns frames[{t,url,width,height}] when ready.
import json, os, urllib.request
body = {
"video_url": "https://media.sume.com/artifacts/artf_demo/talk.mp4",
"at": [
1,
3,
5
],
"format": "jpeg",
"max_edge": 1280
}
req = urllib.request.Request(
"https://api.sume.com/v1/video-frames",
data=json.dumps(body).encode(),
headers={
"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": "x-preview-001",
},
method="POST",
)
print(urllib.request.urlopen(req).read().decode())What about the call-to-action?
The spec lists three CTA shapes: visit_site, watch_now and app_install. The spec describes the watch-now variant with an HTTPS URL, and says an app_install CTA needs at least one store id. Treat the CTA as part of the post design, and verify the exact nested field names in the live spec before coding, since only the top-level shape is summarised here.
What should I verify?
Run a test post on a throwaway account and look at the card. The video frames guide covers the Sume side.
Sources
Related posts
More in Integrations
- YouTube channelBanners.insert: 6 MB JPEG or PNG limit for AI banners
YouTube's channelBanners.insert accepts a JPEG or PNG up to 6 MB (6291456 bytes). Generate a banner with Sume Images and keep the file under the cap.
- YouTube Data API containsSyntheticMedia: set it on videos.insert
YouTube Data API v3 VideoStatus has containsSyntheticMedia, a boolean for altered or synthetic media. Where to set it and how to trim a Sume clip first.
- YouTube playlistImages API: 50 MB cover images from an AI image
YouTube's playlistImages insert and update accept a JPEG or PNG up to 50 MB (52428800 bytes). Make a cover with Sume Images; the spec gives no pixel size.
- YouTube watermarks.set: 10 MB JPEG or PNG for channel branding
The YouTube Data API watermarks.set method uploads a JPEG or PNG up to 10 MB as a channel watermark. Generate a transparent PNG logo mark with Sume Images.
Written by Sume