> ## Documentation Index
> Fetch the complete documentation index at: https://docs.platform.decart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Queue API

> Asynchronous job-based video processing

The Queue API is the primary way to process videos with the JavaScript SDK. Submit jobs that are processed asynchronously in the background, then poll for status and retrieve results when complete.

<Note>
  All video processing (video editing, restyling, motion control) uses the Queue API. For image editing, use the [Process API](/sdks/javascript-process).
</Note>

## Overview

The Queue API 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:

```typescript theme={null}
const job = await client.queue.submit({
  model: models.video("lucy-2.1"),
  data: videoFile,
  prompt: "Transform into anime style",
});

console.log(`Job ID: ${job.job_id}`);
console.log(`Status: ${job.status}`); // "pending"
```

**Returns:**

* `job_id` - Unique identifier for the job
* `status` - Initial status (`"pending"`)

***

## Check Job Status

Poll the status of a submitted job:

```typescript theme={null}
const status = await client.queue.status(job.job_id);

console.log(`Status: ${status.status}`); // "pending", "processing", "completed", or "failed"
```

**Status Values:**

| Status       | Description                                        |
| ------------ | -------------------------------------------------- |
| `pending`    | Job is queued, waiting to be processed             |
| `processing` | Job is currently being processed                   |
| `completed`  | Job finished successfully                          |
| `failed`     | Job failed or timed out (timeout after 10 minutes) |

***

## Get Job Result

Retrieve the video once the job is completed:

```typescript theme={null}
import { writeFileSync } from "fs";

// First check status
const status = await client.queue.status(job.job_id);

if (status.status === "completed") {
  const result = await client.queue.result(job.job_id);

  if (result.status === "completed") {
    // result.data is a Blob
    const buffer = Buffer.from(await result.data.arrayBuffer());
    writeFileSync("output.mp4", buffer);
    console.log("Video saved!");
  } else {
    console.error(`Error: ${result.error}`);
  }
}
```

**Returns:**

* `status` - Either `"completed"` or `"failed"`
* `data` - Video Blob (when completed)
* `error` - Error message (when failed)

***

## Submit and Poll

The easiest way to use the Queue API - submit a job and automatically poll until completion:

```typescript theme={null}
import { writeFileSync } from "fs";

const result = await client.queue.submitAndPoll({
  model: models.video("lucy-2.1"),
  prompt: "A serene lake at sunset with mountains in the background",
  resolution: "720p",
  onStatusChange: (job) => {
    console.log(`Status: ${job.status}`);
  },
});

if (result.status === "completed") {
  const buffer = Buffer.from(await result.data.arrayBuffer());
  writeFileSync("output.mp4", buffer);
  console.log("Video saved!");
} else {
  console.error(`Generation failed: ${result.error}`);
}
```

**Parameters:**

* All standard model parameters (prompt, resolution, etc.)
* `onStatusChange` (optional) - Callback function called on each status change

***

## TypeScript Types

```typescript theme={null}
import type {
  JobStatus,
  JobSubmitResponse,
  JobStatusResponse,
  QueueJobResult,
} from "@decartai/sdk";

// Job status values
type JobStatus = "pending" | "processing" | "completed" | "failed";

// Submit response
interface JobSubmitResponse {
  job_id: string;
  status: JobStatus;
}

// Status response
interface JobStatusResponse {
  job_id: string;
  status: JobStatus;
}

// Result (discriminated union)
type QueueJobResult =
  | { status: "completed"; data: Blob }
  | { status: "failed"; error: string };
```

***

## Complete Example

### Node.js

```typescript theme={null}
import { createDecartClient, models } from "@decartai/sdk";
import { writeFileSync } from "fs";

const client = createDecartClient({ apiKey: "your-api-key" });

async function editVideo() {
  console.log("Submitting video editing job...");

  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-2.1"),
    data: videoFile,
    prompt: "Transform into anime style",
    onStatusChange: (job) => {
      console.log(`  Status: ${job.status}`);
    },
  });

  if (result.status === "completed") {
    const buffer = Buffer.from(await result.data.arrayBuffer());
    writeFileSync("cityscape.mp4", buffer);
    console.log("Video saved to cityscape.mp4");
  } else {
    console.error(`Editing failed: ${result.error}`);
  }
}

editVideo();
```

***

## Video Editing with Queue

Transform videos with style transfer:

```typescript theme={null}
import { readFileSync, writeFileSync } from "fs";

const videoBuffer = readFileSync("input-video.mp4");
const videoBlob = new Blob([videoBuffer], { type: "video/mp4" });

const result = await client.queue.submitAndPoll({
  model: models.video("lucy-2.1"),
  prompt: "Convert to anime style with vibrant colors",
  data: videoBlob,
  onStatusChange: (job) => {
    console.log(`Status: ${job.status}`);
  },
});

if (result.status === "completed") {
  const buffer = Buffer.from(await result.data.arrayBuffer());
  writeFileSync("styled-video.mp4", buffer);
}
```

