Does this video model take a last frame? Check /v1/videos/models first
Read supported_frame_images from GET /v1/videos/models before sending a first or last frame to Sume. A small Python guard that fails before any spend.

How do I know if a Sume video model accepts a last frame?
Read its entry in GET /v1/videos/models and look at supported_frame_images. A model that takes both ends lists first_frame and last_frame. One that lists only first_frame is image-to-video from an opening still. An empty list means the model takes no frame images at all.
This matters now that first-and-last-frame control is a headline feature. Google's Gemini Omni 1.1 Flash post lists first and last frame control, but other catalog models differ. A request with a capability the model lacks fails with 400 unsupported_capability, and it is cheaper to catch that before the call.
The list is a contract, not a hint. If a model reports first_frame only, do not send a last_frame and hope: the request is refused, and nothing is generated. Reading the descriptor is a free GET, so it costs less than one failed submit and tells you the allowed durations and resolutions at the same time.
Descriptor fields worth reading
| Field | Tells you | Use it to |
|---|---|---|
| supported_frame_images | first_frame, last_frame, or both | Gate a pinned opening or ending |
| supported_input_references | image_url, video_url, audio_url | Gate reference inputs by type |
| supported_durations | Allowed seconds | Clamp duration before submit |
| supported_resolutions | 480p, 720p and so on | Pick a resolution that exists |
| generate_audio | Whether audio can be toggled | Avoid sending a rejected flag |
A guard that runs before you spend
The pure function takes the parsed data list, so you can unit test it with a fixture. fetch_models is the only part that touches the network and needs your key.
import json, os, urllib.request
def frame_support(models: list, model_id: str) -> list:
for m in models:
if m["id"] == model_id:
return m.get("supported_frame_images") or []
raise KeyError(f"unknown model {model_id}")
def can_pin(models, model_id, first=True, last=False) -> bool:
have = frame_support(models, model_id)
return (not first or "first_frame" in have) and (not last or "last_frame" in have)
def fetch_models() -> list:
req = urllib.request.Request(
"https://api.sume.com/v1/videos/models",
headers={"x-api-key": os.environ["SUME_API_KEY"]},
)
with urllib.request.urlopen(req, timeout=15) as r:
return json.load(r)["data"]
demo = [{"id": "a", "supported_frame_images": ["first_frame", "last_frame"]},
{"id": "b", "supported_frame_images": ["first_frame"]}]
print(can_pin(demo, "a", last=True), can_pin(demo, "b", last=True))Sending the frames
Each frame goes in frame_images as {type: "image_url", image_url: {url}, frame_type: "first_frame" | "last_frame"}. If you also send input_references, the frame images win and the request is image-to-video, so use one field or the other. Keep every URL public HTTPS.
Call fetch_models once at startup, cache the list, and refresh it on deploy. The catalog is the source of truth for what each model accepts, and the cached copy keeps a hot path from adding a request to every submit.
A last frame is also a creative commitment. The model has to travel from the first still to the last one inside the clip length you chose, so pick two frames that a plausible camera move or action can connect, and give the prompt the verb that links them. Two unrelated stills tend to produce a cut or a morph rather than a shot, whichever model you use.
Sources
Related posts
More in Developers
- TTS then H3 Max lip sync: check the 5 to 14.8 s audio window
H3 Max lip sync takes 5 to 14.8 seconds of Sume-hosted audio and clips the rest. Measure a TTS line from its word timings and price it before you submit.
- CI smoke test for Ideogram 4.5 on Sume: one low-quality image
A bash and jq check that submits one 1K low-quality Ideogram 4.5 image, passes on 200 or 202, and explains 401, 402 and 429. List price is $0.03.
- Clamp video duration when swapping Sora for a Sume video model
Each Sume video id has its own seconds range, so old Sora code can ask for a length a model rejects. Clamp per id before you submit; Python table of limits.
- Claude Code MCP insufficient_scope: re-authenticate to grant write
Sume's hosted MCP starts read-only. If Claude Code pins oauth.scopes, add mcp:write, run /mcp and re-authenticate, or the new token still lacks write.
Written by Sume