Email-sized preview image from an avatar clip: video-frames max_edge

Pull the first frame of a Sume avatar clip as a 600-pixel jpeg for an email or a link card: one video-frames call with at [0] and max_edge 600.

4 min readSume
All posts

Call POST /v1/video-frames with at: [0], format: "jpeg" and max_edge: 600 to get the first frame of a Sume avatar clip clamped to 600 pixels on its long edge, a size that fits an email or a link card. max_edge accepts 16 to 2160; leave it out and you get the source frame size.

Everything here is from Sume's video frames guide, read 2026-10-04. The route needs a media.sume.com clip your workspace owns, takes one of at[] or fps, and returns durable image artifacts, so the still stays available after the request.

The three fields that matter

video-frames fields for a thumbnail (read 2026-10-04)
FieldValue for a thumbnailRange
at[0]1 to 24 instants, each at least 0 and below the clip length
formatjpeg (default)jpeg or png
max_edge60016 to 2160, long edge

The request

Submit returns 202; poll the GET until resource_status is ready, then read frames[0].url. Use a stable Idempotency-Key so a retry does not queue a second extract.

import json, os, time, urllib.request

KEY = os.environ['SUME_API_KEY']
H = {'Authorization': 'Bearer ' + KEY, 'Content-Type': 'application/json'}

def call(url, body=None, extra=None):
    headers = dict(H, **(extra or {}))
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(url, data=data, headers=headers, method='POST' if body is not None else 'GET')
    with urllib.request.urlopen(req) as r:
        return json.load(r)

sub = call('https://api.sume.com/v1/video-frames',
           {'video_url': os.environ['SUME_VIDEO_URL'], 'at': [0], 'format': 'jpeg', 'max_edge': 600},
           {'Idempotency-Key': 'thumb-001'})
rid = sub['request_id']
while True:
    res = call('https://api.sume.com/v1/video-frames/' + rid)
    vf = res.get('video_frames', res)
    if vf.get('resource_status') == 'ready':
        print(vf['frames'][0]['url'])
        break
    time.sleep(2)

Checks before you send

One instant can fail on its own: its url comes back null and the job still succeeds, so test for None before you put the image in an email. Add the real clip link as the click target, and say in the surrounding text that the presenter is AI-generated.

Frames or inspect?

Use video-frames for a specific instant at a size you choose. Use video inspect when you want the probe facts and a grid of sampled stills; its default max_edge is 768.

Sources

Related posts

More in Media tools

All Media tools posts

Written by Sume