***

## Cancellation with AbortSignal

Cancel queue operations using AbortController:

```typescript theme={null}
const controller = new AbortController();

// Start generation
const resultPromise = client.queue.submitAndPoll({
  model: models.video("lucy-2.1"),
  prompt: "A beautiful sunset",
  signal: controller.signal,
  onStatusChange: (job) => {
    console.log(`Status: ${job.status}`);
  },
});

// Cancel after 30 seconds (example)
setTimeout(() => {
  controller.abort();
  console.log("Cancellation requested");
}, 30000);

try {
  const result = await resultPromise;
  // Handle result...
} catch (error) {
  if (error.name === "AbortError") {
    console.log("Generation cancelled");
  }
}
```

***

## Manual Polling

For custom polling logic, you can manually poll for status:

```typescript theme={null}
import { writeFileSync } from "fs";

// Submit job
const job = await client.queue.submit({
  model: models.video("lucy-2.1"),
  prompt: "A serene lake at sunset",
});

console.log(`Job submitted: ${job.job_id}`);

// Manual polling loop
while (true) {
  const status = await client.queue.status(job.job_id);
  console.log(`Status: ${status.status}`);

  if (status.status === "completed") {
    const result = await client.queue.result(job.job_id);
    if (result.status === "completed") {
      const buffer = Buffer.from(await result.data.arrayBuffer());
      writeFileSync("output.mp4", buffer);
      console.log("Video saved!");
    }
    break;
  } else if (status.status === "failed") {
    console.error("Generation failed");
    break;
  }

  // Wait before next poll
  await new Promise((r) => setTimeout(r, 2000));
}
```

***

## Error Handling

```typescript theme={null}
import {
  createDecartClient,
  models,
  QueueSubmitError,
  QueueStatusError,
  QueueResultError,
  DecartSDKError,
} from "@decartai/sdk";

try {
  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-2.1"),
    prompt: "A beautiful sunset",
  });
} catch (error) {
  if (error instanceof QueueSubmitError) {
    console.error(`Failed to submit job: ${error.message}`);
  } else if (error instanceof QueueStatusError) {
    console.error(`Failed to check status: ${error.message}`);
  } else if (error instanceof QueueResultError) {
    console.error(`Failed to get result: ${error.message}`);
  } else if (error instanceof DecartSDKError) {
    console.error(`SDK error: ${error.message}`);
  }
}
```

***

## Supported Models

All non-realtime video models support queue processing:

| Model            | Type           | Description            |
| ---------------- | -------------- | ---------------------- |
| `lucy-2.1`       | Video-to-Video | Video editing (latest) |
| `lucy-2.1-vton`  | Video-to-Video | Virtual try-on         |
| `lucy-restyle-2` | Video-to-Video | Video restyling        |

<Accordion title="Latest aliases">
  | Alias                 | Description                            |
  | --------------------- | -------------------------------------- |
  | `lucy-latest`         | Always the latest editing model        |
  | `lucy-vton-latest`    | Always the latest virtual try-on model |
  | `lucy-restyle-latest` | Always the latest restyling model      |
  | `lucy-clip-latest`    | Always the latest legacy editing model |
</Accordion>

<Accordion title="Previous generation models">
  | Model       | Type           | Description           |
  | ----------- | -------------- | --------------------- |
  | `lucy-clip` | Video-to-Video | Transform video style |
</Accordion>

***

## API Reference

### `client.queue.submit(options)`

Submit a job for processing.

**Parameters:**

* `options: QueueSubmitOptions` - Model and input parameters
  * `model` - Model from `models.video()`
  * `signal?: AbortSignal` - Optional abort signal
  * Additional model-specific parameters

**Returns:** `Promise<JobSubmitResponse>`

* `job_id: 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:** `Promise<JobStatusResponse>`

* `job_id: 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:** `Promise<QueueJobResult>`

* When completed: `{ status: "completed", data: Blob }`
* When failed: `{ status: "failed", error: string }`

***

### `client.queue.submitAndPoll(options)`

Submit a job and poll until completion.

**Parameters:**

* `options: QueueSubmitAndPollOptions` - Model and input parameters
  * `onStatusChange?: (job: JobStatusResponse) => void` - Status change callback
  * `signal?: AbortSignal` - Optional abort signal
  * Additional model-specific parameters

**Returns:** `Promise<QueueJobResult>`

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Process API" icon="image" href="/sdks/javascript-process">
    Synchronous image editing
  </Card>

  <Card title="Realtime API" icon="bolt" href="/sdks/javascript-realtime">
    Transform video streams in realtime with WebRTC
  </Card>
</CardGroup>
