RawFrame

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" }
}
  • model and prompt are required. Model ids are provider-family/name; see Models.
  • params uses 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 with invalid_parameters and param naming the field, before anything is charged. Omitted params take the model's default.
  • mode is optional. It's inferred from references: a first_frame makes it image_to_video, a source_image makes it image_edit, and so on. Without references it's the model's text mode.
  • references attach media by upload_id (Uploads) or by public HTTPS url.
  • metadata holds up to 16 string values of your own. It's returned on the generation, in webhooks and in usage exports.
  • provider_options passes provider-specific settings through, at most 8 KB. They can't override the model, prompt, references or params.

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

StatusMeaning
queuedAccepted and waiting. Canceling now is always free.
submittingBeing sent to the provider.
runningThe provider is working. Progress may be reported.
finalizingCopying outputs to our storage.
succeededDone. outputs has the files and charge_micros the charge.
failedDidn't produce a result. error says why. Not charged.
canceledCanceled 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.

On this page