First-frame image for /v1/videos: public HTTPS only, no signed URLs
Image and video inputs to Sume generation must be fetchable public HTTPS URLs. Localhost, private IPs, signed URLs and wrong content types are rejected.

Give Sume a first-frame or reference image as a public HTTPS URL. For the launch media fields, the Media inputs page says input URLs must be fetchable public HTTPS URLs and that the API rejects localhost, private-network, non-HTTPS and signed or private URLs, and mismatched content types, before the job is created. A pre-signed bucket link will not work there. There is no upload step for normal requests.
That rule is written for the launch media fields in Media inputs. For /v1/videos, which takes frame_images and input_references, the Video generation troubleshooting asks that all reference images be available over public HTTPS and in supported formats, so treat the same rule as the safe one.
Preflight, then submit
A HEAD request catches the three mistakes you control: scheme, redirect to a login page, and wrong content type. Use supported_frame_images from GET /v1/videos/models to know whether a model takes first_frame, last_frame, or both.
import os, requests
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
def check(url):
if not url.startswith("https://"):
raise ValueError("not https: " + url)
r = requests.head(url, allow_redirects=True, timeout=10)
if not r.ok or not r.headers.get("content-type", "").startswith("image/"):
raise ValueError("not a fetchable image: %s %s" % (r.status_code, url))
first = "https://example.com/first-frame.png"
check(first)
body = {
"model": "seedance-2",
"prompt": "The character walks into the forest",
"frame_images": [{"type": "image_url", "image_url": {"url": first},
"frame_type": "first_frame"}],
"resolution": "720p",
}
r = requests.post("https://api.sume.com/v1/videos", json=body, headers=H, timeout=30)
print(r.status_code, r.json())Which field does what
| Field | Mode | Entry shape |
|---|---|---|
frame_images | Image to video | frame_type of first_frame or last_frame |
input_references | Reference to video | Style or content guides, not exact frames |
| Both sent | Image to video | frame_images wins |
When the fetch still fails
Errors such as image_not_fetchable or input_media_unreachable mean Sume could not fetch or mirror the media safely. Make sure the URL is public HTTPS, then retry with the same idempotency key, or send the request_id to support.
Making inputs reliable
Host reference images on a stable public address that does not redirect to a login page and does not expire within the job's runtime. Sume fetches and mirrors the media, so a link that works for your browser session but not for an anonymous client will fail at the fetch.
- Serve the right
content-type; a PNG labelled asapplication/octet-streamis a mismatch. - Avoid short-lived presigned URLs, which the API treats as signed or private.
- Store outputs by their media.sume.com URL, not the input URL, once the job completes.
Sources
Related posts
More in Developers
- Fix one sentence in a 30-minute narration: 1 cent plus a re-render
Re-recording a 180-character sentence is 1 cent of Sume TTS. Swapping it into a 30-minute Timeline spine means a $3.00 re-render. Read model_id and voice first.
- 40 claimed Shorts, 40 trims to 59 seconds: $0.80 with a Python loop
Cut 40 claimed Shorts to 59 seconds with Sume Video trim at $0.02 each, $0.80 in total, using a Python loop with one Idempotency-Key per clip.
- Four music variants in parallel: Python asyncio, one key per take
Submit four Music Router jobs at once from Python with one Idempotency-Key each, poll status concurrently, and pay 4 x $0.125 = $0.50. Code that runs.
- Free plan accepts 6 paid jobs: submit 7 and read queue_full
Free allows 1 processing job and 5 queued, so 6 are accepted. A Python script submits 7 in parallel and prints which are accepted and which get 429 queue_full.
Written by Sume