Skip to main content

Why Use the Async Queue

The synchronous endpoints (/ai/images/generate, /ai/videos/generate) block until the result is ready. For video generation, this can be 1-10+ minutes. The async queue returns immediately with generation IDs so you can:
  • Run many generations in parallel (up to 4 per request, no limit on total queued)
  • Avoid long-lived HTTP connections
  • Build progress-tracking UIs
  • Query completed generations and their output URLs at any time

Workflow

Generations persist after reaching a terminal state (succeeded, failed, or cancelled), and you can fetch them at any time. See Output Files for more information about where the outputs are saved. A Server-Sent Events stream at GET /api/events can also deliver completion notifications with the output file URL. See Completion Events.

Enqueue

Submit an async image or video generation job.

Required Parameters

Additional Parameters

All other parameters (e.g. prompt, multi_prompt, input_image, input_video, aspect_ratio, duration, seed, generate_audio) are passed through to the model. Consult the model’s request_schema via GET /api/ai/models/:id for supported parameters and their constraints.

Response

Validation

The API validates at enqueue time that:
  • The model exists and produces image, video, or audio output
  • num_generations is 1-4
  • The user is authenticated with sufficient credits
Model-specific parameter validation (prompt content, duration ranges, aspect ratio values) happens when the generation runs, not at enqueue time. If a parameter is invalid, the generation transitions to failed status with an error_message. To validate parameters and get immediate error feedback, use /ai/images/generate or /ai/videos/generate instead.

Billing an Organization

A generation bills the target namespace and saves its file there. That’s your own account unless you pass target_namespace. Pass an organization’s name to use its credits and storage with your own API key, as long as you’re an admin or editor of that organization. Only the organization’s balance counts, and a request fails with a 402 when the organization is out of credit, even if your own account has plenty.

Output Files

A generation writes its output file into a repository in the target namespace. The repository is playground unless you pass target_repo, and it’s created the first time it’s used. The file goes at the repository’s root unless you pass target_directory. The workbench also saves your uploads and generations to playground. Give an application its own target_repo to keep its files separate. result_url is a signed link to that file which expires after one hour. Get Generation and List Generations sign it again on every call, which means you can keep the generation_id and fetch a fresh link whenever you need the file. The url in a completion event is signed when the generation completes and expires an hour later.

List Generations

Lists generations for the authenticated user’s namespace. By default, only active generations (queued or processing) are returned. Pass an explicit status filter to include terminal states.

Query Parameters

Response

Any additional parameters from the original enqueue request (e.g. seed, aspect_ratio, duration, input_image) are included in the response alongside the fields above.

Polling Strategy

  • Image generation (FLUX, etc.): typically completes in 5-30 seconds. Poll every 2-5 seconds.
  • Video generation (Kling, etc.): typically takes 1-5 minutes. Poll every 10-30 seconds.
Poll until every generation’s status is a terminal value (succeeded, failed, or cancelled), or until count reaches 0 when using the default active-only filter.

Get Generation

Retrieves metadata for a single generation. Includes result_url when the generation has succeeded and error_message when it has failed.

Path Parameters

Response (in progress)

Response (succeeded)

Response (failed)

Response (not found)

Returns 404 when the generation ID does not exist:

Cancel Generation

Cancels a queued or in-progress generation.

Path Parameters

Response (success)

Response (not found)

Returns 404 when the generation ID does not exist:
You can only cancel generations that are still active (queued or processing). Cancelling a generation that has already reached a terminal state (succeeded, failed, or cancelled) has no effect.

Completion Events

Server-Sent Events stream that emits media_generation_completed events when generations reach a terminal state.

Connect

Response is Content-Type: text/event-stream. The server sends : keep-alive\n\n every 15 seconds when idle. Events are broadcast to currently-connected subscribers with no buffering. Anything that fires before you connect is lost. Subscribe before calling POST /ai/queue to avoid missing events.

Event: media_generation_completed

Fires once per generation on terminal state. Success wire format:
Failure:

Fields

Other events on this stream

GET /api/events is a user-scoped stream that may carry unrelated event types (e.g. deployment events). Filter on the event: line and ignore anything other than media_generation_completed.

Example

Cancellation

Cancelling a generation fires the same event with status: "cancelled":
A cancelled event carries only the identifying fields, so branch on status when you handle one.

Sessions

A session groups related generations, such as one task, one agent run, or one storyboard. Each session appears as a tab in the workbench. Sessions belong to you and to one repository, which is the target_repo your generations write to (playground by default). Another user can’t add to your sessions or read them. Workbench session tabs named Locations, Cars, and People

Default session

A generation sent without workbench_session_id goes into your default session. Your default session is the first one you create on a repository, so if you never pass a session ID, all of your generations land in that first session. To be precise, a generation with no session ID isn’t tagged with any session. Reads filtered to your default session also return your untagged generations, which is why they appear there. This has two consequences:
  • Untagged generations appear in whichever session is your default when you read them, including generations you made before you created any session.
  • If you delete your default session, the next session you create becomes the default and the untagged generations move to it.
To keep an agent’s work separate from everything else, create a session for it and pass that session’s ID on every request.

Session lifecycle

All session endpoints are scoped to a repository:
The optional JSON payload on create and update is yours to use. A session has no name field, so store a label or any other metadata in payload (up to 1 MB). A PATCH replaces the whole payload rather than merging into it. A session object looks like this:
default is true on the session that untagged generations appear in. Create returns it under workbench_session, and list returns an array under workbench_sessions.

Example: group an agent’s work into a session

Create a session, pass its ID when you enqueue, read the session’s generations back, and delete the session when the task is done.

Rules

  • The session must be on the target repository. Create the session on the same target_namespace/target_repo you enqueue into. If workbench_session_id names a session that doesn’t exist, has been deleted, is on a different repository, or belongs to someone else, POST /ai/queue returns 422 with code workbench_session_invalid.
  • Filter history by session to see a session’s generations. GET /ai/queue has no session filter. Use filter[workbench_session_id] on the repository’s workbench/history endpoint. Get Generation does return workbench_session_id for a tagged generation, along with the other request parameters.
  • Deleting a session keeps its generations. The generations and output files stay in the repository and still carry the session ID. They no longer appear under any tab.

Examples

Batch image generation with polling

Async video generation

Poll a single generation by ID

End-to-end: enqueue, wait for SSE, download

Python

Errors