Animate a still by API: first-frame jobs on Sume

fal lists FLUX 3 as animating one still into video. On Sume you send the still as a first frame to a video model; this Python script submits and polls.

4 min readSume
All posts

To animate one still image through the Sume API, send it as a first_frame in frame_images on POST /v1/videos with a model that lists first_frame in supported_frame_images, such as seedance-2. The fal model list describes FLUX 3 from Black Forest Labs as animating a single still image into video; I did not read the FLUX 3 API, so this post covers only the Sume side.

How the two descriptions line up

If both frame_images and input_references are sent, frame_images wins and the request is treated as image-to-video. Reference images guide style and do not fix a frame.

Still-to-video (read 2026-10-03)
SourceWhat it says
falNewest-video list includes FLUX 3 from Black Forest Labs, described as animating a single still image into video
Sumeframe_images with frame_type first_frame (and optionally last_frame) selects image-to-video

Submit and poll in Python

The script below wraps everything in main and calls it with asyncio.run. It submits with an Idempotency-Key, polls the polling URL every 15 seconds, and prints the first download URL. The image URL must be a public HTTPS URL. Video jobs usually take between 30 seconds and several minutes, so allow time.

Each model advertises its own durations and resolutions in GET /v1/videos/models, so read them before you pin values.

import asyncio, os, uuid
import requests

BASE = 'https://api.sume.com/v1/videos'
H = {'Authorization': f"Bearer {os.environ['SUME_API_KEY']}", 'Content-Type': 'application/json'}

async def main():
    body = {
        'model': 'seedance-2',
        'prompt': 'Gentle camera drift; keep the product locked in frame',
        'frame_images': [{
            'type': 'image_url',
            'image_url': {'url': 'https://example.com/first-frame.png'},
            'frame_type': 'first_frame',
        }],
        'resolution': '720p',
    }
    r = requests.post(BASE, headers={**H, 'Idempotency-Key': str(uuid.uuid4())}, json=body)
    r.raise_for_status()
    job = r.json()
    while True:
        await asyncio.sleep(15)
        s = requests.get(job['polling_url'], headers=H).json()
        if s['status'] == 'completed':
            print(s['unsigned_urls'][0])
            return
        if s['status'] in ('failed', 'cancelled'):
            raise SystemExit(s.get('error', s['status']))

asyncio.run(main())

Practical notes

  • Use a first frame that already has the composition you want; the model animates from it.
  • For a start and end pair, add a second frame_images entry with frame_type last_frame, on models that list it.
  • Download from unsigned_urls with your key, or use the content endpoint, and store the Sume URL.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume