Skip to main content
The Queue API is the primary way to process videos with the Swift SDK. Submit jobs that are processed asynchronously in the background, then poll for status and retrieve results when complete.
All video processing (video editing, restyling, motion control) uses the Queue API. For image editing, use the Process API.

Overview

The Queue API is accessed via client.queue and provides four main methods:
  • submit() - Submit a job and get a job ID immediately
  • status() - Check the status of a submitted job
  • result() - Retrieve the completed video
  • submitAndPoll() - Submit and automatically poll until completion

Submit a Job

Submit a video editing job and receive a job ID immediately:
import Foundation
import DecartSDK

let videoData = try Data(contentsOf: videoURL)
let input = try VideoEditInput(
    prompt: "Transform into anime style",
    data: .video(data: videoData)
)

let job = try await client.queue.submit(model: .lucy_2_v2v, input: input)

print("Job ID: \(job.jobId)")
print("Status: \(job.status)")  // .pending
Returns:
  • jobId - Unique identifier for the job
  • status - Initial status (.pending)

Check Job Status

Poll the status of a submitted job:
let status = try await client.queue.status(jobId: job.jobId)

print("Status: \(status.status)")  // .pending, .processing, .completed, or .failed
Status Values:
StatusDescription
.pendingJob is queued, waiting to be processed
.processingJob is currently being processed
.completedJob finished successfully
.failedJob failed or timed out

Get Job Result

Retrieve the video data once the job is completed:
let status = try await client.queue.status(jobId: job.jobId)

if status.status == .completed {
    let videoData = try await client.queue.result(jobId: job.jobId)
    try videoData.write(to: outputURL)
}
Returns: Data — the raw video bytes

Submit and Poll

The easiest way to use the Queue API — submit a job and automatically poll until completion:
let videoData = try Data(contentsOf: videoURL)
let input = try VideoEditInput(
    prompt: "Transform into anime style",
    data: .video(data: videoData)
)

let result = try await client.queue.submitAndPoll(
    model: .lucy_2_v2v,
    input: input
) { status in
    print("Status: \(status.status)")
}

switch result {
case .completed(let jobId, let data):
    try data.write(to: outputURL)
    print("Video saved!")
case .failed(let jobId, let error):
    print("Failed: \(error)")
}
Parameters:
  • model (required) - Video model from Models.video()
  • input (required) - Typed input for the model
  • onStatusChange (optional) - Closure called on each status change
Returns: QueueJobResult
  • .completed(jobId: String, data: Data) - Video data on success
  • .failed(jobId: String, error: String) - Error message on failure

Video Editing

Transform videos with prompt and optional reference image using lucy_2_v2v:
let input = try VideoEditInput(
    prompt: "Convert to anime style with vibrant colors",
    data: .video(data: videoData),
    referenceImage: .image(data: refImageData),  // optional
    resolution: .res720p
)

let result = try await client.queue.submitAndPoll(
    model: .lucy_2_v2v,
    input: input
)
VideoEditInput parameters:
  • prompt (required) - Text description of the transformation
  • data (required) - Input video as FileInput
  • referenceImage (optional) - Reference image as FileInput
  • seed (optional) - Random seed for reproducible results
  • resolution (optional) - Output resolution (.res720p or .res480p)
  • enhancePrompt (optional) - Auto-enhance the prompt

Video Restyling

Restyle videos using either a text prompt or a reference image (but not both) with lucy_restyle_v2v:
// Option A: With text prompt
let promptInput = try VideoRestyleInput(
    prompt: "Studio Ghibli style",
    data: .video(data: videoData)
)

// Option B: With reference image
let imageInput = try VideoRestyleInput(
    data: .video(data: videoData),
    referenceImage: .image(data: refImageData)
)

let result = try await client.queue.submitAndPoll(
    model: .lucy_restyle_v2v,
    input: promptInput  // or imageInput
)
VideoRestyleInput parameters:
  • prompt (optional) - Text description of style (required if no referenceImage)
  • data (required) - Input video as FileInput
  • referenceImage (optional) - Reference image (required if no prompt)
  • seed (optional) - Random seed
  • resolution (optional) - Output resolution
  • enhancePrompt (optional) - Auto-enhance the prompt
You must provide either prompt or referenceImage, but not both. The SDK validates this at initialization.

Motion Video

Generate motion-controlled video from a still image and trajectory points using lucy_motion:
let trajectory = [
    try TrajectoryPoint(frame: 0, x: 0.5, y: 0.5),
    try TrajectoryPoint(frame: 30, x: 0.7, y: 0.3),
    try TrajectoryPoint(frame: 60, x: 0.5, y: 0.5),
]

let input = try MotionVideoInput(
    data: .image(data: imageData),  // Note: image, not video
    trajectory: trajectory
)

let result = try await client.queue.submitAndPoll(
    model: .lucy_motion,
    input: input
)
MotionVideoInput parameters:
  • data (required) - Input image as FileInput
  • trajectory (required) - Array of 2–1000 TrajectoryPoint values
  • seed (optional) - Random seed
  • resolution (optional) - Output resolution
TrajectoryPoint parameters:
  • frame (required) - Frame number (≥ 0)
  • x (required) - Normalized x coordinate (0.0–1.0)
  • y (required) - Normalized y coordinate (0.0–1.0)

Manual Polling

For custom polling logic, use submit(), status(), and result() separately:
import Foundation

// Submit job
let job = try await client.queue.submit(model: .lucy_2_v2v, input: input)
print("Job submitted: \(job.jobId)")

// Manual polling loop
while true {
    let status = try await client.queue.status(jobId: job.jobId)
    print("Status: \(status.status)")

    switch status.status {
    case .completed:
        let data = try await client.queue.result(jobId: job.jobId)
        try data.write(to: outputURL)
        print("Video saved!")
        return
    case .failed:
        print("Processing failed")
        return
    default:
        try await Task.sleep(for: .seconds(2))
    }
}

Error Handling

do {
    let result = try await client.queue.submitAndPoll(
        model: .lucy_2_v2v,
        input: input
    )
} catch let error as DecartError {
    switch error {
    case .invalidAPIKey:
        print("Invalid API key")
    case .invalidInput(let message):
        print("Invalid input: \(message)")
    case .queueError(let message):
        print("Queue error: \(message)")
    case .networkError(let underlying):
        print("Network error: \(underlying)")
    case .serverError(let message):
        print("Server error: \(message)")
    default:
        print("Error: \(error.localizedDescription)")
    }
}

Supported Models

All video models support queue processing:
ModelTypeDescription
lucy_2_v2vVideo-to-VideoVideo editing with prompt and optional reference image
lucy_restyle_v2vVideo-to-VideoVideo restyling with prompt or reference image
lucy_motionImage-to-VideoTrajectory-based motion control
ModelTypeDescription
lucy_pro_v2vVideo-to-VideoTransform video style

API Reference

client.queue.submit(model:input:)

Submit a job for processing. Parameters:
  • model: VideoModel - Video model
  • input - Typed input (VideoEditInput, VideoRestyleInput, VideoToVideoInput, or MotionVideoInput)
Returns: JobSubmitResponse
  • jobId: String - Unique job identifier
  • status: JobStatus - Initial status (.pending)

client.queue.status(jobId:)

Check the status of a job. Parameters:
  • jobId: String - The job identifier
Returns: JobStatusResponse
  • jobId: String - Job identifier
  • status: JobStatus - Current status

client.queue.result(jobId:)

Get the result of a completed job. Parameters:
  • jobId: String - The job identifier
Returns: Data - Video bytes

client.queue.submitAndPoll(model:input:onStatusChange:)

Submit a job and poll until completion. Parameters:
  • model: VideoModel - Video model
  • input - Typed input
  • onStatusChange: ((JobStatusResponse) -> Void)? - Optional status callback
Returns: QueueJobResult

Next Steps

Process API

Synchronous image editing

Realtime API

Transform video streams in realtime with WebRTC