Skip to main content
After submitting a job, you need to poll the queue to check when processing is complete. The SDK provides both automatic and manual polling methods.

Automatic Polling

The easiest way to handle polling is with submitAndPoll(), which submits the job and automatically polls until completion.

Method Signature

submitAndPoll: <T extends VideoModelDefinition>(
  options: QueueSubmitAndPollOptions<T>
) => Promise<QueueJobResult>

Parameters

All parameters from submit() plus:
options.onStatusChange
(job: JobStatusResponse) => void
Optional callback invoked when job status changes during polling.

Return Value

type QueueJobResult =
  | { status: "completed"; job_id: string; data: Blob }
  | { status: "failed"; job_id: string; error: string };

Basic Example

import { createDecartClient, models } from "@decart/sdk";
import * as fs from "fs/promises";

const client = createDecartClient({
  apiKey: process.env.DECART_API_KEY,
});

const result = await client.queue.submitAndPoll({
  model: models.video("lucy-pro-t2v"),
  prompt: "A beautiful sunset over the ocean",
  onStatusChange: (job) => {
    console.log(`Job ${job.job_id}: ${job.status}`);
  },
});

if (result.status === "completed") {
  // Save the video
  const arrayBuffer = await result.data.arrayBuffer();
  await fs.writeFile("output.mp4", Buffer.from(arrayBuffer));
  console.log("Video saved successfully!");
} else {
  // Handle failure
  console.error(`Job ${result.job_id} failed:`, result.error);
}

With Progress Tracking

Use the onStatusChange callback to track progress:
const result = await client.queue.submitAndPoll({
  model: models.video("lucy-pro-i2v"),
  prompt: "Camera pans across the landscape",
  data: "https://example.com/landscape.jpg",
  onStatusChange: (job) => {
    const timestamp = new Date().toISOString();
    console.log(`[${timestamp}] Job ${job.job_id} is ${job.status}`);
    
    // Update UI, show spinner, etc.
    if (job.status === "processing") {
      showSpinner("Processing video...");
    }
  },
});

if (result.status === "completed") {
  hideSpinner();
  displayVideo(result.data);
}

Cancellation

You can cancel polling using an AbortSignal:
const controller = new AbortController();

// Cancel after 5 minutes
setTimeout(() => controller.abort(), 5 * 60 * 1000);

try {
  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-pro-t2v"),
    prompt: "A stormy sea with lightning",
    signal: controller.signal,
  });
} catch (error) {
  if (error.message === "Polling aborted") {
    console.log("Polling was cancelled");
  }
}

Manual Polling

For more control over the polling process, you can manually submit and check status.

Method Signatures

// Check job status
status: (jobId: string) => Promise<JobStatusResponse>

// Retrieve completed job result
result: (jobId: string) => Promise<Blob>

Complete Manual Example

import { createDecartClient, models } from "@decart/sdk";

const client = createDecartClient({
  apiKey: process.env.DECART_API_KEY,
});

// Step 1: Submit the job
const job = await client.queue.submit({
  model: models.video("lucy-pro-t2v"),
  prompt: "A peaceful forest with sunlight filtering through trees",
});

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

// Step 2: Poll for completion
let status = job.status;
while (status === "pending" || status === "processing") {
  console.log(`Current status: ${status}`);
  
  // Wait before next poll (recommended: 1-2 seconds)
  await new Promise(resolve => setTimeout(resolve, 1500));
  
  // Check status
  const statusResponse = await client.queue.status(job.job_id);
  status = statusResponse.status;
}

// Step 3: Handle result
if (status === "completed") {
  const videoBlob = await client.queue.result(job.job_id);
  
  // Save or display the video
  const arrayBuffer = await videoBlob.arrayBuffer();
  await fs.writeFile("output.mp4", Buffer.from(arrayBuffer));
  console.log("Video generation complete!");
} else if (status === "failed") {
  console.error("Job failed");
}

Reusable Polling Function

Create a helper function for manual polling:
async function pollJob(client: DecartClient, jobId: string) {
  const POLL_INTERVAL = 1500; // 1.5 seconds
  
  while (true) {
    const status = await client.queue.status(jobId);
    
    if (status.status === "completed") {
      const blob = await client.queue.result(jobId);
      return { success: true, data: blob };
    }
    
    if (status.status === "failed") {
      return { success: false, error: "Job failed" };
    }
    
    // Still pending or processing
    await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL));
  }
}

// Usage
const job = await client.queue.submit({
  model: models.video("lucy-pro-t2v"),
  prompt: "A magical forest",
});

const result = await pollJob(client, job.job_id);
if (result.success) {
  console.log("Got video:", result.data);
}

Polling Best Practices

The SDK uses these default polling intervals:
  • Initial delay: 500ms before first status check
  • Poll interval: 1500ms (1.5 seconds) between checks
These values balance responsiveness with server load. Avoid polling more frequently than once per second.

Timeout Handling

The backend automatically fails jobs after 10 minutes. You don’t need to implement your own timeout, but you can use AbortSignal to cancel polling earlier if needed.
const controller = new AbortController();

// Set custom timeout (3 minutes)
const timeout = setTimeout(() => {
  controller.abort();
  console.log("Polling timeout - job took too long");
}, 3 * 60 * 1000);

try {
  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-pro-t2v"),
    prompt: "Epic cinematic scene",
    signal: controller.signal,
  });
  
  clearTimeout(timeout);
  
  if (result.status === "completed") {
    console.log("Success!");
  }
} catch (error) {
  clearTimeout(timeout);
  throw error;
}

Error Handling

try {
  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-pro-t2v"),
    prompt: "Beautiful landscape",
  });
  
  if (result.status === "completed") {
    // Success
    handleSuccess(result.data);
  } else {
    // Job failed on backend
    handleFailure(result.error);
  }
} catch (error) {
  // Network error, validation error, or aborted
  console.error("Polling error:", error.message);
}

Next Steps

Job Status

Learn about job status values and error handling

Submit Jobs

Review job submission for different model types

Build docs developers (and LLMs) love