Video Frames
Sample still frames out of a video so a model can SEE what was generated (uncharged).
Closes the loop the generate verbs leave open: generate → sample frames → judge them against
the brief → regenerate or accept. Frames come back inline as JPEG data URLs, the way
POST /v1/canvases/{ref}/screenshot returns page captures — nothing is stored in the team’s
library and nothing is charged.
Omit timestamps_ms for an even survey across the clip (first and last frame always
included). Supply it — off the duration_ms a previous call reported — to look closely at
one moment instead.
Best-effort by contract: a codec Moda cannot read returns frames: [] with a
no_frames_decoded warning. That means “we could not look”, NOT “the video is bad” — do not
regenerate on it.
Authorizations
API key from Settings > Developer > REST API
Headers
Calendar-dated API version pin. New integrations should pin 2026-05-01 to opt into the newest response shapes. For back-compat the server also accepts requests with no header and resolves them to the current default (today: 2026-04-12); that default advances on each sunset date. Any unsupported value returns 400 unsupported_version.
2026-04-12, 2026-05-01 "2026-05-01"
Body
The video to look at: a file_ id from an upload or a generate-video result.
^file_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$"file_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
Frames to sample evenly across the clip, first and last always included (default 4). Mutually exclusive with timestamps_ms — supplying both is rejected.
1 <= x <= 8Exact moments to sample instead of an even survey — read them off the duration_ms a previous call reported. Out-of-range values clamp to the clip rather than failing, and duplicates collapse. Mutually exclusive with count: the list is its own count, so supplying both is rejected rather than silently honouring one.
1 - 8 elementsResponse
Successful Response
The response is of type Response Mediavideoframes · object.