Generations
The lifecycle of a generation, and three ways to learn when it's done.
Every generation is asynchronous, image or video. POST /v1/generations validates the request, reserves
its maximum price, queues it and returns 202 straight away. The work happens in the background.
The request
{
"model": "bytedance/seedance-2.5",
"prompt": "A paper boat drifting down a rain-soaked city gutter",
"params": { "duration_seconds": 5, "aspect_ratio": "16:9", "resolution": "720p" },
"references": [{ "role": "first_frame", "upload_id": "upl_01jbx9w6k3f8..." }],
"metadata": { "order_id": "1234" }
}modelandpromptare required. Model ids areprovider-family/name; see Models.paramsuses the same names for every model. Each model accepts a subset of values, listed on its page. Values a model doesn't support are rejected withinvalid_parametersandparamnaming the field, before anything is charged. Omitted params take the model's default.modeis optional. It's inferred fromreferences: afirst_framemakes itimage_to_video, asource_imagemakes itimage_edit, and so on. Without references it's the model's text mode.referencesattach media byupload_id(Uploads) or by public HTTPSurl.metadataholds up to 16 string values of your own. It's returned on the generation, in webhooks and in usage exports.provider_optionspasses provider-specific settings through, at most 8 KB. They can't override the model, prompt, references orparams.
webhook_url is in the spec but not available yet. Requests that set it are rejected with
feature_not_available. To fall back to other models when one is down, see Fallback routing.
Statuses
| Status | Meaning |
|---|---|
queued | Accepted and waiting. Canceling now is always free. |
submitting | Being sent to the provider. |
running | The provider is working. Progress may be reported. |
finalizing | Copying outputs to our storage. |
succeeded | Done. outputs has the files and charge_micros the charge. |
failed | Didn't produce a result. error says why. Not charged. |
canceled | Canceled before it finished (Canceling). |
The last three are terminal: a generation never changes after reaching one. Temporary provider problems (rate limits, outages) are retried for you before a generation fails.
Waiting for the result
Poll. GET /v1/generations/{id} returns the current state. Every two to five seconds is plenty. The
SDK helpers do this for you and throw if the generation fails:
const video = await rf.generations.waitForCompletion(generation.id, { timeoutMs: 10 * 60_000 });Stream. GET /v1/generations/{id}/events is a Server-Sent Events stream. The first event is the
current state, then one event per change (status, progress), and the stream closes after the
terminal event. Each data: line is a JSON object with type, an optional progress from 0 to 1,
and the full generation.
import { RawFrame } from "@rawframe/sdk";
const rf = new RawFrame();
const generation = await rf.generations.create({
model: "bytedance/seedance-2.5",
prompt: "Timelapse of clouds rolling over a mountain ridge",
});
// The first event is the current state; the stream ends after the terminal event.
for await (const event of rf.generations.stream(generation.id)) {
const progress = event.progress === undefined ? "" : ` ${Math.round(event.progress * 100)}%`;
console.log(`${event.type}: ${event.generation.status}${progress}`);
}Webhooks. Register an endpoint once, and we POST a signed event when each generation succeeds,
fails or is canceled. Best for long videos and for backends that shouldn't hold connections open. See
Webhooks.
Outputs
A succeeded generation has one entry in outputs per file, with kind, content_type, size_bytes,
dimensions, and for video duration_seconds and has_audio. url is a signed link that expires at
url_expires_at, an hour after it was issued. Fetch the generation again for a fresh link. Files are
kept until expires_at (30 days by default), then deleted. Download anything you want to keep.
Canceling
POST /v1/generations/{id}/cancel cancels a generation that hasn't finished. While it's queued it's
canceled immediately at no charge. After that, the request is recorded and the generation stops at its
next status check; whether that costs anything depends on the model's cancel policy, shown on its page.
Canceling a finished generation fails with 409 generation_finished.
Listing
GET /v1/generations lists your organization's generations, newest first, filtered by status or
model. Pages hold up to 100 (limit, default 20). When has_more is true, pass next_cursor as
cursor to get the next page. The SDKs' iterate() does this for you.