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:
  • Generate up to 4 images or videos in parallel
  • Avoid long-lived HTTP connections
  • Build progress-tracking UIs

Workflow

1. POST /ai/queue                       → Get generation IDs
2. GET  /ai/queue  or  /ai/queue/:id    → Poll until done
3. Results accessible via URLs in your account

Enqueue: POST /api/ai/queue

Submit an async image or video generation job.

Request Parameters

ParameterTypeRequiredDefaultDescription
modelstringyesMust be an image or video model. Text-only models are rejected.
promptstringone ofText prompt. Use this or multi_prompt for video models.
num_generationsintegerno1How many generations to run in parallel. Range: 1-4.
target_namespacestringnoyour usernameNamespace to store results and bill to.
seedintegernoRandom seed for reproducibility.
aspect_ratiostringnoAspect ratio (e.g. "16:9", "1:1").
durationintegernoVideo duration in seconds.
All other model-specific parameters are passed through (e.g. multi_prompt, input_image, generate_audio, response_format, etc.).

Response

{
  "generations": [
    {"generation_id": "bb8f5eb7-361e-4e13-ab73-67457bc8057e", "status": "processing"},
    {"generation_id": "e9bede09-cd0e-46cf-bbcd-cb1a50099351", "status": "processing"}
  ]
}

Validation

The API validates at enqueue time that:
  • The model exists and has image or video output capability
  • 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 fails silently (it disappears from the queue without producing a result). To validate parameters and get immediate error feedback, use /ai/images/generate or /ai/videos/generate instead.

List Generations: GET /api/ai/queue

Lists all in-progress generations. Only actively-processing generations are returned; completed, failed, or cancelled generations are not retained.

Query Parameters

ParameterTypeRequiredDescription
namespacestringnoNamespace to query. Defaults to the authenticated user.
modelstringnoFilter by model name.

Response (jobs in progress)

{
  "count": 2,
  "generations": [
    {
      "generation_id": "7cf9b23a-1234-5678-9abc-def012345678",
      "model": "kling-video-o3-pro-reference-to-video",
      "prompt": "An astronaut walking on Mars",
      "media_type": "video",
      "enqueued_at": 1775091431,
      "aspect_ratio": "16:9",
      "duration": 10
    },
    {
      "generation_id": "bb8f5eb7-361e-4e13-ab73-67457bc8057e",
      "model": "black-forest-labs-flux-2-klein-4b",
      "prompt": "Abstract geometric pattern in blue and gold",
      "media_type": "image",
      "enqueued_at": 1775091440
    }
  ]
}
FieldAlways PresentDescription
countyesNumber of in-progress generations
generation_idyesUnique ID for this generation
modelyesModel name
promptyesText prompt
media_typeyes"image" or "video"
enqueued_atyesUnix timestamp when the job was enqueued
seedif submittedRandom seed
aspect_ratioif submittedAspect ratio
durationif submittedVideo duration

Response (all jobs complete)

{
  "count": 0,
  "generations": []
}

How Completion Works

When a generation finishes, it is removed from the queue. There is no “completed” status on this endpoint. Generations are either in the list (still processing) or gone (done). Poll until count reaches 0.

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.
  • Generations expire after 24 hours regardless of completion.

Get Generation: GET /api/ai/queue/:generation_id

Retrieves metadata for a single in-progress generation.

Path Parameters

ParameterTypeRequiredDescription
generation_idstring (UUID)yesThe generation ID returned by the enqueue endpoint.

Response (in progress)

{
  "generation_id": "7cf9b23a-1234-5678-9abc-def012345678",
  "model": "kling-video-o3-pro-reference-to-video",
  "prompt": "An astronaut walking on Mars",
  "media_type": "video",
  "enqueued_at": 1775091431,
  "aspect_ratio": "16:9",
  "duration": 10
}

Response (completed or not found)

Returns 404 when the generation has reached a terminal state (completed, failed, cancelled, or expired after 24h):
{
  "error": {
    "type": "resource_not_found",
    "title": "The requested resource could not be found"
  },
  "status": "error"
}

Cancel Generation: DELETE /api/ai/queue/:generation_id

Cancels a queued or in-progress generation.

Path Parameters

ParameterTypeRequiredDescription
generation_idstring (UUID)yesThe generation ID to cancel.

Response (success)

{
  "status": "success",
  "generation_id": "bb8f5eb7-361e-4e13-ab73-67457bc8057e"
}

Response (already completed or not found)

Returns 404:
{
  "error": {
    "type": "resource_not_found",
    "title": "The requested resource could not be found"
  },
  "status": "error"
}
You can only cancel generations that are still processing. Once a generation completes and leaves the queue, the DELETE endpoint returns 404.

Examples

Batch image generation with polling

import requests
import time

API_KEY = "YOUR_API_KEY"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

# Enqueue 4 images
response = requests.post(
    "https://hub.oxen.ai/api/ai/queue",
    headers=HEADERS,
    json={
        "model": "black-forest-labs-flux-2-klein-4b",
        "prompt": "Abstract geometric pattern in blue and gold",
        "num_generations": 4,
    },
)
generations = response.json()["generations"]
print(f"Enqueued {len(generations)} generations")

# Poll until done
while True:
    status = requests.get(
        "https://hub.oxen.ai/api/ai/queue",
        headers=HEADERS,
        params={"model": "black-forest-labs-flux-2-klein-4b"},
    ).json()
    print(f"Remaining: {status['count']}")
    if status["count"] == 0:
        break
    time.sleep(5)

print("All images generated!")

Async video generation

import requests

response = requests.post(
    "https://hub.oxen.ai/api/ai/queue",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "kling-video-o3-pro-reference-to-video",
        "multi_prompt": [
            {"prompt": "Aerial view of waves crashing on a rocky shore", "duration": 5},
            {"prompt": "Camera pulls back to reveal the full coastline", "duration": 5},
        ],
        "aspect_ratio": "16:9",
    },
)

print(response.json())

Poll a single generation by ID

import requests
import time

API_KEY = "YOUR_API_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# After enqueuing, grab a generation ID
generation_id = "bb8f5eb7-361e-4e13-ab73-67457bc8057e"

while True:
    resp = requests.get(
        f"https://hub.oxen.ai/api/ai/queue/{generation_id}",
        headers=HEADERS,
    )
    if resp.status_code == 404:
        print("Generation complete (or cancelled/expired)")
        break
    print(f"Still processing: {resp.json()['model']}")
    time.sleep(10)

Errors

ConditionError
num_generations out of range"num_generations must be an integer between 1 and 4"
Model not found"Model not found: <name>"
Text-only model":unsupported_media_type"
404 on GET/DELETEGeneration completed, cancelled, expired, or doesn’t exist