Qwen Cloud offers two async processing systems. Choose based on what you're building:
| Task API | Batch API |
|---|
| Use case | Image generation, video generation, file transcription | High-volume text generation, embeddings |
| How it works | Submit one request → get a task ID → poll for result | Upload a JSONL file of requests → poll for completion → download results |
| Endpoint | dashscope-intl.aliyuncs.com/api/v1/tasks/ | dashscope-intl.aliyuncs.com/compatible-mode/v1/batches |
| Cost | Standard pricing | 50% discount |
| Completion time | Seconds to minutes | Up to 24h (configurable to 336h) |
| Result retention | 24 hours | 30 days |
| Max per request | 1 task (with optional multi-output like n=4) | 50,000 requests per file, 500 MB |
Task API
Image generation, video generation, and file transcription use the Task API: you submit a single request, receive a task ID, and poll for the result.
How it works
Every task follows the same two-step pattern:
- Create a task — Send a POST request and receive a
task_id
- Query the result — Poll
GET /api/v1/tasks/{task_id} until the task reaches a terminal state
POST (create) ──→ task_id
│
┌─────────────┘
▼
┌─────────┐ ┌─────────┐ ┌───────────┐
│ PENDING │───→│ RUNNING │───→│ SUCCEEDED │
└─────────┘ └─────────┘ └───────────┘
│ │
▼ ▼
┌──────────┐ ┌────────┐
│ CANCELED │ │ FAILED │
└──────────┘ └────────┘
Task states
| State | Meaning |
|---|
PENDING | Queued, waiting to start |
RUNNING | Actively processing |
SUCCEEDED | Completed successfully |
FAILED | Encountered an error |
CANCELED | Manually canceled (only from PENDING state) |
UNKNOWN | Task ID expired or cannot be queried |
Create a task
Some APIs (like image generation) support both synchronous and asynchronous modes. Add the X-DashScope-Async header to force async execution:
curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/image-generation/generation \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-DashScope-Async: enable" \
-d '{
"model": "wan2.6-t2i",
"input": {
"prompt": "A cat sitting on a windowsill at sunset"
}
}'
The response returns a task_id:
{
"request_id": "e5d5af82-9a08-xxx",
"output": {
"task_id": "86ecf553-d340-xxx",
"task_status": "PENDING"
}
}
Video generation APIs are always asynchronous — you do not need the X-DashScope-Async header for these.
Query the result
Poll the task endpoint with the returned task_id:
curl -X GET "https://dashscope-intl.aliyuncs.com/api/v1/tasks/86ecf553-d340-xxx" \
-H "Authorization: Bearer $DASHSCOPE_API_KEY"
import requests
import os
task_id = "86ecf553-d340-xxx"
url = f"https://dashscope-intl.aliyuncs.com/api/v1/tasks/{task_id}"
headers = {"Authorization": f"Bearer {os.getenv('DASHSCOPE_API_KEY')}"}
response = requests.get(url, headers=headers)
result = response.json()
print(result["output"]["task_status"])
A completed task returns the result in the output field:
{
"request_id": "e5d5af82-9a08-xxx",
"output": {
"task_id": "86ecf553-d340-xxx",
"task_status": "SUCCEEDED",
"submit_time": "2025-01-15 10:30:00.000",
"scheduled_time": "2025-01-15 10:30:01.000",
"end_time": "2025-01-15 10:30:12.000",
"results": [
{
"url": "https://dashscope-result-xxx.oss-xxx.aliyuncs.com/..."
}
],
"task_metrics": {
"TOTAL": 1,
"SUCCEEDED": 1,
"FAILED": 0
}
},
"usage": {
"image_count": 1
}
}
A failed task includes an error code and message:
{
"output": {
"task_id": "86ecf553-d340-xxx",
"task_status": "FAILED",
"code": "DataInspectionFailed",
"message": "Input or output data may contain inappropriate content."
}
}
Polling strategies
Naive fixed-interval polling wastes API calls and may hit rate limits. Use exponential backoff instead.
Start with a short interval and increase gradually. Different modalities have different typical completion times:
| Modality | Initial interval | Increase factor | Timeout |
|---|
| Image generation | 3 seconds | 1.5× | 2 minutes |
| Video generation | 15 seconds | 1.5× | 5 minutes |
| File transcription (ASR) | 5 seconds | 1.5× | Varies with audio length |
import time
import requests
import os
def poll_task(task_id, initial_interval=3, max_interval=15, timeout=120):
"""Poll a task with exponential backoff."""
url = f"https://dashscope-intl.aliyuncs.com/api/v1/tasks/{task_id}"
headers = {"Authorization": f"Bearer {os.getenv('DASHSCOPE_API_KEY')}"}
interval = initial_interval
elapsed = 0
while elapsed < timeout:
response = requests.get(url, headers=headers)
result = response.json()
status = result["output"]["task_status"]
if status == "SUCCEEDED":
return result
elif status == "FAILED":
raise Exception(
f"Task failed: {result['output'].get('code', 'Unknown')} - "
f"{result['output'].get('message', '')}"
)
time.sleep(interval)
elapsed += interval
interval = min(interval * 1.5, max_interval)
raise TimeoutError(f"Task {task_id} did not complete within {timeout}s")
# Image generation: poll every 3s, escalate to 15s, timeout at 2min
result = poll_task("86ecf553-d340-xxx", initial_interval=3, max_interval=15, timeout=120)
# Video generation: poll every 15s, escalate to 60s, timeout at 5min
result = poll_task("86ecf553-d340-xxx", initial_interval=15, max_interval=60, timeout=300)
async function pollTask(taskId, { initialInterval = 3000, maxInterval = 15000, timeout = 120000 } = {}) {
const url = `https://dashscope-intl.aliyuncs.com/api/v1/tasks/${taskId}`;
const headers = { Authorization: `Bearer ${process.env.DASHSCOPE_API_KEY}` };
let interval = initialInterval;
const deadline = Date.now() + timeout;
while (Date.now() < deadline) {
const res = await fetch(url, { headers });
const result = await res.json();
const { task_status, code, message } = result.output;
if (task_status === "SUCCEEDED") return result;
if (task_status === "FAILED") throw new Error(`Task failed: ${code} - ${message}`);
await new Promise(resolve => setTimeout(resolve, interval));
interval = Math.min(interval * 1.5, maxInterval);
}
throw new Error(`Task ${taskId} did not complete within ${timeout}ms`);
}
SDK-level abstraction
The DashScope Python SDK encapsulates the polling loop. Use call() for a synchronous experience, or async_call() + wait() for explicit control:
from dashscope import ImageSynthesis
# Option 1: Synchronous — SDK polls internally
result = ImageSynthesis.call(
model="wan2.6-t2i",
prompt="A cat sitting on a windowsill at sunset",
n=1
)
print(result.output.results[0].url)
# Option 2: Explicit async — you control when to wait
task = ImageSynthesis.async_call(
model="wan2.6-t2i",
prompt="A cat sitting on a windowsill at sunset",
n=1
)
# Do other work here...
result = ImageSynthesis.wait(task)
print(result.output.results[0].url)
The same pattern applies across modalities:
from dashscope import VideoSynthesis
task = VideoSynthesis.async_call(model="wan2.1-t2v-plus", prompt="...")
result = VideoSynthesis.wait(task)
Manage tasks at scale
List tasks
Query tasks by time range, status, or model:
curl -X GET "https://dashscope-intl.aliyuncs.com/api/v1/tasks/?start_time=20250115100000&end_time=20250115120000&status=FAILED&model_name=wan2.6-t2i&page_no=1&page_size=20" \
-H "Authorization: Bearer $DASHSCOPE_API_KEY"
Supported filters:
| Parameter | Description |
|---|
start_time | Start of time range, format: YYYYMMDDhhmmss |
end_time | End of time range, format: YYYYMMDDhhmmss |
status | Filter by task status (PENDING, RUNNING, SUCCEEDED, FAILED) |
model_name | Filter by model name |
page_no | Page number (starting from 1) |
page_size | Results per page |
The time range cannot exceed 24 hours. If both start_time and end_time are omitted, the API returns tasks from the last 24 hours.
Cancel a task
Cancel a task that is still in PENDING state:
curl -X POST "https://dashscope-intl.aliyuncs.com/api/v1/tasks/86ecf553-d340-xxx/cancel" \
-H "Authorization: Bearer $DASHSCOPE_API_KEY"
Only tasks in PENDING state can be canceled. Once a task moves to RUNNING, it will continue to completion.
Rate limits
Task management endpoints (query, list, cancel) share a rate limit of 20 QPS per account. If you manage many concurrent tasks, batch your status checks rather than polling each task individually at high frequency.
Task API best practices
Download results immediately — Task data and result URLs (images, videos) are retained for 24 hours only. After that, both the task metadata and generated files are automatically deleted. Always download and save results to persistent storage as soon as the task succeeds.
Handle multi-output tasks — When you request multiple outputs (such as n=4 images), the task is marked SUCCEEDED if at least one output is generated. Check the task_metrics field and iterate over the results array to handle partial success:
result = poll_task(task_id)
metrics = result["output"]["task_metrics"]
print(f"{metrics['SUCCEEDED']}/{metrics['TOTAL']} outputs generated")
for item in result["output"]["results"]:
if "url" in item:
download(item["url"])
else:
print(f"Failed: {item.get('message', 'Unknown error')}")
Avoid duplicate tasks — Each POST request creates a new task, even with identical parameters. If your application retries a failed submission, track task IDs to avoid duplicate work and unnecessary cost.
Batch API
The Batch API processes large volumes of text generation or embedding requests at 50% of the standard price. You upload a JSONL file of requests, wait for processing to complete, and download the results.
| Feature | Details |
|---|
| Supported models | Qwen text generation models, text embedding models |
| Input format | JSONL file, up to 50,000 requests / 500 MB |
| Completion window | 24 hours (configurable up to 336 hours) |
| Result retention | 30 days |
| Cancellation | Supported at any stage (in-progress requests finish first) |
The Batch API uses the OpenAI-compatible endpoint and SDK. For the complete guide with examples, input format, task states, and management operations, see Batch API.
Common errors
These errors apply to both the Task API and the Batch API:
| Error | Cause | Action |
|---|
DataInspectionFailed | Input or output blocked by content moderation | Modify the prompt and retry. See Safety |
Throttling.RateQuota | Rate limit exceeded | Reduce request frequency; increase polling interval |
| Task/batch stuck | Processing taking longer than expected | For tasks: continue polling until timeout. For batches: increase completion_window |
Next steps