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.

4 min readSume
All posts

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.

CreatePostsMedia in the X OpenAPI document (read 2026-10-02)
FieldWhat the spec says
media_ids1-4 ids to attach
preview_media_idMedia whose asset is the preview image
titleTitle rendered on the Post card for video
descriptionDescription rendered on the Post card for video
call_to_actionsvisit_site, watch_now or app_install
embeddableAsset URLs do not expire; syndicated playback allowed
tagged_user_idsUp 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

All Integrations posts

Written by Sume